summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Chan <ben.chan@algorand.com>2019-06-11 10:42:27 -0400
committerBenjamin Chan <ben.chan@algorand.com>2019-06-11 10:42:27 -0400
commit00cf3438c6ba56ebdcf2105354551152b0732bc5 (patch)
treeff84db82a6188e794f84498d98dd01df4f5e1e38
parenta9c28959fbd4e4bd3e2d8c4fa37152d01fdf4274 (diff)
make sortition deterministic in synchronous agreement testsorigin/ben/flakytest
-rw-r--r--agreement/service_test.go92
-rw-r--r--crypto/rand.go4
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 {