A very experimental PLC implementation which uses BFT consensus for decentralization
19
fork

Configure Feed

Select the types of activity you want to include in your feed.

Allow passing callback for arbitrary changes in ChangeAllNonZeroValidatorReputations

gbl08ma d5732b12 ca2f1ec2

+35 -10
+15 -7
store/consensus.go
··· 83 83 84 84 ValidatorReputation(tx transaction.Read, validatorAddress []byte) (uint64, error) 85 85 ChangeValidatorReputation(tx transaction.Write, validatorAddress []byte, change int64) error 86 - ChangeAllNonZeroValidatorReputations(tx transaction.Write, change int64) error 86 + ChangeAllNonZeroValidatorReputations(tx transaction.Write, changer func(validatorAddress []byte, reputation uint64) (uint64, error)) error 87 87 } 88 88 89 89 var _ ConsensusStore = (*consensusStore)(nil) ··· 877 877 var maxReputationKey = marshalValidatorReputationKey(slices.Repeat([]byte{0xff}, 20)) 878 878 879 879 // ChangeAllNonZeroValidatorReputations implements [ConsensusStore]. 880 - func (t *consensusStore) ChangeAllNonZeroValidatorReputations(tx transaction.Write, change int64) error { 880 + func (t *consensusStore) ChangeAllNonZeroValidatorReputations(tx transaction.Write, changer func(validatorAddress []byte, reputation uint64) (uint64, error)) error { 881 881 // we are not allowed to make updates to the tree while an iterator is active 882 882 // process validators in batches of 100 to avoid loading too many key-value pairs into memory 883 883 const batchSize = 100 ··· 890 890 value []byte 891 891 } 892 892 893 - changeInt := big.NewInt(change) 894 - 895 893 batch := func() ([]kv, bool, error) { 896 894 toSet := make([]kv, 0, batchSize) 897 895 itr, err := tx.Tree().Iterator(startingKey, maxReputationKey, true) ··· 904 902 itr.Next() 905 903 } 906 904 905 + validatorAddrTmp := make([]byte, 20) 906 + 907 907 for i := 0; itr.Valid() && i < batchSize; i++ { 908 908 reputation := new(big.Int).SetBytes(itr.Value()) 909 - reputation.Add(reputation, changeInt) 909 + 910 + keyCopy := slices.Clone(itr.Key()) 911 + copy(validatorAddrTmp, keyCopy[1:21]) 912 + 913 + newValue, err := changer(validatorAddrTmp, reputation.Uint64()) 914 + if err != nil { 915 + return nil, false, stacktrace.Propagate(err) 916 + } 917 + reputation.SetUint64(newValue) 910 918 911 919 if reputation.Sign() <= 0 { 912 920 toSet = append(toSet, kv{ 913 - key: slices.Clone(itr.Key()), 921 + key: keyCopy, 914 922 value: nil, 915 923 }) 916 924 } else { 917 925 toSet = append(toSet, kv{ 918 - key: slices.Clone(itr.Key()), 926 + key: keyCopy, 919 927 value: reputation.Bytes(), 920 928 }) 921 929 }
+20 -3
store/store_test.go
··· 5 5 "testing" 6 6 "time" 7 7 8 + "github.com/gbl08ma/stacktrace" 8 9 "github.com/stretchr/testify/require" 9 10 "tangled.org/gbl08ma.com/didplcbft/store" 10 11 "tangled.org/gbl08ma.com/didplcbft/testutil" ··· 16 17 tx, err := txFactory.ReadWorking(time.Now()).Upgrade() 17 18 require.NoError(t, err) 18 19 19 - err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, 100) 20 + err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { 21 + return 0, stacktrace.NewError("should not be called once") 22 + }) 20 23 require.NoError(t, err) 21 24 22 25 validators := make([][]byte, 10) ··· 38 41 require.Equal(t, uint64(3*10*i), rep) 39 42 } 40 43 41 - err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, 100) 44 + err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { 45 + require.Contains(t, validators, validatorAddress) 46 + return reputation + 100, nil 47 + }) 42 48 require.NoError(t, err) 43 49 50 + err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { 51 + return 0, stacktrace.NewError("should propagate error") 52 + }) 53 + require.Error(t, err) 54 + 44 55 for i := range validators { 45 56 rep, err := store.Consensus.ValidatorReputation(tx.Downgrade(), validators[i]) 46 57 require.NoError(t, err) ··· 52 63 } 53 64 } 54 65 55 - err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, -1000) 66 + err = store.Consensus.ChangeAllNonZeroValidatorReputations(tx, func(validatorAddress []byte, reputation uint64) (uint64, error) { 67 + require.Contains(t, validators, validatorAddress) 68 + if reputation < 1000 { 69 + return 0, nil 70 + } 71 + return reputation - 1000, nil 72 + }) 56 73 require.NoError(t, err) 57 74 58 75 for i := range validators {