package store_test import ( "crypto/rand" "testing" "time" "github.com/gbl08ma/stacktrace" "github.com/stretchr/testify/require" "tangled.org/gbl08ma.com/didplcbft/store" "tangled.org/gbl08ma.com/didplcbft/testutil" ) func TestValidatorReputation(t *testing.T) { txFactory, _, _ := testutil.NewTestTxFactory(t) tx, err := txFactory.ReadWorking(time.Now()).Upgrade() require.NoError(t, err) err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { return 0, stacktrace.NewError("should not be called once") }) require.NoError(t, err) validators := make([][]byte, 10) for i := range validators { validators[i] = make([]byte, store.PublicKeyLength) rand.Read(validators[i]) } for range 3 { for i := range validators { err = store.Consensus.ChangeValidatorReputation(tx, validators[i], func(reputation uint64) (uint64, error) { return reputation + uint64(i)*10, nil }) require.NoError(t, err) } } for i := range validators { rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i]) require.NoError(t, err) require.Equal(t, uint64(3*10*i), rep) } err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { require.Contains(t, validators, validatorAddress) return reputation + 100, nil }) require.NoError(t, err) err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { return 0, stacktrace.NewError("should propagate error") }) require.Error(t, err) for i := range validators { rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i]) require.NoError(t, err) if i == 0 { // validators[0] did not have a NonZero reputation, so we don't expect it to change require.Zero(t, rep) } else { require.Equal(t, uint64(100+3*10*i), rep) } } err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { require.Contains(t, validators, validatorAddress) if reputation < 1000 { return 0, nil } return reputation - 1000, nil }) require.NoError(t, err) for i := range validators { rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i]) require.NoError(t, err) require.Zero(t, rep) } } func TestValidatorVotingActivity(t *testing.T) { txFactory, _, _ := testutil.NewTestTxFactory(t) tx, err := txFactory.ReadWorking(time.Now()).Upgrade() require.NoError(t, err) store.Consensus.ConfigureEpochSize(100) validatorPubKey := make([]byte, store.PublicKeyLength) rand.Read(validatorPubKey) validatorAddress := make([]byte, store.AddressLength) rand.Read(validatorAddress) err = store.Consensus.InitializeValidatorVotingActivity(tx, validatorAddress, validatorPubKey, 100) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 100) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 101) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 123) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 199) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 321) require.Error(t, err) err = store.Consensus.InitializeValidatorVotingActivity(tx, validatorAddress, validatorPubKey, 300) require.NoError(t, err) err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 321) require.NoError(t, err) for epoch := range []uint64{100, 200, 300} { iterated := false for v := range store.Consensus.ActiveValidatorsIterator(tx.Downgrade(), 100, &err) { iterated = true require.Equal(t, validatorAddress, v.Address) require.Equal(t, validatorPubKey, v.PublicKey) switch epoch { case 100: require.Equal(t, uint64(4), v.VoteCount) case 200: require.Zero(t, v.VoteCount) case 300: require.Equal(t, uint64(1), v.VoteCount) } } require.True(t, iterated) require.NoError(t, err) } }