Skip to content

Commit

Permalink
Add finalized flag to API responses (#11947)
Browse files Browse the repository at this point in the history
* server code

(cherry picked from commit fc68e6e78f2a84c66cd6c4db2a482cccdaf487d5)

* tests

* middleware

* more tests

* fix one more test
  • Loading branch information
rkapka authored Jan 31, 2023
1 parent c070283 commit b10e59a
Show file tree
Hide file tree
Showing 13 changed files with 539 additions and 79 deletions.
10 changes: 10 additions & 0 deletions beacon-chain/rpc/apimiddleware/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ type FeeRecipientsRequestJSON struct {
type StateRootResponseJson struct {
Data *StateRootResponse_StateRootJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type StateRootResponse_StateRootJson struct {
Expand All @@ -47,11 +48,13 @@ type StateRootResponse_StateRootJson struct {
type StateForkResponseJson struct {
Data *ForkJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type StateFinalityCheckpointResponseJson struct {
Data *StateFinalityCheckpointResponse_StateFinalityCheckpointJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type StateFinalityCheckpointResponse_StateFinalityCheckpointJson struct {
Expand All @@ -63,33 +66,39 @@ type StateFinalityCheckpointResponse_StateFinalityCheckpointJson struct {
type StateValidatorsResponseJson struct {
Data []*ValidatorContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type StateValidatorResponseJson struct {
Data *ValidatorContainerJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type ValidatorBalancesResponseJson struct {
Data []*ValidatorBalanceJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type StateCommitteesResponseJson struct {
Data []*CommitteeJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type SyncCommitteesResponseJson struct {
Data *SyncCommitteeValidatorsJson `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type RandaoResponseJson struct {
Data *struct {
Randao string `json:"randao" hex:"true"`
} `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type BlockHeadersResponseJson struct {
Expand Down Expand Up @@ -201,6 +210,7 @@ type BeaconStateV2ResponseJson struct {
Version string `json:"version" enum:"true"`
Data *BeaconStateContainerV2Json `json:"data"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
}

type ForkChoiceHeadsResponseJson struct {
Expand Down
25 changes: 25 additions & 0 deletions beacon-chain/rpc/eth/beacon/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,18 @@ func (bs *Server) GetStateRoot(ctx context.Context, req *ethpb.StateRequest) (*e
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
blockRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not calculate root of latest block header")
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)

return &ethpb.StateRootResponse{
Data: &ethpb.StateRootResponse_StateRoot{
Root: stateRoot,
},
ExecutionOptimistic: isOptimistic,
Finalized: isFinalized,
}, nil
}

Expand All @@ -98,6 +104,11 @@ func (bs *Server) GetStateFork(ctx context.Context, req *ethpb.StateRequest) (*e
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
blockRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not calculate root of latest block header")
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)

return &ethpb.StateForkResponse{
Data: &ethpb.Fork{
Expand All @@ -106,6 +117,7 @@ func (bs *Server) GetStateFork(ctx context.Context, req *ethpb.StateRequest) (*e
Epoch: fork.Epoch,
},
ExecutionOptimistic: isOptimistic,
Finalized: isFinalized,
}, nil
}

Expand All @@ -123,6 +135,11 @@ func (bs *Server) GetFinalityCheckpoints(ctx context.Context, req *ethpb.StateRe
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}
blockRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not calculate root of latest block header")
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)

return &ethpb.StateFinalityCheckpointResponse{
Data: &ethpb.StateFinalityCheckpointResponse_StateFinalityCheckpoint{
Expand All @@ -131,6 +148,7 @@ func (bs *Server) GetFinalityCheckpoints(ctx context.Context, req *ethpb.StateRe
Finalized: checkpoint(st.FinalizedCheckpoint()),
},
ExecutionOptimistic: isOptimistic,
Finalized: isFinalized,
}, nil
}

Expand Down Expand Up @@ -173,9 +191,16 @@ func (bs *Server) GetRandao(ctx context.Context, req *eth2.RandaoRequest) (*eth2
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}

blockRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not calculate root of latest block header")
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)

return &eth2.RandaoResponse{
Data: &eth2.RandaoResponse_Randao{Randao: randao},
ExecutionOptimistic: isOptimistic,
Finalized: isFinalized,
}, nil
}

Expand Down
140 changes: 140 additions & 0 deletions beacon-chain/rpc/eth/beacon/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func TestGetStateRoot(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}

Expand Down Expand Up @@ -116,6 +117,7 @@ func TestGetStateRoot(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetStateRoot(context.Background(), &eth.StateRequest{
Expand All @@ -125,6 +127,40 @@ func TestGetStateRoot(t *testing.T) {
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.ExecutionOptimistic)
})

t.Run("finalized", func(t *testing.T) {
parentRoot := [32]byte{'a'}
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
root, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))

headerRoot, err := fakeState.LatestBlockHeader().HashTreeRoot()
require.NoError(t, err)
chainService := &chainMock.ChainService{
FinalizedRoots: map[[32]byte]bool{
headerRoot: true,
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
BeaconStateRoot: stateRoot[:],
BeaconState: fakeState,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetStateRoot(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.Finalized)
})
}

func TestGetStateFork(t *testing.T) {
Expand All @@ -148,6 +184,7 @@ func TestGetStateFork(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}

Expand Down Expand Up @@ -177,6 +214,7 @@ func TestGetStateFork(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetStateFork(context.Background(), &eth.StateRequest{
Expand All @@ -186,6 +224,39 @@ func TestGetStateFork(t *testing.T) {
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.ExecutionOptimistic)
})

t.Run("finalized", func(t *testing.T) {
parentRoot := [32]byte{'a'}
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
root, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))

headerRoot, err := fakeState.LatestBlockHeader().HashTreeRoot()
require.NoError(t, err)
chainService := &chainMock.ChainService{
FinalizedRoots: map[[32]byte]bool{
headerRoot: true,
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
BeaconState: fakeState,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetStateFork(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.Finalized)
})
}

func TestGetFinalityCheckpoints(t *testing.T) {
Expand Down Expand Up @@ -216,6 +287,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}

Expand Down Expand Up @@ -247,6 +319,7 @@ func TestGetFinalityCheckpoints(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetFinalityCheckpoints(context.Background(), &eth.StateRequest{
Expand All @@ -256,6 +329,39 @@ func TestGetFinalityCheckpoints(t *testing.T) {
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.ExecutionOptimistic)
})

t.Run("finalized", func(t *testing.T) {
parentRoot := [32]byte{'a'}
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
root, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))

headerRoot, err := fakeState.LatestBlockHeader().HashTreeRoot()
require.NoError(t, err)
chainService := &chainMock.ChainService{
FinalizedRoots: map[[32]byte]bool{
headerRoot: true,
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
BeaconState: fakeState,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetFinalityCheckpoints(context.Background(), &eth.StateRequest{
StateId: make([]byte, 0),
})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.Finalized)
})
}

func TestGetRandao(t *testing.T) {
Expand Down Expand Up @@ -287,6 +393,7 @@ func TestGetRandao(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}

Expand Down Expand Up @@ -339,6 +446,7 @@ func TestGetRandao(t *testing.T) {
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetRandao(context.Background(), &eth2.RandaoRequest{
Expand All @@ -348,4 +456,36 @@ func TestGetRandao(t *testing.T) {
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.ExecutionOptimistic)
})
t.Run("finalized", func(t *testing.T) {
parentRoot := [32]byte{'a'}
blk := util.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
root, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
util.SaveBlock(t, ctx, db, blk)
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))

headerRoot, err := headSt.LatestBlockHeader().HashTreeRoot()
require.NoError(t, err)
chainService := &chainMock.ChainService{
FinalizedRoots: map[[32]byte]bool{
headerRoot: true,
},
}
server := &Server{
StateFetcher: &testutil.MockFetcher{
BeaconState: st,
},
HeadFetcher: chainService,
OptimisticModeFetcher: chainService,
FinalizationFetcher: chainService,
BeaconDB: db,
}
resp, err := server.GetRandao(context.Background(), &eth2.RandaoRequest{
StateId: make([]byte, 0),
})
require.NoError(t, err)
assert.NotNil(t, resp)
assert.DeepEqual(t, true, resp.Finalized)
})
}
7 changes: 7 additions & 0 deletions beacon-chain/rpc/eth/beacon/sync_committee.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,19 @@ func (bs *Server) ListSyncCommittees(ctx context.Context, req *ethpbv2.StateSync
return nil, status.Errorf(codes.Internal, "Could not check if slot's block is optimistic: %v", err)
}

blockRoot, err := st.LatestBlockHeader().HashTreeRoot()
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not calculate root of latest block header")
}
isFinalized := bs.FinalizationFetcher.IsFinalized(ctx, blockRoot)

return &ethpbv2.StateSyncCommitteesResponse{
Data: &ethpbv2.SyncCommitteeValidators{
Validators: committeeIndices,
ValidatorAggregates: subcommittees,
},
ExecutionOptimistic: isOptimistic,
Finalized: isFinalized,
}, nil
}

Expand Down
Loading

0 comments on commit b10e59a

Please sign in to comment.