Skip to content

Commit

Permalink
e2etest: use helper methods in plaintext test
Browse files Browse the repository at this point in the history
  • Loading branch information
mariajdab authored and altergui committed Apr 17, 2023
1 parent bcbc355 commit c8cfb29
Showing 1 changed file with 33 additions and 177 deletions.
210 changes: 33 additions & 177 deletions cmd/end2endtest/plaintext.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"os"
"strings"
"sync"
Expand All @@ -15,9 +14,6 @@ import (
"go.vocdoni.io/dvote/apiclient"
"go.vocdoni.io/dvote/crypto/ethereum"
"go.vocdoni.io/dvote/log"
"go.vocdoni.io/dvote/types"
"go.vocdoni.io/dvote/util"
"go.vocdoni.io/proto/build/go/models"
)

func init() {
Expand All @@ -26,13 +22,17 @@ func init() {
description: "Publishes a census and a non-anonymous, non-secret election, emits N votes and verifies the results",
example: os.Args[0] + " --operation=plaintextelection --votes=1000",
}
ops["encryptedelection"] = operation{
test: &E2EEncryptedElection{},
description: "Publishes a census and a non-anonymous, secret-until-the-end election, emits N votes and verifies the results",
example: os.Args[0] + " --operation=encryptedelection --votes=1000",
}
}

var _ VochainTest = (*E2EPlaintextElection)(nil)

type E2EPlaintextElection struct {
api *apiclient.HTTPclient
config *config
electionBase
}

func (t *E2EPlaintextElection) Setup(api *apiclient.HTTPclient, config *config) error {
Expand Down Expand Up @@ -61,206 +61,62 @@ func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) {
// TODO: check if the account balance is low and use the faucet
acc, err := api.Account("")
if err != nil {
log.Infof("getting faucet package")
faucetPkg, err := getFaucetPackage(c, api.MyAddress().Hex())
if err != nil {
log.Fatal(err)
}

// Create the organization account and bootstraping with the faucet package
log.Infof("creating Vocdoni account %s", api.MyAddress().Hex())
log.Debugf("faucetPackage is %x", faucetPkg)
hash, err := api.AccountBootstrap(faucetPkg, &vapi.AccountMetadata{
Name: map[string]string{"default": "test account " + api.MyAddress().Hex()},
Description: map[string]string{"default": "test description"},
Version: "1.0",
})
acc, err = t.createAccount(api.MyAddress().Hex())
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*40)
defer cancel()
if _, err := api.WaitUntilTxIsMined(ctx, hash); err != nil {
log.Fatalf("gave up waiting for tx %x to be mined: %s", hash, err)
}

acc, err = api.Account("")
if err != nil {
log.Fatal(err)
}
if c.faucet != "" && acc.Balance == 0 {
log.Fatal("account balance is 0")
}
}

log.Infof("account %s balance is %d", api.MyAddress().Hex(), acc.Balance)

// Create a new census
censusID, err := api.NewCensus("weighted")
censusID, err := api.NewCensus(vapi.CensusTypeWeighted)
if err != nil {
log.Fatal(err)
}
log.Infof("new census created with id %s", censusID.String())

// Generate 10 participant accounts
voterAccounts := ethereum.NewSignKeysBatch(c.nvotes)
t.voterAccounts = ethereum.NewSignKeysBatch(c.nvotes)

// Add the accounts to the census by batches
participants := &vapi.CensusParticipants{}
for i, voterAccount := range voterAccounts {
participants.Participants = append(participants.Participants,
vapi.CensusParticipant{
Key: voterAccount.Address().Bytes(),
Weight: (*types.BigInt)(new(big.Int).SetUint64(10)),
})
if i == len(voterAccounts)-1 || ((i+1)%vapi.MaxCensusAddBatchSize == 0) {
if err := api.CensusAddParticipants(censusID, participants); err != nil {
log.Fatal(err)
}
log.Infof("added %d participants to census %s",
len(participants.Participants), censusID.String())
participants = &vapi.CensusParticipants{}
}
if err := t.addParticipantsCensus(vapi.CensusTypeWeighted, censusID); err != nil {
log.Fatal(err)
}

// Check census size
size, err := api.CensusSize(censusID)
if err != nil {
if !t.isCensusSizeValid(censusID) {
log.Fatal(err)
}
if size != uint64(c.nvotes) {
log.Fatalf("census size is %d, expected %d", size, c.nvotes)
}
log.Infof("census %s size is %d", censusID.String(), size)

// Publish the census
root, censusURI, err := api.CensusPublish(censusID)
root, censusURI, err := t.api.CensusPublish(censusID)
if err != nil {
log.Fatal(err)
}
log.Infof("census published with root %s", root.String())

// Check census size (of the published census)
size, err = api.CensusSize(root)
if err != nil {
if !t.isCensusSizeValid(root) {
log.Fatal(err)
}
if size != uint64(c.nvotes) {
log.Fatalf("published census size is %d, expected %d", size, c.nvotes)
}

// Generate the voting proofs (parallelized)
type voterProof struct {
proof *apiclient.CensusProof
address string
}
proofs := make(map[string]*apiclient.CensusProof, c.nvotes)
proofCh := make(chan *voterProof)
stopProofs := make(chan bool)
go func() {
for {
select {
case p := <-proofCh:
proofs[p.address] = p.proof
case <-stopProofs:
return
}
}
}()

addNaccounts := func(accounts []*ethereum.SignKeys, wg *sync.WaitGroup) {
defer wg.Done()
log.Infof("generating %d voting proofs", len(accounts))
for _, acc := range accounts {
pr, err := api.CensusGenProof(root, acc.Address().Bytes())
if err != nil {
log.Fatal(err)
}
pr.KeyType = models.ProofArbo_ADDRESS
proofCh <- &voterProof{
proof: pr,
address: acc.Address().Hex(),
}
}
}

pcount := c.nvotes / c.parallelCount
var wg sync.WaitGroup
for i := 0; i < len(voterAccounts); i += pcount {
end := i + pcount
if end > len(voterAccounts) {
end = len(voterAccounts)
}
wg.Add(1)
go addNaccounts(voterAccounts[i:end], &wg)
}

wg.Wait()
time.Sleep(time.Second) // wait a grace time for the last proof to be added
log.Debugf("%d/%d voting proofs generated successfully", len(proofs), len(voterAccounts))
stopProofs <- true
t.proofs = t.generateProofs(root)

// Create a new Election
electionID, err := api.NewElection(&vapi.ElectionDescription{
Title: map[string]string{"default": fmt.Sprintf("Test election %s", util.RandomHex(8))},
Description: map[string]string{"default": "Test election description"},
EndDate: time.Now().Add(time.Minute * 20),

VoteType: vapi.VoteType{
UniqueChoices: false,
MaxVoteOverwrites: 1,
},

ElectionType: vapi.ElectionType{
Autostart: true,
Interruptible: true,
Anonymous: false,
SecretUntilTheEnd: false,
DynamicCensus: false,
},

Census: vapi.CensusTypeDescription{
RootHash: root,
URL: censusURI,
Type: "weighted",
Size: uint64(len(voterAccounts)),
},

Questions: []vapi.Question{
{
Title: map[string]string{"default": "Test question 1"},
Description: map[string]string{"default": "Test question 1 description"},
Choices: []vapi.ChoiceMetadata{
{
Title: map[string]string{"default": "Yes"},
Value: 0,
},
{
Title: map[string]string{"default": "No"},
Value: 1,
},
},
},
},
})
description := newDefaultElectionDescription(root, censusURI, uint64(t.config.nvotes))
election, err := t.createElection(description)
if err != nil {
log.Fatal(err)
}
log.Infof("created new election with id %s - now wait until it starts", electionID.String())

// Wait for the election to start
ctx, cancel := context.WithTimeout(context.Background(), time.Second*40)
defer cancel()
election, err := api.WaitUntilElectionStarts(ctx, electionID)
if err != nil {
log.Fatal(err)
}
t.election = election

log.Debugf("election details: %+v", *election)

// Send the votes (parallelized)
startTime := time.Now()
wg = sync.WaitGroup{}
wg := sync.WaitGroup{}
voteAccounts := func(accounts []*ethereum.SignKeys, wg *sync.WaitGroup) {
defer wg.Done()
log.Infof("sending %d votes", len(accounts))
Expand All @@ -277,8 +133,8 @@ func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) {
for i, voterAccount := range accountsMap {
c := api.Clone(fmt.Sprintf("%x", voterAccount.PrivateKey()))
_, err := c.Vote(&apiclient.VoteData{
ElectionID: electionID,
ProofMkTree: proofs[voterAccount.Address().Hex()],
ElectionID: t.election.ElectionID,
ProofMkTree: t.proofs[voterAccount.Address().Hex()],
Choices: []int{i % 2},
})
// if the context deadline is reached, we don't need to print it (let's jus retry)
Expand All @@ -305,14 +161,14 @@ func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) {
time.Sleep(time.Second * 2)
}

pcount = c.nvotes / c.parallelCount
for i := 0; i < len(voterAccounts); i += pcount {
pcount := c.nvotes / c.parallelCount
for i := 0; i < len(t.voterAccounts); i += pcount {
end := i + pcount
if end > len(voterAccounts) {
end = len(voterAccounts)
if end > len(t.voterAccounts) {
end = len(t.voterAccounts)
}
wg.Add(1)
go voteAccounts(voterAccounts[i:end], &wg)
go voteAccounts(t.voterAccounts[i:end], &wg)
}

wg.Wait()
Expand All @@ -322,7 +178,7 @@ func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) {
// Wait for all the votes to be verified
log.Infof("waiting for all the votes to be registered...")
for {
count, err := api.ElectionVoteCount(electionID)
count, err := api.ElectionVoteCount(t.election.ElectionID)
if err != nil {
log.Warn(err)
}
Expand All @@ -346,35 +202,35 @@ func (t *E2EPlaintextElection) Run() (duration time.Duration, err error) {

// End the election by setting the status to ENDED
log.Infof("ending election...")
hash, err := api.SetElectionStatus(electionID, "ENDED")
hash, err := api.SetElectionStatus(t.election.ElectionID, "ENDED")
if err != nil {
log.Fatal(err)
}

// Check the election status is actually ENDED
ctx, cancel = context.WithTimeout(context.Background(), time.Second*40)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*40)
defer cancel()
if _, err := api.WaitUntilTxIsMined(ctx, hash); err != nil {
log.Fatalf("gave up waiting for tx %s to be mined: %s", hash, err)
}

election, err = api.Election(electionID)
election, err = api.Election(t.election.ElectionID)
if err != nil {
log.Fatal(err)
}
if election.Status != "ENDED" {
log.Fatal("election status is not ENDED")
}
log.Infof("election %s status is ENDED", electionID.String())
log.Infof("election %s status is ENDED", t.election.ElectionID.String())

// Wait for the election to be in RESULTS state
ctx, cancel = context.WithTimeout(context.Background(), time.Second*300)
defer cancel()
election, err = api.WaitUntilElectionStatus(ctx, electionID, "RESULTS")
election, err = api.WaitUntilElectionStatus(ctx, t.election.ElectionID, "RESULTS")
if err != nil {
log.Fatal(err)
}
log.Infof("election %s status is RESULTS", electionID.String())
log.Infof("election %s status is RESULTS", t.election.ElectionID.String())
log.Infof("election results: %v", election.Results)

return time.Since(start), nil
Expand Down

0 comments on commit c8cfb29

Please sign in to comment.