Skip to content

Commit

Permalink
Implement GetBeaconState Endpoint (#5668)
Browse files Browse the repository at this point in the history
* implement get beacon state
* gaz
* Merge branch 'master' into implement-debug-state
* passing tests
* enable with featureconfig
* struct oder
* Update beacon-chain/rpc/beacon/state.go
* Merge refs/heads/master into implement-debug-state
* lint resolve
* Merge branch 'implement-debug-state' of github.com:prysmaticlabs/prysm into implement-debug-state
* tested at runtime
* fix build
* Merge branch 'master' into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* build and fmt
* conf
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
* Merge refs/heads/master into implement-debug-state
  • Loading branch information
rauljordan authored May 1, 2020
1 parent e1ac1d3 commit 2e33595
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 161 deletions.
5 changes: 5 additions & 0 deletions beacon-chain/flags/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,9 @@ var (
Usage: "The amount of blocks the local peer is bounded to request and respond to in a batch.",
Value: 64,
}
// EnableDebugRPCEndpoints as /v1/beacon/state.
EnableDebugRPCEndpoints = &cli.BoolFlag{
Name: "enable-debug-rpc-endpoints",
Usage: "Enables the debug rpc service, containing utility endpoints such as /eth/v1alpha1/beacon/state. Requires --new-state-mgmt",
}
)
1 change: 1 addition & 0 deletions beacon-chain/gateway/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ go_library(
],
deps = [
"//shared:go_default_library",
"//proto/beacon/rpc/v1:go_grpc_gateway_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_grpc_gateway_library",
"@com_github_rs_cors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
Expand Down
56 changes: 37 additions & 19 deletions beacon-chain/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1_gateway"
pbrpc "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1_gateway"
"github.com/prysmaticlabs/prysm/shared"
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
Expand All @@ -21,16 +22,16 @@ var _ = shared.Service(&Gateway{})
// Gateway is the gRPC gateway to serve HTTP JSON traffic as a proxy and forward
// it to the beacon-chain gRPC server.
type Gateway struct {
conn *grpc.ClientConn
ctx context.Context
cancel context.CancelFunc
gatewayAddr string
remoteAddr string
server *http.Server
mux *http.ServeMux
allowedOrigins []string

startFailure error
conn *grpc.ClientConn
ctx context.Context
cancel context.CancelFunc
gatewayAddr string
remoteAddr string
server *http.Server
mux *http.ServeMux
allowedOrigins []string
startFailure error
enableDebugRPCEndpoints bool
}

// Start the gateway service. This serves the HTTP JSON traffic on the specified
Expand All @@ -50,12 +51,21 @@ func (g *Gateway) Start() {

g.conn = conn

gwmux := gwruntime.NewServeMux(gwruntime.WithMarshalerOption(gwruntime.MIMEWildcard, &gwruntime.JSONPb{OrigName: false, EmitDefaults: true}))
for _, f := range []func(context.Context, *gwruntime.ServeMux, *grpc.ClientConn) error{
gwmux := gwruntime.NewServeMux(
gwruntime.WithMarshalerOption(
gwruntime.MIMEWildcard,
&gwruntime.JSONPb{OrigName: false, EmitDefaults: true},
),
)
handlers := []func(context.Context, *gwruntime.ServeMux, *grpc.ClientConn) error{
ethpb.RegisterNodeHandler,
ethpb.RegisterBeaconChainHandler,
ethpb.RegisterBeaconNodeValidatorHandler,
} {
}
if g.enableDebugRPCEndpoints {
handlers = append(handlers, pbrpc.RegisterDebugHandler)
}
for _, f := range handlers {
if err := f(ctx, gwmux, conn); err != nil {
log.WithError(err).Error("Failed to start gateway")
g.startFailure = err
Expand Down Expand Up @@ -108,17 +118,25 @@ func (g *Gateway) Stop() error {

// New returns a new gateway server which translates HTTP into gRPC.
// Accepts a context and optional http.ServeMux.
func New(ctx context.Context, remoteAddress, gatewayAddress string, mux *http.ServeMux, allowedOrigins []string) *Gateway {
func New(
ctx context.Context,
remoteAddress,
gatewayAddress string,
mux *http.ServeMux,
allowedOrigins []string,
enableDebugRPCEndpoints bool,
) *Gateway {
if mux == nil {
mux = http.NewServeMux()
}

return &Gateway{
remoteAddr: remoteAddress,
gatewayAddr: gatewayAddress,
ctx: ctx,
mux: mux,
allowedOrigins: allowedOrigins,
remoteAddr: remoteAddress,
gatewayAddr: gatewayAddress,
ctx: ctx,
mux: mux,
allowedOrigins: allowedOrigins,
enableDebugRPCEndpoints: enableDebugRPCEndpoints,
}
}

Expand Down
18 changes: 13 additions & 5 deletions beacon-chain/gateway/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import (
)

var (
beaconRPC = flag.String("beacon-rpc", "localhost:4000", "Beacon chain gRPC endpoint")
port = flag.Int("port", 8000, "Port to serve on")
debug = flag.Bool("debug", false, "Enable debug logging")
allowedOrigins = flag.String("corsdomain", "", "A comma separated list of CORS domains to allow")
beaconRPC = flag.String("beacon-rpc", "localhost:4000", "Beacon chain gRPC endpoint")
port = flag.Int("port", 8000, "Port to serve on")
debug = flag.Bool("debug", false, "Enable debug logging")
allowedOrigins = flag.String("corsdomain", "", "A comma separated list of CORS domains to allow")
enableDebugRPCEndpoints = flag.Bool("enable-debug-rpc-endpoints", false, "Enable debug rpc endpoints such as /eth/v1alpha1/beacon/state")
)

func init() {
Expand All @@ -35,7 +36,14 @@ func main() {
}

mux := http.NewServeMux()
gw := gateway.New(context.Background(), *beaconRPC, fmt.Sprintf("0.0.0.0:%d", *port), mux, strings.Split(*allowedOrigins, ","))
gw := gateway.New(
context.Background(),
*beaconRPC,
fmt.Sprintf("0.0.0.0:%d", *port),
mux,
strings.Split(*allowedOrigins, ","),
*enableDebugRPCEndpoints,
)
mux.HandleFunc("/swagger/", gateway.SwaggerServer())
mux.HandleFunc("/healthz", healthzServer(gw))
gw.Start()
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ var appFlags = []cli.Flag{
flags.ArchiveBlocksFlag,
flags.ArchiveAttestationsFlag,
flags.SlotsPerArchivedPoint,
flags.EnableDebugRPCEndpoints,
cmd.BootstrapNode,
cmd.NoDiscovery,
cmd.StaticPeers,
Expand Down
64 changes: 34 additions & 30 deletions beacon-chain/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -538,38 +538,40 @@ func (b *BeaconNode) registerRPCService() error {
slasherCert := b.cliCtx.String(flags.SlasherCertFlag.Name)
slasherProvider := b.cliCtx.String(flags.SlasherProviderFlag.Name)
mockEth1DataVotes := b.cliCtx.Bool(flags.InteropMockEth1DataVotesFlag.Name)
enableDebugRPCEndpoints := b.cliCtx.Bool(flags.EnableDebugRPCEndpoints.Name)
p2pService := b.fetchP2P()
rpcService := rpc.NewService(b.ctx, &rpc.Config{
Host: host,
Port: port,
CertFlag: cert,
KeyFlag: key,
BeaconDB: b.db,
Broadcaster: p2pService,
PeersFetcher: p2pService,
HeadFetcher: chainService,
ForkFetcher: chainService,
FinalizationFetcher: chainService,
ParticipationFetcher: chainService,
BlockReceiver: chainService,
AttestationReceiver: chainService,
GenesisTimeFetcher: chainService,
GenesisFetcher: chainService,
AttestationsPool: b.attestationPool,
ExitPool: b.exitPool,
SlashingsPool: b.slashingsPool,
POWChainService: web3Service,
ChainStartFetcher: chainStartFetcher,
MockEth1Votes: mockEth1DataVotes,
SyncService: syncService,
DepositFetcher: depositFetcher,
PendingDepositFetcher: b.depositCache,
BlockNotifier: b,
StateNotifier: b,
OperationNotifier: b,
SlasherCert: slasherCert,
SlasherProvider: slasherProvider,
StateGen: b.stateGen,
Host: host,
Port: port,
CertFlag: cert,
KeyFlag: key,
BeaconDB: b.db,
Broadcaster: p2pService,
PeersFetcher: p2pService,
HeadFetcher: chainService,
ForkFetcher: chainService,
FinalizationFetcher: chainService,
ParticipationFetcher: chainService,
BlockReceiver: chainService,
AttestationReceiver: chainService,
GenesisTimeFetcher: chainService,
GenesisFetcher: chainService,
AttestationsPool: b.attestationPool,
ExitPool: b.exitPool,
SlashingsPool: b.slashingsPool,
POWChainService: web3Service,
ChainStartFetcher: chainStartFetcher,
MockEth1Votes: mockEth1DataVotes,
SyncService: syncService,
DepositFetcher: depositFetcher,
PendingDepositFetcher: b.depositCache,
BlockNotifier: b,
StateNotifier: b,
OperationNotifier: b,
SlasherCert: slasherCert,
SlasherProvider: slasherProvider,
StateGen: b.stateGen,
EnableDebugRPCEndpoints: enableDebugRPCEndpoints,
})

return b.services.RegisterService(rpcService)
Expand Down Expand Up @@ -610,13 +612,15 @@ func (b *BeaconNode) registerGRPCGateway() error {
selfAddress := fmt.Sprintf("127.0.0.1:%d", b.cliCtx.Int(flags.RPCPort.Name))
gatewayAddress := fmt.Sprintf("0.0.0.0:%d", gatewayPort)
allowedOrigins := strings.Split(b.cliCtx.String(flags.GPRCGatewayCorsDomain.Name), ",")
enableDebugRPCEndpoints := b.cliCtx.Bool(flags.EnableDebugRPCEndpoints.Name)
return b.services.RegisterService(
gateway.New(
b.ctx,
selfAddress,
gatewayAddress,
nil, /*optional mux*/
allowedOrigins,
enableDebugRPCEndpoints,
),
)
}
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ go_library(
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/sync:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/beacon/rpc/v1:go_default_library",
"//proto/slashing:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
Expand Down
4 changes: 4 additions & 0 deletions beacon-chain/rpc/beacon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ go_library(
"config.go",
"server.go",
"slashings.go",
"state.go",
"validators.go",
"validators_stream.go",
],
Expand Down Expand Up @@ -37,6 +38,7 @@ go_library(
"//beacon-chain/state/stategen:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/beacon/rpc/v1:go_default_library",
"//shared/attestationutil:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/event:go_default_library",
Expand Down Expand Up @@ -67,6 +69,7 @@ go_test(
"committees_test.go",
"config_test.go",
"slashings_test.go",
"state_test.go",
"validators_stream_test.go",
"validators_test.go",
],
Expand All @@ -92,6 +95,7 @@ go_test(
"//beacon-chain/state:go_default_library",
"//beacon-chain/state/stategen:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//proto/beacon/rpc/v1:go_default_library",
"//shared/attestationutil:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
Expand Down
39 changes: 39 additions & 0 deletions beacon-chain/rpc/beacon/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package beacon

import (
"context"

pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
pbrpc "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// GetBeaconState retrieves a beacon state
// from the beacon node by either a slot or block root.
func (bs *Server) GetBeaconState(
ctx context.Context,
req *pbrpc.BeaconStateRequest,
) (*pbp2p.BeaconState, error) {
if !featureconfig.Get().NewStateMgmt {
return nil, status.Error(codes.FailedPrecondition, "requires --enable-new-state-mgmt to function")
}
switch q := req.QueryFilter.(type) {
case *pbrpc.BeaconStateRequest_Slot:
st, err := bs.StateGen.StateBySlot(ctx, q.Slot)
if err != nil {
return nil, status.Errorf(codes.Internal, "could not compute state by slot: %v", err)
}
return st.CloneInnerState(), nil
case *pbrpc.BeaconStateRequest_BlockRoot:
st, err := bs.StateGen.StateByRoot(ctx, bytesutil.ToBytes32(q.BlockRoot))
if err != nil {
return nil, status.Errorf(codes.Internal, "could not compute state by block root: %v", err)
}
return st.CloneInnerState(), nil
default:
return nil, status.Error(codes.InvalidArgument, "need to specify either a block root or slot to request state")
}
}
80 changes: 80 additions & 0 deletions beacon-chain/rpc/beacon/state_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package beacon

import (
"context"
"testing"

"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
pbrpc "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/testutil"
)

func TestServer_GetBeaconState(t *testing.T) {
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{NewStateMgmt: true})
defer resetCfg()

db := dbTest.SetupDB(t)
defer dbTest.TeardownDB(t, db)

ctx := context.Background()
st := testutil.NewBeaconState()
slot := uint64(100)
if err := st.SetSlot(slot); err != nil {
t.Fatal(err)
}
b := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{
Slot: slot,
}}
if err := db.SaveBlock(ctx, b); err != nil {
t.Fatal(err)
}
gRoot, err := ssz.HashTreeRoot(b.Block)
if err != nil {
t.Fatal(err)
}
gen := stategen.New(db, cache.NewStateSummaryCache())
if err := gen.SaveState(ctx, gRoot, st); err != nil {
t.Fatal(err)
}
if err := db.SaveState(ctx, st, gRoot); err != nil {
t.Fatal(err)
}
bs := &Server{
BeaconDB: db,
StateGen: gen,
}
if _, err := bs.GetBeaconState(ctx, &pbrpc.BeaconStateRequest{}); err == nil {
t.Errorf("Expected error without a query filter, received nil")
}
req := &pbrpc.BeaconStateRequest{
QueryFilter: &pbrpc.BeaconStateRequest_BlockRoot{
BlockRoot: gRoot[:],
},
}
res, err := bs.GetBeaconState(ctx, req)
if err != nil {
t.Fatal(err)
}
wanted := st.CloneInnerState()
if !proto.Equal(wanted, res) {
t.Errorf("Wanted %v, received %v", wanted, res)
}
req = &pbrpc.BeaconStateRequest{
QueryFilter: &pbrpc.BeaconStateRequest_Slot{
Slot: slot,
},
}
res, err = bs.GetBeaconState(ctx, req)
if err != nil {
t.Fatal(err)
}
if !proto.Equal(wanted, res) {
t.Errorf("Wanted %v, received %v", wanted, res)
}
}
Loading

0 comments on commit 2e33595

Please sign in to comment.