diff options
author | Benjamin Chan <ben.chan@algorand.com> | 2019-06-11 10:42:27 -0400 |
---|---|---|
committer | Benjamin Chan <ben.chan@algorand.com> | 2019-06-11 10:42:27 -0400 |
commit | 00cf3438c6ba56ebdcf2105354551152b0732bc5 (patch) | |
tree | ff84db82a6188e794f84498d98dd01df4f5e1e38 | |
parent | a9c28959fbd4e4bd3e2d8c4fa37152d01fdf4274 (diff) |
make sortition deterministic in synchronous agreement testsorigin/ben/flakytest
-rw-r--r-- | agreement/service_test.go | 92 | ||||
-rw-r--r-- | crypto/rand.go | 4 |
2 files changed, 62 insertions, 34 deletions
diff --git a/agreement/service_test.go b/agreement/service_test.go index dc5fbe3e8..0c759193d 100644 --- a/agreement/service_test.go +++ b/agreement/service_test.go @@ -583,6 +583,18 @@ func (l amCoserviceListener) dec(sum uint) { } } +// copied from fuzzer/ledger_test.go. We can merge once a refactor seems necessary. +func generatePseudoRandomVRF(keynum int) *crypto.VRFSecrets { + seed := [32]byte{} + seed[0] = byte(keynum % 255) + seed[1] = byte(keynum / 255) + pk, sk := crypto.VrfKeygenFromSeed(seed) + return &crypto.VRFSecrets{ + PK: pk, + SK: sk, + } +} + func createTestAccountsAndBalances(t *testing.T, numNodes int, rootSeed []byte) (accounts []account.Participation, balances map[basics.Address]basics.BalanceRecord) { off := int(rand.Uint32() >> 2) // prevent name collision from running tests more than once @@ -590,44 +602,63 @@ func createTestAccountsAndBalances(t *testing.T, numNodes int, rootSeed []byte) accounts = make([]account.Participation, numNodes) balances = make(map[basics.Address]basics.BalanceRecord, numNodes) var seed crypto.Seed - if len(rootSeed) < 32 { - crypto.RandBytes(seed[:]) - } else { - copy(seed[:], rootSeed) - } + copy(seed[:], rootSeed) for i := 0; i < numNodes; i++ { - stake := basics.MicroAlgos{Raw: 1000000} - firstValid := basics.Round(0) - lastValid := basics.Round(1000) - - rootAccess, err := db.MakeAccessor(t.Name()+"root"+strconv.Itoa(i+off), false, true) - - if err != nil { - panic(err) - } - - seed = sha256.Sum256(seed[:]) - root, err := account.ImportRoot(rootAccess, seed) - if err != nil { - panic(err) + var rootAddress basics.Address + // add new account rootAddress to db + { + rootAccess, err := db.MakeAccessor(t.Name()+"root"+strconv.Itoa(i+off), false, true) + if err != nil { + panic(err) + } + seed = sha256.Sum256(seed[:]) // rehash every node to get different root addresses + root, err := account.ImportRoot(rootAccess, seed) + if err != nil { + panic(err) + } + rootAddress = root.Address() } - rootAddress := root.Address() - - partAccess, err := db.MakeAccessor(t.Name()+"part"+strconv.Itoa(i+off), false, true) - if err != nil { - panic(err) + var v *crypto.OneTimeSignatureSecrets + firstValid := basics.Round(0) + lastValid := basics.Round(1000) + // generate new participation keys + { + // Compute how many distinct participation keys we should generate + keyDilution := config.Consensus[protocol.ConsensusCurrentVersion].DefaultKeyDilution + firstID := basics.OneTimeIDForRound(firstValid, keyDilution) + lastID := basics.OneTimeIDForRound(lastValid, keyDilution) + numBatches := lastID.Batch - firstID.Batch + 1 + + // Generate them + v = crypto.GenerateOneTimeSignatureSecrets(firstID.Batch, numBatches) } - accounts[i], err = account.FillDBWithParticipationKeys(partAccess, rootAddress, firstValid, lastValid, config.Consensus[protocol.ConsensusCurrentVersion].DefaultKeyDilution) - if err != nil { - panic(err) + // save partkeys to db + { + partAccess, err := db.MakeAccessor(t.Name()+"part"+strconv.Itoa(i+off), false, true) + if err != nil { + panic(err) + } + accounts[i] = account.Participation{ + Parent: rootAddress, + VRF: generatePseudoRandomVRF(i), + Voting: v, + FirstValid: firstValid, + LastValid: lastValid, + Store: partAccess, + } + err = accounts[i].Persist() + if err != nil { + panic(err) + } } + // expose balances for future ledger creation acctData := basics.AccountData{ Status: basics.Online, - MicroAlgos: stake, + MicroAlgos: basics.MicroAlgos{Raw: 1000000}, VoteID: accounts[i].VotingSecrets().OneTimeSignatureVerifier, SelectionID: accounts[i].VRFSecrets().PK, } @@ -657,8 +688,7 @@ func setupAgreement(t *testing.T, numNodes int, traceLevel traceLevel, ledgerFac bufCap := 1000 // max number of buffered messages // system state setup: keygen, stake initialization - accounts, balances := createTestAccountsAndBalances(t, numNodes, nil) - + accounts, balances := createTestAccountsAndBalances(t, numNodes, (&[32]byte{})[:]) baseLedger := makeTestLedger(balances) // logging @@ -669,7 +699,6 @@ func setupAgreement(t *testing.T, numNodes int, traceLevel traceLevel, ledgerFac log.SetLevel(logging.Debug) // node setup - clocks := make([]timers.Clock, numNodes) ledgers := make([]Ledger, numNodes) dbAccessors := make([]db.Accessor, numNodes) @@ -736,7 +765,6 @@ func setupAgreement(t *testing.T, numNodes int, traceLevel traceLevel, ledgerFac panic(r) } } - return baseNetwork, baseLedger, cleanupFn, services, clocks, ledgers, am } diff --git a/crypto/rand.go b/crypto/rand.go index 7bb61b7c9..6f7dca89a 100644 --- a/crypto/rand.go +++ b/crypto/rand.go @@ -69,14 +69,14 @@ func RandBytes(buf []byte) { // MakePRNG creates a new PRNG from an initial seed. The implementation is // based on HMAC_DRBG. All random bytes from the PRNG will be determined by -// the initial seed value. +// the initial seed value. Used by test code only. func MakePRNG(seed []byte) *PRNG { return &PRNG{ d: drbg.New(seed), } } -// RandBytes implements the RNG interface for the PRNG. +// RandBytes implements the RNG interface for the PRNG. Used by test code only. func (prng *PRNG) RandBytes(buf []byte) { n, err := prng.d.Read(buf) if err != nil { |