Skip to content

Commit

Permalink
Handle hex in Blocker, Stater and optimistic mode checker (#12979)
Browse files Browse the repository at this point in the history
* Handle hex in `Blocker`

* hex in stater

* ineff fix

* optimistic mode

---------

Co-authored-by: Nishant Das <[email protected]>
  • Loading branch information
rkapka and nisdas authored Oct 3, 2023
1 parent 9e33723 commit 58f23d2
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 5 deletions.
2 changes: 2 additions & 0 deletions beacon-chain/rpc/eth/helpers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ go_library(
"//consensus-types/validator:go_default_library",
"//encoding/bytesutil:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@org_golang_google_grpc//codes:go_default_library",
"@org_golang_google_grpc//status:go_default_library",
Expand Down Expand Up @@ -62,6 +63,7 @@ go_test(
"//testing/assert:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
"@org_golang_google_grpc//:go_default_library",
],
Expand Down
9 changes: 8 additions & 1 deletion beacon-chain/rpc/eth/helpers/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strconv"
"strings"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/api/grpc"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
Expand Down Expand Up @@ -95,7 +96,13 @@ func IsOptimistic(
}
return optimisticModeFetcher.IsOptimisticForRoot(ctx, bytesutil.ToBytes32(jcp.Root))
default:
if len(stateId) == 32 {
if len(stateIdString) >= 2 && stateIdString[:2] == "0x" {
id, err := hexutil.Decode(stateIdString)
if err != nil {
return false, err
}
return isStateRootOptimistic(ctx, id, optimisticModeFetcher, stateFetcher, chainInfo, database)
} else if len(stateId) == 32 {
return isStateRootOptimistic(ctx, stateId, optimisticModeFetcher, stateFetcher, chainInfo, database)
} else {
optimistic, err := optimisticModeFetcher.IsOptimistic(ctx)
Expand Down
73 changes: 73 additions & 0 deletions beacon-chain/rpc/eth/helpers/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"
"testing"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
grpcutil "github.com/prysmaticlabs/prysm/v4/api/grpc"
chainmock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
Expand Down Expand Up @@ -204,6 +205,78 @@ func TestIsOptimistic(t *testing.T) {
assert.Equal(t, true, o)
})
})
t.Run("hex", func(t *testing.T) {
t.Run("is head and head is optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: true}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("is head and head is not optimistic", func(t *testing.T) {
st, err := util.NewBeaconState()
require.NoError(t, err)
cs := &chainmock.ChainService{Optimistic: false}
mf := &testutil.MockStater{BeaconState: st}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, nil)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("root is optimistic", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
bRoot, err := b.Block().HashTreeRoot()
require.NoError(t, err)
cs := &chainmock.ChainService{State: chainSt, OptimisticRoots: map[[32]byte]bool{bRoot: true}}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
t.Run("root is not optimistic", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
b.SetStateRoot(bytesutil.PadTo([]byte("root"), 32))
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
cs := &chainmock.ChainService{State: chainSt}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), cs, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, false, o)
})
t.Run("no canonical blocks", func(t *testing.T) {
b, err := blocks.NewSignedBeaconBlock(util.NewBeaconBlock())
require.NoError(t, err)
db := dbtest.SetupDB(t)
require.NoError(t, db.SaveBlock(ctx, b))
fetcherSt, err := util.NewBeaconState()
require.NoError(t, err)
chainSt, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, chainSt.SetSlot(fieldparams.SlotsPerEpoch))
cs := &chainmock.ChainService{Optimistic: false, State: chainSt, CanonicalRoots: map[[32]byte]bool{}}
mf := &testutil.MockStater{BeaconState: fetcherSt}
o, err := IsOptimistic(ctx, []byte(hexutil.Encode(bytesutil.PadTo([]byte("root"), 32))), nil, mf, cs, db)
require.NoError(t, err)
assert.Equal(t, true, o)
})
})
t.Run("slot", func(t *testing.T) {
t.Run("head is not optimistic", func(t *testing.T) {
cs := &chainmock.ChainService{Optimistic: false}
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/lookup/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"//consensus-types/primitives:go_default_library",
"//encoding/bytesutil:go_default_library",
"//time/slots:go_default_library",
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@io_opencensus_go//trace:go_default_library",
],
Expand Down
16 changes: 15 additions & 1 deletion beacon-chain/rpc/lookup/blocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package lookup
import (
"context"
"strconv"
"strings"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
Expand Down Expand Up @@ -47,6 +49,7 @@ type BeaconDbBlocker struct {
// - "justified"
// - <slot>
// - <hex encoded block root with '0x' prefix>
// - <block root>
func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.ReadOnlySignedBeaconBlock, error) {
var err error
var blk interfaces.ReadOnlySignedBeaconBlock
Expand All @@ -69,7 +72,18 @@ func (p *BeaconDbBlocker) Block(ctx context.Context, id []byte) (interfaces.Read
return nil, errors.Wrap(err, "could not retrieve genesis block")
}
default:
if len(id) == 32 {
stringId := strings.ToLower(string(id))
if len(stringId) >= 2 && stringId[:2] == "0x" {
decoded, err := hexutil.Decode(string(id))
if err != nil {
e := NewBlockIdParseError(err)
return nil, &e
}
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(decoded))
if err != nil {
return nil, errors.Wrap(err, "could not retrieve block")
}
} else if len(id) == 32 {
blk, err = p.BeaconDB.Block(ctx, bytesutil.ToBytes32(id))
if err != nil {
return nil, errors.Wrap(err, "could not retrieve block")
Expand Down
6 changes: 6 additions & 0 deletions beacon-chain/rpc/lookup/blocker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"reflect"
"testing"

"github.com/ethereum/go-ethereum/common/hexutil"
mock "github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain/testing"
dbtesting "github.com/prysmaticlabs/prysm/v4/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/testutil"
Expand Down Expand Up @@ -116,6 +117,11 @@ func TestGetBlock(t *testing.T) {
blockID: bytesutil.PadTo([]byte("hi there"), 32),
want: nil,
},
{
name: "hex",
blockID: []byte(hexutil.Encode(blkContainers[20].BlockRoot)),
want: blkContainers[20].Block.(*ethpbalpha.BeaconBlockContainer_Phase0Block).Phase0Block,
},
{
name: "no block",
blockID: []byte("105"),
Expand Down
12 changes: 11 additions & 1 deletion beacon-chain/rpc/lookup/stater.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"strings"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
Expand Down Expand Up @@ -94,6 +95,7 @@ type BeaconDbStater struct {
// - "justified"
// - <slot>
// - <hex encoded state root with '0x' prefix>
// - <state root>
func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.BeaconState, error) {
var (
s state.BeaconState
Expand Down Expand Up @@ -141,7 +143,15 @@ func (p *BeaconDbStater) State(ctx context.Context, stateId []byte) (state.Beaco
return nil, errors.Wrap(err, "could not get justified state")
}
default:
if len(stateId) == 32 {
stringId := strings.ToLower(string(stateId))
if len(stringId) >= 2 && stringId[:2] == "0x" {
decoded, parseErr := hexutil.Decode(string(stateId))
if parseErr != nil {
e := NewStateIdParseError(parseErr)
return nil, &e
}
s, err = p.stateByRoot(ctx, decoded)
} else if len(stateId) == 32 {
s, err = p.stateByRoot(ctx, stateId)
} else {
slotNumber, parseErr := strconv.ParseUint(stateIdString, 10, 64)
Expand Down
23 changes: 21 additions & 2 deletions beacon-chain/rpc/lookup/stater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,26 @@ func TestGetState(t *testing.T) {
assert.DeepEqual(t, stateRoot, sRoot)
})

t.Run("hex_root", func(t *testing.T) {
t.Run("hex", func(t *testing.T) {
hex := "0x" + strings.Repeat("0", 63) + "1"
root, err := hexutil.Decode(hex)
require.NoError(t, err)
stateGen := mockstategen.NewMockService()
stateGen.StatesByRoot[bytesutil.ToBytes32(root)] = newBeaconState

p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
StateGenService: stateGen,
}

s, err := p.State(ctx, []byte(hex))
require.NoError(t, err)
sRoot, err := s.HashTreeRoot(ctx)
require.NoError(t, err)
assert.DeepEqual(t, stateRoot, sRoot)
})

t.Run("root", func(t *testing.T) {
stateId, err := hexutil.Decode("0x" + strings.Repeat("0", 63) + "1")
require.NoError(t, err)
stateGen := mockstategen.NewMockService()
Expand All @@ -158,7 +177,7 @@ func TestGetState(t *testing.T) {
assert.DeepEqual(t, stateRoot, sRoot)
})

t.Run("hex_root_not_found", func(t *testing.T) {
t.Run("root not found", func(t *testing.T) {
p := BeaconDbStater{
ChainInfoFetcher: &chainMock.ChainService{State: newBeaconState},
}
Expand Down

0 comments on commit 58f23d2

Please sign in to comment.