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: ð.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: ð.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 := ð.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 := ð.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 }