Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add finalized flag to API responses #11947

Merged
merged 7 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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