github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/v1/types_test.go (about) 1 package v1_test 2 3 import ( 4 "context" 5 "reflect" 6 "strconv" 7 "testing" 8 9 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 10 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 11 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 12 "github.com/prysmaticlabs/prysm/shared/bytesutil" 13 "github.com/prysmaticlabs/prysm/shared/interop" 14 "github.com/prysmaticlabs/prysm/shared/params" 15 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 16 "github.com/prysmaticlabs/prysm/shared/testutil/require" 17 log "github.com/sirupsen/logrus" 18 "google.golang.org/protobuf/proto" 19 ) 20 21 func TestBeaconState_ProtoBeaconStateCompatibility(t *testing.T) { 22 params.UseMinimalConfig() 23 ctx := context.Background() 24 genesis := setupGenesisState(t, 64) 25 customState, err := v1.InitializeFromProto(genesis) 26 require.NoError(t, err) 27 cloned, ok := proto.Clone(genesis).(*pb.BeaconState) 28 assert.Equal(t, true, ok, "Object is not of type *pb.BeaconState") 29 custom := customState.CloneInnerState() 30 assert.DeepSSZEqual(t, cloned, custom) 31 32 r1, err := customState.HashTreeRoot(ctx) 33 require.NoError(t, err) 34 beaconState, err := v1.InitializeFromProto(genesis) 35 require.NoError(t, err) 36 r2, err := beaconState.HashTreeRoot(context.Background()) 37 require.NoError(t, err) 38 assert.Equal(t, r1, r2, "Mismatched roots") 39 40 // We then write to the the state and compare hash tree roots again. 41 balances := genesis.Balances 42 balances[0] = 3823 43 require.NoError(t, customState.SetBalances(balances)) 44 r1, err = customState.HashTreeRoot(ctx) 45 require.NoError(t, err) 46 genesis.Balances = balances 47 beaconState, err = v1.InitializeFromProto(genesis) 48 require.NoError(t, err) 49 r2, err = beaconState.HashTreeRoot(context.Background()) 50 require.NoError(t, err) 51 assert.Equal(t, r1, r2, "Mismatched roots") 52 } 53 54 func setupGenesisState(tb testing.TB, count uint64) *pb.BeaconState { 55 genesisState, _, err := interop.GenerateGenesisState(context.Background(), 0, count) 56 require.NoError(tb, err, "Could not generate genesis beacon state") 57 for i := uint64(1); i < count; i++ { 58 someRoot := [32]byte{} 59 someKey := [48]byte{} 60 copy(someRoot[:], strconv.Itoa(int(i))) 61 copy(someKey[:], strconv.Itoa(int(i))) 62 genesisState.Validators = append(genesisState.Validators, ðpb.Validator{ 63 PublicKey: someKey[:], 64 WithdrawalCredentials: someRoot[:], 65 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 66 Slashed: false, 67 ActivationEligibilityEpoch: 1, 68 ActivationEpoch: 1, 69 ExitEpoch: 1, 70 WithdrawableEpoch: 1, 71 }) 72 genesisState.Balances = append(genesisState.Balances, params.BeaconConfig().MaxEffectiveBalance) 73 } 74 return genesisState 75 } 76 77 func BenchmarkCloneValidators_Proto(b *testing.B) { 78 b.StopTimer() 79 validators := make([]*ethpb.Validator, 16384) 80 somePubKey := [48]byte{1, 2, 3} 81 someRoot := [32]byte{3, 4, 5} 82 for i := 0; i < len(validators); i++ { 83 validators[i] = ðpb.Validator{ 84 PublicKey: somePubKey[:], 85 WithdrawalCredentials: someRoot[:], 86 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 87 Slashed: false, 88 ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch, 89 ActivationEpoch: 3, 90 ExitEpoch: 4, 91 WithdrawableEpoch: 5, 92 } 93 } 94 b.StartTimer() 95 for i := 0; i < b.N; i++ { 96 cloneValidatorsWithProto(validators) 97 } 98 } 99 100 func BenchmarkCloneValidators_Manual(b *testing.B) { 101 b.StopTimer() 102 validators := make([]*ethpb.Validator, 16384) 103 somePubKey := [48]byte{1, 2, 3} 104 someRoot := [32]byte{3, 4, 5} 105 for i := 0; i < len(validators); i++ { 106 validators[i] = ðpb.Validator{ 107 PublicKey: somePubKey[:], 108 WithdrawalCredentials: someRoot[:], 109 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 110 Slashed: false, 111 ActivationEligibilityEpoch: params.BeaconConfig().FarFutureEpoch, 112 ActivationEpoch: 3, 113 ExitEpoch: 4, 114 WithdrawableEpoch: 5, 115 } 116 } 117 b.StartTimer() 118 for i := 0; i < b.N; i++ { 119 cloneValidatorsManually(validators) 120 } 121 } 122 123 func BenchmarkStateClone_Proto(b *testing.B) { 124 b.StopTimer() 125 params.UseMinimalConfig() 126 genesis := setupGenesisState(b, 64) 127 b.StartTimer() 128 for i := 0; i < b.N; i++ { 129 _, ok := proto.Clone(genesis).(*pb.BeaconState) 130 assert.Equal(b, true, ok, "Entity is not of type *pb.BeaconState") 131 } 132 } 133 134 func BenchmarkStateClone_Manual(b *testing.B) { 135 b.StopTimer() 136 params.UseMinimalConfig() 137 genesis := setupGenesisState(b, 64) 138 st, err := v1.InitializeFromProto(genesis) 139 require.NoError(b, err) 140 b.StartTimer() 141 for i := 0; i < b.N; i++ { 142 _ = st.CloneInnerState() 143 } 144 } 145 146 func cloneValidatorsWithProto(vals []*ethpb.Validator) []*ethpb.Validator { 147 var ok bool 148 res := make([]*ethpb.Validator, len(vals)) 149 for i := 0; i < len(res); i++ { 150 res[i], ok = proto.Clone(vals[i]).(*ethpb.Validator) 151 if !ok { 152 log.Debug("Entity is not of type *ethpb.Validator") 153 } 154 } 155 return res 156 } 157 158 func cloneValidatorsManually(vals []*ethpb.Validator) []*ethpb.Validator { 159 res := make([]*ethpb.Validator, len(vals)) 160 for i := 0; i < len(res); i++ { 161 val := vals[i] 162 res[i] = ðpb.Validator{ 163 PublicKey: val.PublicKey, 164 WithdrawalCredentials: val.WithdrawalCredentials, 165 EffectiveBalance: val.EffectiveBalance, 166 Slashed: val.Slashed, 167 ActivationEligibilityEpoch: val.ActivationEligibilityEpoch, 168 ActivationEpoch: val.ActivationEpoch, 169 ExitEpoch: val.ExitEpoch, 170 WithdrawableEpoch: val.WithdrawableEpoch, 171 } 172 } 173 return res 174 } 175 176 func TestBeaconState_ImmutabilityWithSharedResources(t *testing.T) { 177 params.UseMinimalConfig() 178 genesis := setupGenesisState(t, 64) 179 a, err := v1.InitializeFromProto(genesis) 180 require.NoError(t, err) 181 b := a.Copy() 182 183 // Randao mixes 184 require.DeepEqual(t, a.RandaoMixes(), b.RandaoMixes(), "Test precondition failed, fields are not equal") 185 require.NoError(t, a.UpdateRandaoMixesAtIndex(1, []byte("foo"))) 186 if reflect.DeepEqual(a.RandaoMixes(), b.RandaoMixes()) { 187 t.Error("Expect a.RandaoMixes() to be different from b.RandaoMixes()") 188 } 189 190 // Validators 191 require.DeepEqual(t, a.Validators(), b.Validators(), "Test precondition failed, fields are not equal") 192 require.NoError(t, a.UpdateValidatorAtIndex(1, ðpb.Validator{Slashed: true})) 193 if reflect.DeepEqual(a.Validators(), b.Validators()) { 194 t.Error("Expect a.Validators() to be different from b.Validators()") 195 } 196 197 // State Roots 198 require.DeepEqual(t, a.StateRoots(), b.StateRoots(), "Test precondition failed, fields are not equal") 199 require.NoError(t, a.UpdateStateRootAtIndex(1, bytesutil.ToBytes32([]byte("foo")))) 200 if reflect.DeepEqual(a.StateRoots(), b.StateRoots()) { 201 t.Fatal("Expected a.StateRoots() to be different from b.StateRoots()") 202 } 203 204 // Block Roots 205 require.DeepEqual(t, a.BlockRoots(), b.BlockRoots(), "Test precondition failed, fields are not equal") 206 require.NoError(t, a.UpdateBlockRootAtIndex(1, bytesutil.ToBytes32([]byte("foo")))) 207 if reflect.DeepEqual(a.BlockRoots(), b.BlockRoots()) { 208 t.Fatal("Expected a.BlockRoots() to be different from b.BlockRoots()") 209 } 210 } 211 212 func TestForkManualCopy_OK(t *testing.T) { 213 params.UseMinimalConfig() 214 genesis := setupGenesisState(t, 64) 215 a, err := v1.InitializeFromProto(genesis) 216 require.NoError(t, err) 217 wantedFork := &pb.Fork{ 218 PreviousVersion: []byte{'a', 'b', 'c'}, 219 CurrentVersion: []byte{'d', 'e', 'f'}, 220 Epoch: 0, 221 } 222 require.NoError(t, a.SetFork(wantedFork)) 223 224 pbState, err := v1.ProtobufBeaconState(a.InnerStateUnsafe()) 225 require.NoError(t, err) 226 require.DeepEqual(t, pbState.Fork, wantedFork) 227 }