diff --git a/beacon-chain/rpc/eth/helpers/sync.go b/beacon-chain/rpc/eth/helpers/sync.go index 0f1d450930..a30a57f2b7 100644 --- a/beacon-chain/rpc/eth/helpers/sync.go +++ b/beacon-chain/rpc/eth/helpers/sync.go @@ -53,7 +53,7 @@ func IsOptimistic( } return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(jcp.Root)) default: - if len(stateIdString) >= 2 && stateIdString[:2] == "0x" { + if bytesutil.IsHex(stateId) { id, err := hexutil.Decode(stateIdString) if err != nil { return false, err diff --git a/beacon-chain/rpc/lookup/blocker.go b/beacon-chain/rpc/lookup/blocker.go index 8d8a1b6f1f..39bcedc954 100644 --- a/beacon-chain/rpc/lookup/blocker.go +++ b/beacon-chain/rpc/lookup/blocker.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "strconv" - "strings" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/pkg/errors" @@ -82,8 +81,7 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read return nil, errors.Wrap(err, "could not retrieve genesis block") } default: - stringId := strings.ToLower(string(id)) - if len(stringId) >= 2 && stringId[:2] == "0x" { + if bytesutil.IsHex(id) { decoded, err := hexutil.Decode(string(id)) if err != nil { e := NewBlockIdParseError(err) diff --git a/beacon-chain/rpc/lookup/stater.go b/beacon-chain/rpc/lookup/stater.go index 5c062bfeb9..5ddbaaebe5 100644 --- a/beacon-chain/rpc/lookup/stater.go +++ b/beacon-chain/rpc/lookup/stater.go @@ -143,7 +143,7 @@ func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.Beaco return nil, errors.Wrap(err, "could not get justified state") } default: - if len(stateIdString) >= 2 && stateIdString[:2] == "0x" { + if bytesutil.IsHex(stateId) { decoded, parseErr := hexutil.Decode(string(stateId)) if parseErr != nil { e := NewStateIdParseError(parseErr) @@ -185,7 +185,15 @@ func (p *BeaconDbStater) StateRoot(ctx context.Context, stateId []byte) (root [] case "justified": root, err = p.justifiedStateRoot(ctx) default: - if len(stateId) == 32 { + if bytesutil.IsHex(stateId) { + var decoded []byte + decoded, err = hexutil.Decode(string(stateId)) + if err != nil { + e := NewStateIdParseError(err) + return nil, &e + } + root, err = p.stateRootByRoot(ctx, decoded) + } else if len(stateId) == 32 { root, err = p.stateRootByRoot(ctx, stateId) } else { slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64) diff --git a/beacon-chain/rpc/lookup/stater_test.go b/beacon-chain/rpc/lookup/stater_test.go index 009c8c3026..60d1e56ddd 100644 --- a/beacon-chain/rpc/lookup/stater_test.go +++ b/beacon-chain/rpc/lookup/stater_test.go @@ -241,7 +241,6 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, err) assert.DeepEqual(t, stateRoot[:], s) }) - t.Run("genesis", func(t *testing.T) { db := testDB.SetupDB(t) b := util.NewBeaconBlock() @@ -270,7 +269,6 @@ func TestGetStateRoot(t *testing.T) { sr := genesisBlock.Block().StateRoot() assert.DeepEqual(t, sr[:], s) }) - t.Run("finalized", func(t *testing.T) { db := testDB.SetupDB(t) genesis := bytesutil.ToBytes32([]byte("genesis")) @@ -301,7 +299,6 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, err) assert.DeepEqual(t, blk.Block.StateRoot, s) }) - t.Run("justified", func(t *testing.T) { db := testDB.SetupDB(t) genesis := bytesutil.ToBytes32([]byte("genesis")) @@ -332,30 +329,52 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, err) assert.DeepEqual(t, blk.Block.StateRoot, s) }) - - t.Run("hex_root", func(t *testing.T) { - stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1") - require.NoError(t, err) + t.Run("hex", func(t *testing.T) { + hex := "0x" + strings.Repeat("0", 63) + "1" p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } - s, err := p.StateRoot(ctx, stateId) + s, err := p.StateRoot(ctx, []byte(hex)) require.NoError(t, err) - assert.DeepEqual(t, stateId, s) + expected, err := hexutil.Decode(hex) + require.NoError(t, err) + assert.DeepEqual(t, expected, s) }) + t.Run("hex not found", func(t *testing.T) { + hex := "0x" + strings.Repeat("f", 64) - t.Run("hex_root_not_found", func(t *testing.T) { p := BeaconDbStater{ ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, } - stateId, err := hexutil.Decode("0x" + strings.Repeat("f", 64)) - require.NoError(t, err) - _, err = p.StateRoot(ctx, stateId) + + _, err = p.StateRoot(ctx, []byte(hex)) require.ErrorContains(t, "state root not found in the last 8192 state roots", err) }) + t.Run("bytes", func(t *testing.T) { + root, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1") + require.NoError(t, err) + p := BeaconDbStater{ + ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, + } + + s, err := p.StateRoot(ctx, root) + require.NoError(t, err) + assert.DeepEqual(t, root, s) + }) + t.Run("bytes not found", func(t *testing.T) { + root, err := hexutil.Decode("0x" + strings.Repeat("f", 64)) + require.NoError(t, err) + + p := BeaconDbStater{ + ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState}, + } + + _, err = p.StateRoot(ctx, root) + require.ErrorContains(t, "state root not found in the last 8192 state roots", err) + }) t.Run("slot", func(t *testing.T) { db := testDB.SetupDB(t) genesis := bytesutil.ToBytes32([]byte("genesis")) @@ -382,8 +401,7 @@ func TestGetStateRoot(t *testing.T) { require.NoError(t, err) assert.DeepEqual(t, blk.Block.StateRoot, s) }) - - t.Run("slot_too_big", func(t *testing.T) { + t.Run("slot too big", func(t *testing.T) { p := BeaconDbStater{ GenesisTimeFetcher: &chainMock.ChainService{ Genesis: time.Now(), @@ -393,7 +411,7 @@ func TestGetStateRoot(t *testing.T) { assert.ErrorContains(t, "slot cannot be in the future", err) }) - t.Run("invalid_state", func(t *testing.T) { + t.Run("invalid state", func(t *testing.T) { p := BeaconDbStater{} _, err := p.StateRoot(ctx, []byte("foo")) require.ErrorContains(t, "could not parse state ID", err) diff --git a/changelog/radek_fix-state-root-endpoint.md b/changelog/radek_fix-state-root-endpoint.md new file mode 100644 index 0000000000..ab3ddf75c8 --- /dev/null +++ b/changelog/radek_fix-state-root-endpoint.md @@ -0,0 +1,3 @@ +#### Ignored + +- Allow hex strings in `/eth/v1/beacon/states/{state_id}/root` endpoint.