github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/statefetcher/fetcher_test.go (about)

     1  package statefetcher
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/common/hexutil"
    11  	types "github.com/prysmaticlabs/eth2-types"
    12  	chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    13  	testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    14  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    15  	pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    16  	eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    17  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    18  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    19  	"github.com/prysmaticlabs/prysm/shared/params"
    20  	"github.com/prysmaticlabs/prysm/shared/testutil"
    21  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    22  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    23  )
    24  
    25  func TestGetState(t *testing.T) {
    26  	ctx := context.Background()
    27  
    28  	headSlot := types.Slot(123)
    29  	fillSlot := func(state *pb.BeaconState) error {
    30  		state.Slot = headSlot
    31  		return nil
    32  	}
    33  	state, err := testutil.NewBeaconState(testutil.FillRootsNaturalOpt, fillSlot)
    34  	require.NoError(t, err)
    35  	stateRoot, err := state.HashTreeRoot(ctx)
    36  	require.NoError(t, err)
    37  
    38  	t.Run("head", func(t *testing.T) {
    39  		p := StateProvider{
    40  			ChainInfoFetcher: &chainMock.ChainService{State: state},
    41  		}
    42  
    43  		s, err := p.State(ctx, []byte("head"))
    44  		require.NoError(t, err)
    45  		sRoot, err := s.HashTreeRoot(ctx)
    46  		require.NoError(t, err)
    47  		assert.DeepEqual(t, stateRoot, sRoot)
    48  	})
    49  
    50  	t.Run("genesis", func(t *testing.T) {
    51  		params.SetupTestConfigCleanup(t)
    52  		cfg := params.BeaconConfig()
    53  		cfg.ConfigName = "test"
    54  		params.OverrideBeaconConfig(cfg)
    55  
    56  		db := testDB.SetupDB(t)
    57  		b := testutil.NewBeaconBlock()
    58  		b.Block.StateRoot = bytesutil.PadTo([]byte("foo"), 32)
    59  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
    60  		r, err := b.Block.HashTreeRoot()
    61  		require.NoError(t, err)
    62  
    63  		state, err := testutil.NewBeaconState(func(state *pb.BeaconState) error {
    64  			state.BlockRoots[0] = r[:]
    65  			return nil
    66  		})
    67  		require.NoError(t, err)
    68  		stateRoot, err := state.HashTreeRoot(ctx)
    69  		require.NoError(t, err)
    70  
    71  		require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: r[:]}))
    72  		require.NoError(t, db.SaveGenesisBlockRoot(ctx, r))
    73  		require.NoError(t, db.SaveState(ctx, state, r))
    74  
    75  		p := StateProvider{
    76  			BeaconDB: db,
    77  		}
    78  
    79  		s, err := p.State(ctx, []byte("genesis"))
    80  		require.NoError(t, err)
    81  		sRoot, err := s.HashTreeRoot(ctx)
    82  		require.NoError(t, err)
    83  		assert.DeepEqual(t, stateRoot, sRoot)
    84  	})
    85  
    86  	t.Run("finalized", func(t *testing.T) {
    87  		stateGen := stategen.NewMockService()
    88  		stateGen.StatesByRoot[stateRoot] = state
    89  
    90  		p := StateProvider{
    91  			ChainInfoFetcher: &chainMock.ChainService{
    92  				FinalizedCheckPoint: &eth.Checkpoint{
    93  					Root: stateRoot[:],
    94  				},
    95  			},
    96  			StateGenService: stateGen,
    97  		}
    98  
    99  		s, err := p.State(ctx, []byte("finalized"))
   100  		require.NoError(t, err)
   101  		sRoot, err := s.HashTreeRoot(ctx)
   102  		require.NoError(t, err)
   103  		assert.Equal(t, stateRoot, sRoot)
   104  	})
   105  
   106  	t.Run("justified", func(t *testing.T) {
   107  		stateGen := stategen.NewMockService()
   108  		stateGen.StatesByRoot[stateRoot] = state
   109  
   110  		p := StateProvider{
   111  			ChainInfoFetcher: &chainMock.ChainService{
   112  				CurrentJustifiedCheckPoint: &eth.Checkpoint{
   113  					Root: stateRoot[:],
   114  				},
   115  			},
   116  			StateGenService: stateGen,
   117  		}
   118  
   119  		s, err := p.State(ctx, []byte("justified"))
   120  		require.NoError(t, err)
   121  		sRoot, err := s.HashTreeRoot(ctx)
   122  		require.NoError(t, err)
   123  		assert.DeepEqual(t, stateRoot, sRoot)
   124  	})
   125  
   126  	t.Run("hex_root", func(t *testing.T) {
   127  		stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
   128  		require.NoError(t, err)
   129  		stateGen := stategen.NewMockService()
   130  		stateGen.StatesByRoot[bytesutil.ToBytes32(stateId)] = state
   131  
   132  		p := StateProvider{
   133  			ChainInfoFetcher: &chainMock.ChainService{State: state},
   134  			StateGenService:  stateGen,
   135  		}
   136  
   137  		s, err := p.State(ctx, stateId)
   138  		require.NoError(t, err)
   139  		sRoot, err := s.HashTreeRoot(ctx)
   140  		require.NoError(t, err)
   141  		assert.DeepEqual(t, stateRoot, sRoot)
   142  	})
   143  
   144  	t.Run("hex_root_not_found", func(t *testing.T) {
   145  		p := StateProvider{
   146  			ChainInfoFetcher: &chainMock.ChainService{State: state},
   147  		}
   148  		stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64))
   149  		require.NoError(t, err)
   150  		_, err = p.State(ctx, stateId)
   151  		require.ErrorContains(t, "state not found in the last 8192 state roots", err)
   152  	})
   153  
   154  	t.Run("slot", func(t *testing.T) {
   155  		stateGen := stategen.NewMockService()
   156  		stateGen.StatesBySlot[headSlot] = state
   157  
   158  		p := StateProvider{
   159  			GenesisTimeFetcher: &chainMock.ChainService{Slot: &headSlot},
   160  			StateGenService:    stateGen,
   161  		}
   162  
   163  		s, err := p.State(ctx, []byte(strconv.FormatUint(uint64(headSlot), 10)))
   164  		require.NoError(t, err)
   165  		sRoot, err := s.HashTreeRoot(ctx)
   166  		require.NoError(t, err)
   167  		assert.Equal(t, stateRoot, sRoot)
   168  	})
   169  
   170  	t.Run("slot_too_big", func(t *testing.T) {
   171  		p := StateProvider{
   172  			GenesisTimeFetcher: &chainMock.ChainService{
   173  				Genesis: time.Now(),
   174  			},
   175  		}
   176  		_, err := p.State(ctx, []byte(strconv.FormatUint(1, 10)))
   177  		assert.ErrorContains(t, "slot cannot be in the future", err)
   178  	})
   179  
   180  	t.Run("invalid_state", func(t *testing.T) {
   181  		p := StateProvider{}
   182  		_, err := p.State(ctx, []byte("foo"))
   183  		require.ErrorContains(t, "could not parse state ID", err)
   184  	})
   185  }
   186  
   187  func TestGetStateRoot(t *testing.T) {
   188  	ctx := context.Background()
   189  
   190  	headSlot := types.Slot(123)
   191  	fillSlot := func(state *pb.BeaconState) error {
   192  		state.Slot = headSlot
   193  		return nil
   194  	}
   195  	state, err := testutil.NewBeaconState(testutil.FillRootsNaturalOpt, fillSlot)
   196  	require.NoError(t, err)
   197  	stateRoot, err := state.HashTreeRoot(ctx)
   198  	require.NoError(t, err)
   199  
   200  	t.Run("head", func(t *testing.T) {
   201  		b := testutil.NewBeaconBlock()
   202  		b.Block.StateRoot = stateRoot[:]
   203  		p := StateProvider{
   204  			ChainInfoFetcher: &chainMock.ChainService{
   205  				State: state,
   206  				Block: wrapper.WrappedPhase0SignedBeaconBlock(b),
   207  			},
   208  		}
   209  
   210  		s, err := p.StateRoot(ctx, []byte("head"))
   211  		require.NoError(t, err)
   212  		assert.DeepEqual(t, stateRoot[:], s)
   213  	})
   214  
   215  	t.Run("genesis", func(t *testing.T) {
   216  		db := testDB.SetupDB(t)
   217  		b := testutil.NewBeaconBlock()
   218  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
   219  		r, err := b.Block.HashTreeRoot()
   220  		require.NoError(t, err)
   221  
   222  		state, err := testutil.NewBeaconState(func(state *pb.BeaconState) error {
   223  			state.BlockRoots[0] = r[:]
   224  			return nil
   225  		})
   226  		require.NoError(t, err)
   227  
   228  		require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: r[:]}))
   229  		require.NoError(t, db.SaveGenesisBlockRoot(ctx, r))
   230  		require.NoError(t, db.SaveState(ctx, state, r))
   231  
   232  		p := StateProvider{
   233  			BeaconDB: db,
   234  		}
   235  
   236  		s, err := p.StateRoot(ctx, []byte("genesis"))
   237  		require.NoError(t, err)
   238  		genesisBlock, err := db.GenesisBlock(ctx)
   239  		require.NoError(t, err)
   240  		assert.DeepEqual(t, genesisBlock.Block().StateRoot(), s)
   241  	})
   242  
   243  	t.Run("finalized", func(t *testing.T) {
   244  		db := testDB.SetupDB(t)
   245  		genesis := bytesutil.ToBytes32([]byte("genesis"))
   246  		require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesis))
   247  		blk := testutil.NewBeaconBlock()
   248  		blk.Block.ParentRoot = genesis[:]
   249  		blk.Block.Slot = 40
   250  		root, err := blk.Block.HashTreeRoot()
   251  		require.NoError(t, err)
   252  		cp := &eth.Checkpoint{
   253  			Epoch: 5,
   254  			Root:  root[:],
   255  		}
   256  		// a valid chain is required to save finalized checkpoint.
   257  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
   258  		st, err := testutil.NewBeaconState()
   259  		require.NoError(t, err)
   260  		require.NoError(t, st.SetSlot(1))
   261  		// a state is required to save checkpoint
   262  		require.NoError(t, db.SaveState(ctx, st, root))
   263  		require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
   264  
   265  		p := StateProvider{
   266  			BeaconDB: db,
   267  		}
   268  
   269  		s, err := p.StateRoot(ctx, []byte("finalized"))
   270  		require.NoError(t, err)
   271  		assert.DeepEqual(t, blk.Block.StateRoot, s)
   272  	})
   273  
   274  	t.Run("justified", func(t *testing.T) {
   275  		db := testDB.SetupDB(t)
   276  		genesis := bytesutil.ToBytes32([]byte("genesis"))
   277  		require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesis))
   278  		blk := testutil.NewBeaconBlock()
   279  		blk.Block.ParentRoot = genesis[:]
   280  		blk.Block.Slot = 40
   281  		root, err := blk.Block.HashTreeRoot()
   282  		require.NoError(t, err)
   283  		cp := &eth.Checkpoint{
   284  			Epoch: 5,
   285  			Root:  root[:],
   286  		}
   287  		// a valid chain is required to save finalized checkpoint.
   288  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
   289  		st, err := testutil.NewBeaconState()
   290  		require.NoError(t, err)
   291  		require.NoError(t, st.SetSlot(1))
   292  		// a state is required to save checkpoint
   293  		require.NoError(t, db.SaveState(ctx, st, root))
   294  		require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
   295  
   296  		p := StateProvider{
   297  			BeaconDB: db,
   298  		}
   299  
   300  		s, err := p.StateRoot(ctx, []byte("justified"))
   301  		require.NoError(t, err)
   302  		assert.DeepEqual(t, blk.Block.StateRoot, s)
   303  	})
   304  
   305  	t.Run("hex_root", func(t *testing.T) {
   306  		stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
   307  		require.NoError(t, err)
   308  
   309  		p := StateProvider{
   310  			ChainInfoFetcher: &chainMock.ChainService{State: state},
   311  		}
   312  
   313  		s, err := p.StateRoot(ctx, stateId)
   314  		require.NoError(t, err)
   315  		assert.DeepEqual(t, stateId, s)
   316  	})
   317  
   318  	t.Run("hex_root_not_found", func(t *testing.T) {
   319  		p := StateProvider{
   320  			ChainInfoFetcher: &chainMock.ChainService{State: state},
   321  		}
   322  		stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64))
   323  		require.NoError(t, err)
   324  		_, err = p.StateRoot(ctx, stateId)
   325  		require.ErrorContains(t, "state root not found in the last 8192 state roots", err)
   326  	})
   327  
   328  	t.Run("slot", func(t *testing.T) {
   329  		db := testDB.SetupDB(t)
   330  		genesis := bytesutil.ToBytes32([]byte("genesis"))
   331  		require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesis))
   332  		blk := testutil.NewBeaconBlock()
   333  		blk.Block.ParentRoot = genesis[:]
   334  		blk.Block.Slot = 40
   335  		root, err := blk.Block.HashTreeRoot()
   336  		require.NoError(t, err)
   337  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
   338  		st, err := testutil.NewBeaconState()
   339  		require.NoError(t, err)
   340  		require.NoError(t, st.SetSlot(1))
   341  		// a state is required to save checkpoint
   342  		require.NoError(t, db.SaveState(ctx, st, root))
   343  
   344  		slot := types.Slot(40)
   345  		p := StateProvider{
   346  			GenesisTimeFetcher: &chainMock.ChainService{Slot: &slot},
   347  			BeaconDB:           db,
   348  		}
   349  
   350  		s, err := p.StateRoot(ctx, []byte(strconv.FormatUint(uint64(slot), 10)))
   351  		require.NoError(t, err)
   352  		assert.DeepEqual(t, blk.Block.StateRoot, s)
   353  	})
   354  
   355  	t.Run("slot_too_big", func(t *testing.T) {
   356  		p := StateProvider{
   357  			GenesisTimeFetcher: &chainMock.ChainService{
   358  				Genesis: time.Now(),
   359  			},
   360  		}
   361  		_, err := p.StateRoot(ctx, []byte(strconv.FormatUint(1, 10)))
   362  		assert.ErrorContains(t, "slot cannot be in the future", err)
   363  	})
   364  
   365  	t.Run("invalid_state", func(t *testing.T) {
   366  		p := StateProvider{}
   367  		_, err := p.StateRoot(ctx, []byte("foo"))
   368  		require.ErrorContains(t, "could not parse state ID", err)
   369  	})
   370  }
   371  
   372  func TestNewStateNotFoundError(t *testing.T) {
   373  	e := NewStateNotFoundError(100)
   374  	assert.Equal(t, "state not found in the last 100 state roots", e.message)
   375  }