A very experimental PLC implementation which uses BFT consensus for decentralization
1package store_test
2
3import (
4 "crypto/rand"
5 "testing"
6 "time"
7
8 "github.com/gbl08ma/stacktrace"
9 "github.com/stretchr/testify/require"
10 "tangled.org/gbl08ma.com/didplcbft/store"
11 "tangled.org/gbl08ma.com/didplcbft/testutil"
12)
13
14func TestValidatorReputation(t *testing.T) {
15 txFactory, _, _ := testutil.NewTestTxFactory(t)
16
17 tx, err := txFactory.ReadWorking(time.Now()).Upgrade()
18 require.NoError(t, err)
19
20 err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) {
21 return 0, stacktrace.NewError("should not be called once")
22 })
23 require.NoError(t, err)
24
25 validators := make([][]byte, 10)
26 for i := range validators {
27 validators[i] = make([]byte, store.PublicKeyLength)
28 rand.Read(validators[i])
29 }
30
31 for range 3 {
32 for i := range validators {
33 err = store.Consensus.ChangeValidatorReputation(tx, validators[i], func(reputation uint64) (uint64, error) {
34 return reputation + uint64(i)*10, nil
35 })
36 require.NoError(t, err)
37 }
38 }
39
40 for i := range validators {
41 rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i])
42 require.NoError(t, err)
43 require.Equal(t, uint64(3*10*i), rep)
44 }
45
46 err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) {
47 require.Contains(t, validators, validatorAddress)
48 return reputation + 100, nil
49 })
50 require.NoError(t, err)
51
52 err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) {
53 return 0, stacktrace.NewError("should propagate error")
54 })
55 require.Error(t, err)
56
57 for i := range validators {
58 rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i])
59 require.NoError(t, err)
60 if i == 0 {
61 // validators[0] did not have a NonZero reputation, so we don't expect it to change
62 require.Zero(t, rep)
63 } else {
64 require.Equal(t, uint64(100+3*10*i), rep)
65 }
66 }
67
68 err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) {
69 require.Contains(t, validators, validatorAddress)
70 if reputation < 1000 {
71 return 0, nil
72 }
73 return reputation - 1000, nil
74 })
75 require.NoError(t, err)
76
77 for i := range validators {
78 rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i])
79 require.NoError(t, err)
80 require.Zero(t, rep)
81 }
82}
83
84func TestValidatorVotingActivity(t *testing.T) {
85 txFactory, _, _ := testutil.NewTestTxFactory(t)
86
87 tx, err := txFactory.ReadWorking(time.Now()).Upgrade()
88 require.NoError(t, err)
89
90 store.Consensus.ConfigureEpochSize(100)
91
92 validatorPubKey := make([]byte, store.PublicKeyLength)
93 rand.Read(validatorPubKey)
94
95 validatorAddress := make([]byte, store.AddressLength)
96 rand.Read(validatorAddress)
97
98 err = store.Consensus.InitializeValidatorVotingActivity(tx, validatorAddress, validatorPubKey, 100)
99 require.NoError(t, err)
100
101 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 100)
102 require.NoError(t, err)
103
104 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 101)
105 require.NoError(t, err)
106
107 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 123)
108 require.NoError(t, err)
109
110 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 199)
111 require.NoError(t, err)
112
113 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 321)
114 require.Error(t, err)
115
116 err = store.Consensus.InitializeValidatorVotingActivity(tx, validatorAddress, validatorPubKey, 300)
117 require.NoError(t, err)
118
119 err = store.Consensus.MarkValidatorVote(tx, validatorAddress, 321)
120 require.NoError(t, err)
121
122 for epoch := range []uint64{100, 200, 300} {
123 iterated := false
124 for v := range store.Consensus.ActiveValidatorsIterator(tx.Downgrade(), 100, &err) {
125 iterated = true
126 require.Equal(t, validatorAddress, v.Address)
127 require.Equal(t, validatorPubKey, v.PublicKey)
128 switch epoch {
129 case 100:
130 require.Equal(t, uint64(4), v.VoteCount)
131 case 200:
132 require.Zero(t, v.VoteCount)
133 case 300:
134 require.Equal(t, uint64(1), v.VoteCount)
135 }
136 }
137 require.True(t, iterated)
138 require.NoError(t, err)
139 }
140}