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, &ethpb.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] = &ethpb.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] = &ethpb.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] = &ethpb.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, &ethpb.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  }