github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/state/v1/state_trie_test.go (about)

     1  package v1_test
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"testing"
     7  
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/go-bitfield"
    10  	iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
    11  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    12  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    13  	eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    14  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    15  	"github.com/prysmaticlabs/prysm/shared/params"
    16  	"github.com/prysmaticlabs/prysm/shared/testutil"
    17  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    18  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    19  )
    20  
    21  func TestInitializeFromProto(t *testing.T) {
    22  	testState, _ := testutil.DeterministicGenesisState(t, 64)
    23  	pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
    24  	require.NoError(t, err)
    25  	type test struct {
    26  		name  string
    27  		state *pbp2p.BeaconState
    28  		error string
    29  	}
    30  	initTests := []test{
    31  		{
    32  			name:  "nil state",
    33  			state: nil,
    34  			error: "received nil state",
    35  		},
    36  		{
    37  			name: "nil validators",
    38  			state: &pbp2p.BeaconState{
    39  				Slot:       4,
    40  				Validators: nil,
    41  			},
    42  		},
    43  		{
    44  			name:  "empty state",
    45  			state: &pbp2p.BeaconState{},
    46  		},
    47  		{
    48  			name:  "full state",
    49  			state: pbState,
    50  		},
    51  	}
    52  	for _, tt := range initTests {
    53  		t.Run(tt.name, func(t *testing.T) {
    54  			_, err := v1.InitializeFromProto(tt.state)
    55  			if tt.error != "" {
    56  				assert.ErrorContains(t, tt.error, err)
    57  			} else {
    58  				assert.NoError(t, err)
    59  			}
    60  		})
    61  	}
    62  }
    63  
    64  func TestInitializeFromProtoUnsafe(t *testing.T) {
    65  	testState, _ := testutil.DeterministicGenesisState(t, 64)
    66  	pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
    67  	require.NoError(t, err)
    68  	type test struct {
    69  		name  string
    70  		state *pbp2p.BeaconState
    71  		error string
    72  	}
    73  	initTests := []test{
    74  		{
    75  			name:  "nil state",
    76  			state: nil,
    77  			error: "received nil state",
    78  		},
    79  		{
    80  			name: "nil validators",
    81  			state: &pbp2p.BeaconState{
    82  				Slot:       4,
    83  				Validators: nil,
    84  			},
    85  		},
    86  		{
    87  			name:  "empty state",
    88  			state: &pbp2p.BeaconState{},
    89  		},
    90  		{
    91  			name:  "full state",
    92  			state: pbState,
    93  		},
    94  	}
    95  	for _, tt := range initTests {
    96  		t.Run(tt.name, func(t *testing.T) {
    97  			_, err := v1.InitializeFromProtoUnsafe(tt.state)
    98  			if tt.error != "" {
    99  				assert.ErrorContains(t, tt.error, err)
   100  			} else {
   101  				assert.NoError(t, err)
   102  			}
   103  		})
   104  	}
   105  }
   106  
   107  func TestBeaconState_HashTreeRoot(t *testing.T) {
   108  	testState, _ := testutil.DeterministicGenesisState(t, 64)
   109  
   110  	type test struct {
   111  		name        string
   112  		stateModify func(beaconState iface.BeaconState) (iface.BeaconState, error)
   113  		error       string
   114  	}
   115  	initTests := []test{
   116  		{
   117  			name: "unchanged state",
   118  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   119  				return beaconState, nil
   120  			},
   121  			error: "",
   122  		},
   123  		{
   124  			name: "different slot",
   125  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   126  				if err := beaconState.SetSlot(5); err != nil {
   127  					return nil, err
   128  				}
   129  				return beaconState, nil
   130  			},
   131  			error: "",
   132  		},
   133  		{
   134  			name: "different validator balance",
   135  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   136  				val, err := beaconState.ValidatorAtIndex(5)
   137  				if err != nil {
   138  					return nil, err
   139  				}
   140  				val.EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement
   141  				if err := beaconState.UpdateValidatorAtIndex(5, val); err != nil {
   142  					return nil, err
   143  				}
   144  				return beaconState, nil
   145  			},
   146  			error: "",
   147  		},
   148  	}
   149  
   150  	var err error
   151  	var oldHTR []byte
   152  	for _, tt := range initTests {
   153  		t.Run(tt.name, func(t *testing.T) {
   154  			testState, err = tt.stateModify(testState)
   155  			assert.NoError(t, err)
   156  			root, err := testState.HashTreeRoot(context.Background())
   157  			if err == nil && tt.error != "" {
   158  				t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
   159  			}
   160  			pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
   161  			require.NoError(t, err)
   162  			genericHTR, err := pbState.HashTreeRoot()
   163  			if err == nil && tt.error != "" {
   164  				t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
   165  			}
   166  			assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
   167  			assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")
   168  			if len(oldHTR) != 0 && bytes.Equal(root[:], oldHTR) {
   169  				t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR)
   170  			}
   171  			oldHTR = root[:]
   172  		})
   173  	}
   174  }
   175  
   176  func TestBeaconState_HashTreeRoot_FieldTrie(t *testing.T) {
   177  	testState, _ := testutil.DeterministicGenesisState(t, 64)
   178  
   179  	type test struct {
   180  		name        string
   181  		stateModify func(iface.BeaconState) (iface.BeaconState, error)
   182  		error       string
   183  	}
   184  	initTests := []test{
   185  		{
   186  			name: "unchanged state",
   187  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   188  				return beaconState, nil
   189  			},
   190  			error: "",
   191  		},
   192  		{
   193  			name: "different slot",
   194  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   195  				if err := beaconState.SetSlot(5); err != nil {
   196  					return nil, err
   197  				}
   198  				return beaconState, nil
   199  			},
   200  			error: "",
   201  		},
   202  		{
   203  			name: "different validator balance",
   204  			stateModify: func(beaconState iface.BeaconState) (iface.BeaconState, error) {
   205  				val, err := beaconState.ValidatorAtIndex(5)
   206  				if err != nil {
   207  					return nil, err
   208  				}
   209  				val.EffectiveBalance = params.BeaconConfig().MaxEffectiveBalance - params.BeaconConfig().EffectiveBalanceIncrement
   210  				if err := beaconState.UpdateValidatorAtIndex(5, val); err != nil {
   211  					return nil, err
   212  				}
   213  				return beaconState, nil
   214  			},
   215  			error: "",
   216  		},
   217  	}
   218  
   219  	var err error
   220  	var oldHTR []byte
   221  	for _, tt := range initTests {
   222  		t.Run(tt.name, func(t *testing.T) {
   223  			testState, err = tt.stateModify(testState)
   224  			assert.NoError(t, err)
   225  			root, err := testState.HashTreeRoot(context.Background())
   226  			if err == nil && tt.error != "" {
   227  				t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
   228  			}
   229  			pbState, err := v1.ProtobufBeaconState(testState.InnerStateUnsafe())
   230  			require.NoError(t, err)
   231  			genericHTR, err := pbState.HashTreeRoot()
   232  			if err == nil && tt.error != "" {
   233  				t.Errorf("Expected error, expected %v, recevied %v", tt.error, err)
   234  			}
   235  			assert.DeepNotEqual(t, []byte{}, root[:], "Received empty hash tree root")
   236  			assert.DeepEqual(t, genericHTR[:], root[:], "Expected hash tree root to match generic")
   237  			if len(oldHTR) != 0 && bytes.Equal(root[:], oldHTR) {
   238  				t.Errorf("Expected HTR to change, received %#x == old %#x", root, oldHTR)
   239  			}
   240  			oldHTR = root[:]
   241  		})
   242  	}
   243  }
   244  
   245  func TestBeaconState_AppendValidator_DoesntMutateCopy(t *testing.T) {
   246  	st0, err := testutil.NewBeaconState()
   247  	require.NoError(t, err)
   248  	st1 := st0.Copy()
   249  	originalCount := st1.NumValidators()
   250  
   251  	val := &eth.Validator{Slashed: true}
   252  	assert.NoError(t, st0.AppendValidator(val))
   253  	assert.Equal(t, originalCount, st1.NumValidators(), "st1 NumValidators mutated")
   254  	_, ok := st1.ValidatorIndexByPubkey(bytesutil.ToBytes48(val.PublicKey))
   255  	assert.Equal(t, false, ok, "Expected no validator index to be present in st1 for the newly inserted pubkey")
   256  }
   257  
   258  func TestBeaconState_ToProto(t *testing.T) {
   259  	source, err := testutil.NewBeaconState(testutil.FillRootsNaturalOpt, func(state *pbp2p.BeaconState) error {
   260  		state.GenesisTime = 1
   261  		state.GenesisValidatorsRoot = bytesutil.PadTo([]byte("genesisvalidatorroot"), 32)
   262  		state.Slot = 2
   263  		state.Fork = &pbp2p.Fork{
   264  			PreviousVersion: bytesutil.PadTo([]byte("123"), 4),
   265  			CurrentVersion:  bytesutil.PadTo([]byte("456"), 4),
   266  			Epoch:           3,
   267  		}
   268  		state.LatestBlockHeader = &eth.BeaconBlockHeader{
   269  			Slot:          4,
   270  			ProposerIndex: 5,
   271  			ParentRoot:    bytesutil.PadTo([]byte("lbhparentroot"), 32),
   272  			StateRoot:     bytesutil.PadTo([]byte("lbhstateroot"), 32),
   273  			BodyRoot:      bytesutil.PadTo([]byte("lbhbodyroot"), 32),
   274  		}
   275  		state.BlockRoots = [][]byte{bytesutil.PadTo([]byte("blockroots"), 32)}
   276  		state.StateRoots = [][]byte{bytesutil.PadTo([]byte("stateroots"), 32)}
   277  		state.HistoricalRoots = [][]byte{bytesutil.PadTo([]byte("historicalroots"), 32)}
   278  		state.Eth1Data = &eth.Eth1Data{
   279  			DepositRoot:  bytesutil.PadTo([]byte("e1ddepositroot"), 32),
   280  			DepositCount: 6,
   281  			BlockHash:    bytesutil.PadTo([]byte("e1dblockhash"), 32),
   282  		}
   283  		state.Eth1DataVotes = []*eth.Eth1Data{{
   284  			DepositRoot:  bytesutil.PadTo([]byte("e1dvdepositroot"), 32),
   285  			DepositCount: 7,
   286  			BlockHash:    bytesutil.PadTo([]byte("e1dvblockhash"), 32),
   287  		}}
   288  		state.Eth1DepositIndex = 8
   289  		state.Validators = []*eth.Validator{{
   290  			PublicKey:                  bytesutil.PadTo([]byte("publickey"), 48),
   291  			WithdrawalCredentials:      bytesutil.PadTo([]byte("withdrawalcredentials"), 32),
   292  			EffectiveBalance:           9,
   293  			Slashed:                    true,
   294  			ActivationEligibilityEpoch: 10,
   295  			ActivationEpoch:            11,
   296  			ExitEpoch:                  12,
   297  			WithdrawableEpoch:          13,
   298  		}}
   299  		state.Balances = []uint64{14}
   300  		state.RandaoMixes = [][]byte{bytesutil.PadTo([]byte("randaomixes"), 32)}
   301  		state.Slashings = []uint64{15}
   302  		state.PreviousEpochAttestations = []*pbp2p.PendingAttestation{{
   303  			AggregationBits: bitfield.Bitlist{16},
   304  			Data: &eth.AttestationData{
   305  				Slot:            17,
   306  				CommitteeIndex:  18,
   307  				BeaconBlockRoot: bytesutil.PadTo([]byte("peabeaconblockroot"), 32),
   308  				Source: &eth.Checkpoint{
   309  					Epoch: 19,
   310  					Root:  bytesutil.PadTo([]byte("peasroot"), 32),
   311  				},
   312  				Target: &eth.Checkpoint{
   313  					Epoch: 20,
   314  					Root:  bytesutil.PadTo([]byte("peatroot"), 32),
   315  				},
   316  			},
   317  			InclusionDelay: 21,
   318  			ProposerIndex:  22,
   319  		}}
   320  		state.CurrentEpochAttestations = []*pbp2p.PendingAttestation{{
   321  			AggregationBits: bitfield.Bitlist{23},
   322  			Data: &eth.AttestationData{
   323  				Slot:            24,
   324  				CommitteeIndex:  25,
   325  				BeaconBlockRoot: bytesutil.PadTo([]byte("ceabeaconblockroot"), 32),
   326  				Source: &eth.Checkpoint{
   327  					Epoch: 26,
   328  					Root:  bytesutil.PadTo([]byte("ceasroot"), 32),
   329  				},
   330  				Target: &eth.Checkpoint{
   331  					Epoch: 27,
   332  					Root:  bytesutil.PadTo([]byte("ceatroot"), 32),
   333  				},
   334  			},
   335  			InclusionDelay: 28,
   336  			ProposerIndex:  29,
   337  		}}
   338  		state.JustificationBits = bitfield.Bitvector4{1}
   339  		state.PreviousJustifiedCheckpoint = &eth.Checkpoint{
   340  			Epoch: 30,
   341  			Root:  bytesutil.PadTo([]byte("pjcroot"), 32),
   342  		}
   343  		state.CurrentJustifiedCheckpoint = &eth.Checkpoint{
   344  			Epoch: 31,
   345  			Root:  bytesutil.PadTo([]byte("cjcroot"), 32),
   346  		}
   347  		state.FinalizedCheckpoint = &eth.Checkpoint{
   348  			Epoch: 32,
   349  			Root:  bytesutil.PadTo([]byte("fcroot"), 32),
   350  		}
   351  		return nil
   352  	})
   353  	require.NoError(t, err)
   354  
   355  	result, err := source.ToProto()
   356  	require.NoError(t, err)
   357  	require.NotNil(t, result)
   358  	assert.Equal(t, uint64(1), result.GenesisTime)
   359  	assert.DeepEqual(t, bytesutil.PadTo([]byte("genesisvalidatorroot"), 32), result.GenesisValidatorsRoot)
   360  	assert.Equal(t, types.Slot(2), result.Slot)
   361  	resultFork := result.Fork
   362  	require.NotNil(t, resultFork)
   363  	assert.DeepEqual(t, bytesutil.PadTo([]byte("123"), 4), resultFork.PreviousVersion)
   364  	assert.DeepEqual(t, bytesutil.PadTo([]byte("456"), 4), resultFork.CurrentVersion)
   365  	assert.Equal(t, types.Epoch(3), resultFork.Epoch)
   366  	resultLatestBlockHeader := result.LatestBlockHeader
   367  	require.NotNil(t, resultLatestBlockHeader)
   368  	assert.Equal(t, types.Slot(4), resultLatestBlockHeader.Slot)
   369  	assert.Equal(t, types.ValidatorIndex(5), resultLatestBlockHeader.ProposerIndex)
   370  	assert.DeepEqual(t, bytesutil.PadTo([]byte("lbhparentroot"), 32), resultLatestBlockHeader.ParentRoot)
   371  	assert.DeepEqual(t, bytesutil.PadTo([]byte("lbhstateroot"), 32), resultLatestBlockHeader.StateRoot)
   372  	assert.DeepEqual(t, bytesutil.PadTo([]byte("lbhbodyroot"), 32), resultLatestBlockHeader.BodyRoot)
   373  	assert.DeepEqual(t, [][]byte{bytesutil.PadTo([]byte("blockroots"), 32)}, result.BlockRoots)
   374  	assert.DeepEqual(t, [][]byte{bytesutil.PadTo([]byte("stateroots"), 32)}, result.StateRoots)
   375  	assert.DeepEqual(t, [][]byte{bytesutil.PadTo([]byte("historicalroots"), 32)}, result.HistoricalRoots)
   376  	resultEth1Data := result.Eth1Data
   377  	require.NotNil(t, resultEth1Data)
   378  	assert.DeepEqual(t, bytesutil.PadTo([]byte("e1ddepositroot"), 32), resultEth1Data.DepositRoot)
   379  	assert.Equal(t, uint64(6), resultEth1Data.DepositCount)
   380  	assert.DeepEqual(t, bytesutil.PadTo([]byte("e1dblockhash"), 32), resultEth1Data.BlockHash)
   381  	require.Equal(t, 1, len(result.Eth1DataVotes))
   382  	resultEth1DataVote := result.Eth1DataVotes[0]
   383  	require.NotNil(t, resultEth1DataVote)
   384  	assert.DeepEqual(t, bytesutil.PadTo([]byte("e1dvdepositroot"), 32), resultEth1DataVote.DepositRoot)
   385  	assert.Equal(t, uint64(7), resultEth1DataVote.DepositCount)
   386  	assert.DeepEqual(t, bytesutil.PadTo([]byte("e1dvblockhash"), 32), resultEth1DataVote.BlockHash)
   387  	assert.Equal(t, uint64(8), result.Eth1DepositIndex)
   388  	require.Equal(t, 1, len(result.Validators))
   389  	resultValidator := result.Validators[0]
   390  	require.NotNil(t, resultValidator)
   391  	assert.DeepEqual(t, bytesutil.PadTo([]byte("publickey"), 48), resultValidator.Pubkey)
   392  	assert.DeepEqual(t, bytesutil.PadTo([]byte("withdrawalcredentials"), 32), resultValidator.WithdrawalCredentials)
   393  	assert.Equal(t, uint64(9), resultValidator.EffectiveBalance)
   394  	assert.Equal(t, true, resultValidator.Slashed)
   395  	assert.Equal(t, types.Epoch(10), resultValidator.ActivationEligibilityEpoch)
   396  	assert.Equal(t, types.Epoch(11), resultValidator.ActivationEpoch)
   397  	assert.Equal(t, types.Epoch(12), resultValidator.ExitEpoch)
   398  	assert.Equal(t, types.Epoch(13), resultValidator.WithdrawableEpoch)
   399  	assert.DeepEqual(t, []uint64{14}, result.Balances)
   400  	assert.DeepEqual(t, [][]byte{bytesutil.PadTo([]byte("randaomixes"), 32)}, result.RandaoMixes)
   401  	assert.DeepEqual(t, []uint64{15}, result.Slashings)
   402  	require.Equal(t, 1, len(result.PreviousEpochAttestations))
   403  	resultPrevEpochAtt := result.PreviousEpochAttestations[0]
   404  	require.NotNil(t, resultPrevEpochAtt)
   405  	assert.DeepEqual(t, bitfield.Bitlist{16}, resultPrevEpochAtt.AggregationBits)
   406  	resultPrevEpochAttData := resultPrevEpochAtt.Data
   407  	require.NotNil(t, resultPrevEpochAttData)
   408  	assert.Equal(t, types.Slot(17), resultPrevEpochAttData.Slot)
   409  	assert.Equal(t, types.CommitteeIndex(18), resultPrevEpochAttData.Index)
   410  	assert.DeepEqual(t, bytesutil.PadTo([]byte("peabeaconblockroot"), 32), resultPrevEpochAttData.BeaconBlockRoot)
   411  	resultPrevEpochAttSource := resultPrevEpochAttData.Source
   412  	require.NotNil(t, resultPrevEpochAttSource)
   413  	assert.Equal(t, types.Epoch(19), resultPrevEpochAttSource.Epoch)
   414  	assert.DeepEqual(t, bytesutil.PadTo([]byte("peasroot"), 32), resultPrevEpochAttSource.Root)
   415  	resultPrevEpochAttTarget := resultPrevEpochAttData.Target
   416  	require.NotNil(t, resultPrevEpochAttTarget)
   417  	assert.Equal(t, types.Epoch(20), resultPrevEpochAttTarget.Epoch)
   418  	assert.DeepEqual(t, bytesutil.PadTo([]byte("peatroot"), 32), resultPrevEpochAttTarget.Root)
   419  	assert.Equal(t, types.Slot(21), resultPrevEpochAtt.InclusionDelay)
   420  	assert.Equal(t, types.ValidatorIndex(22), resultPrevEpochAtt.ProposerIndex)
   421  	resultCurrEpochAtt := result.CurrentEpochAttestations[0]
   422  	require.NotNil(t, resultCurrEpochAtt)
   423  	assert.DeepEqual(t, bitfield.Bitlist{23}, resultCurrEpochAtt.AggregationBits)
   424  	resultCurrEpochAttData := resultCurrEpochAtt.Data
   425  	require.NotNil(t, resultCurrEpochAttData)
   426  	assert.Equal(t, types.Slot(24), resultCurrEpochAttData.Slot)
   427  	assert.Equal(t, types.CommitteeIndex(25), resultCurrEpochAttData.Index)
   428  	assert.DeepEqual(t, bytesutil.PadTo([]byte("ceabeaconblockroot"), 32), resultCurrEpochAttData.BeaconBlockRoot)
   429  	resultCurrEpochAttSource := resultCurrEpochAttData.Source
   430  	require.NotNil(t, resultCurrEpochAttSource)
   431  	assert.Equal(t, types.Epoch(26), resultCurrEpochAttSource.Epoch)
   432  	assert.DeepEqual(t, bytesutil.PadTo([]byte("ceasroot"), 32), resultCurrEpochAttSource.Root)
   433  	resultCurrEpochAttTarget := resultCurrEpochAttData.Target
   434  	require.NotNil(t, resultCurrEpochAttTarget)
   435  	assert.Equal(t, types.Epoch(27), resultCurrEpochAttTarget.Epoch)
   436  	assert.DeepEqual(t, bytesutil.PadTo([]byte("ceatroot"), 32), resultCurrEpochAttTarget.Root)
   437  	assert.Equal(t, types.Slot(28), resultCurrEpochAtt.InclusionDelay)
   438  	assert.Equal(t, types.ValidatorIndex(29), resultCurrEpochAtt.ProposerIndex)
   439  	assert.DeepEqual(t, bitfield.Bitvector4{1}, result.JustificationBits)
   440  	resultPrevJustifiedCheckpoint := result.PreviousJustifiedCheckpoint
   441  	require.NotNil(t, resultPrevJustifiedCheckpoint)
   442  	assert.Equal(t, types.Epoch(30), resultPrevJustifiedCheckpoint.Epoch)
   443  	assert.DeepEqual(t, bytesutil.PadTo([]byte("pjcroot"), 32), resultPrevJustifiedCheckpoint.Root)
   444  	resultCurrJustifiedCheckpoint := result.CurrentJustifiedCheckpoint
   445  	require.NotNil(t, resultCurrJustifiedCheckpoint)
   446  	assert.Equal(t, types.Epoch(31), resultCurrJustifiedCheckpoint.Epoch)
   447  	assert.DeepEqual(t, bytesutil.PadTo([]byte("cjcroot"), 32), resultCurrJustifiedCheckpoint.Root)
   448  	resultFinalizedCheckpoint := result.FinalizedCheckpoint
   449  	require.NotNil(t, resultFinalizedCheckpoint)
   450  	assert.Equal(t, types.Epoch(32), resultFinalizedCheckpoint.Epoch)
   451  	assert.DeepEqual(t, bytesutil.PadTo([]byte("fcroot"), 32), resultFinalizedCheckpoint.Root)
   452  }