Skip to content

Commit 5124966

Browse files
authored
Merge pull request #6180 from oasisprotocol/peternose/feature/block-results
go/consensus/api: Add method GetBlockResults
2 parents 9ceffc9 + 246a058 commit 5124966

File tree

28 files changed

+790
-636
lines changed

28 files changed

+790
-636
lines changed

.changelog/6180.feature.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
go/consensus/api: Add method GetBlockResults
2+
3+
A new method has been added to the consensus backend that returns block
4+
results for a specified height.

go/consensus/api/api.go

+14
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ type Backend interface {
135135
// GetBlock returns a consensus block at a specific height.
136136
GetBlock(ctx context.Context, height int64) (*Block, error)
137137

138+
// GetBlockResults returns the consensus block results at a specific height.
139+
GetBlockResults(ctx context.Context, height int64) (*BlockResults, error)
140+
138141
// GetLightBlock returns a light version of the consensus layer block that can be used for light
139142
// client verification.
140143
GetLightBlock(ctx context.Context, height int64) (*LightBlock, error)
@@ -244,6 +247,17 @@ type Block struct {
244247
Meta cbor.RawMessage `json:"meta"`
245248
}
246249

250+
// BlockResults are consensus block results.
251+
//
252+
// While some common fields are provided, most of the structure is dependent on
253+
// the actual backend implementation.
254+
type BlockResults struct {
255+
// Height contains the block height.
256+
Height int64 `json:"height"`
257+
// Meta contains the consensus backend specific block results metadata.
258+
Meta cbor.RawMessage `json:"meta"`
259+
}
260+
247261
// NextBlockState has the state of the next block being voted on by validators.
248262
type NextBlockState struct {
249263
Height int64 `json:"height"`

go/consensus/api/grpc.go

+37
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ var (
4141
methodGetSignerNonce = serviceName.NewMethod("GetSignerNonce", &GetSignerNonceRequest{})
4242
// methodGetBlock is the GetBlock method.
4343
methodGetBlock = serviceName.NewMethod("GetBlock", int64(0))
44+
// methodGetBlockResults is the GetBlockResults method.
45+
methodGetBlockResults = serviceName.NewMethod("GetBlockResults", int64(0))
4446
// methodGetLightBlock is the GetLightBlock method.
4547
methodGetLightBlock = serviceName.NewMethod("GetLightBlock", int64(0))
4648
// methodGetLatestHeight is the GetLatestHeight method.
@@ -114,6 +116,10 @@ var (
114116
MethodName: methodGetBlock.ShortName(),
115117
Handler: handlerGetBlock,
116118
},
119+
{
120+
MethodName: methodGetBlockResults.ShortName(),
121+
Handler: handlerGetBlockResults,
122+
},
117123
{
118124
MethodName: methodGetLightBlock.ShortName(),
119125
Handler: handlerGetLightBlock,
@@ -369,6 +375,29 @@ func handlerGetBlock(
369375
return interceptor(ctx, height, info, handler)
370376
}
371377

378+
func handlerGetBlockResults(
379+
srv any,
380+
ctx context.Context,
381+
dec func(any) error,
382+
interceptor grpc.UnaryServerInterceptor,
383+
) (any, error) {
384+
var height int64
385+
if err := dec(&height); err != nil {
386+
return nil, err
387+
}
388+
if interceptor == nil {
389+
return srv.(Services).Core().GetBlockResults(ctx, height)
390+
}
391+
info := &grpc.UnaryServerInfo{
392+
Server: srv,
393+
FullMethod: methodGetBlockResults.FullName(),
394+
}
395+
handler := func(ctx context.Context, req any) (any, error) {
396+
return srv.(Services).Core().GetBlockResults(ctx, req.(int64))
397+
}
398+
return interceptor(ctx, height, info, handler)
399+
}
400+
372401
func handlerGetLightBlock(
373402
srv any,
374403
ctx context.Context,
@@ -810,6 +839,14 @@ func (c *Client) GetBlock(ctx context.Context, height int64) (*Block, error) {
810839
return &rsp, nil
811840
}
812841

842+
func (c *Client) GetBlockResults(ctx context.Context, height int64) (*BlockResults, error) {
843+
var rsp BlockResults
844+
if err := c.conn.Invoke(ctx, methodGetBlockResults.FullName(), height, &rsp); err != nil {
845+
return nil, err
846+
}
847+
return &rsp, nil
848+
}
849+
813850
func (c *Client) GetLightBlock(ctx context.Context, height int64) (*LightBlock, error) {
814851
var rsp LightBlock
815852
if err := c.conn.Invoke(ctx, methodGetLightBlock.FullName(), height, &rsp); err != nil {

go/consensus/cometbft/api/api.go

+81-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
cmtquery "github.com/cometbft/cometbft/libs/pubsub/query"
1212
cmtp2p "github.com/cometbft/cometbft/p2p"
1313
cmtcrypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
14-
cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types"
14+
cmtcoretypes "github.com/cometbft/cometbft/rpc/core/types"
1515
cmttypes "github.com/cometbft/cometbft/types"
1616

1717
beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
@@ -20,7 +20,6 @@ import (
2020
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
2121
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
2222
"github.com/oasisprotocol/oasis-core/go/common/node"
23-
"github.com/oasisprotocol/oasis-core/go/common/pubsub"
2423
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
2524
"github.com/oasisprotocol/oasis-core/go/consensus/api/events"
2625
"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction"
@@ -157,8 +156,7 @@ func QueryForApp(eventApp string) cmtpubsub.Query {
157156
return cmtquery.MustParse(fmt.Sprintf("%s EXISTS", EventTypeForApp(eventApp)))
158157
}
159158

160-
// BlockMeta is the CometBFT-specific per-block metadata that is
161-
// exposed via the consensus API.
159+
// BlockMeta is the CometBFT-specific per-block metadata.
162160
type BlockMeta struct {
163161
// Header is the CometBFT block header.
164162
Header *cmttypes.Header `json:"header"`
@@ -199,20 +197,85 @@ func NewBlock(blk *cmttypes.Block) *consensus.Block {
199197
}
200198
}
201199

202-
// Backend is a CometBFT consensus backend.
203-
type Backend interface {
204-
consensus.Backend
200+
// BlockResults are CometBFT-specific consensus block results.
201+
type BlockResults struct {
202+
// Height contains the block height.
203+
Height int64 `json:"height"`
204+
// Meta contains the block results metadata.
205+
Meta *BlockResultsMeta `json:"meta"`
206+
}
207+
208+
// BlockResultsMeta is the CometBFT-specific per-block results metadata.
209+
type BlockResultsMeta struct {
210+
TxsResults []*types.ResponseDeliverTx `json:"txs_results"`
211+
BeginBlockEvents []types.Event `json:"begin_block_events"`
212+
EndBlockEvents []types.Event `json:"end_block_events"`
213+
}
214+
215+
// NewBlockResultsMeta converts consensus results into CometBFT-specific block
216+
// results metadata.
217+
func NewBlockResultsMeta(results *consensus.BlockResults) (*BlockResultsMeta, error) {
218+
var meta BlockResultsMeta
219+
if err := cbor.Unmarshal(results.Meta, &meta); err != nil {
220+
return nil, fmt.Errorf("malformed block results metadata: %w", err)
221+
}
222+
223+
return &meta, nil
224+
}
225+
226+
// NewBlockResults converts CometBFT-specific block results into consensus results.
227+
func NewBlockResults(results *cmtcoretypes.ResultBlockResults) *consensus.BlockResults {
228+
meta := BlockResultsMeta{
229+
TxsResults: results.TxsResults,
230+
BeginBlockEvents: results.BeginBlockEvents,
231+
EndBlockEvents: results.EndBlockEvents,
232+
}
233+
234+
return &consensus.BlockResults{
235+
Height: results.Height,
236+
Meta: cbor.Marshal(meta),
237+
}
238+
}
205239

206-
// GetCometBFTBlock returns the CometBFT block at the specified height.
207-
GetCometBFTBlock(ctx context.Context, height int64) (*cmttypes.Block, error)
240+
// GetBlockResults returns CometBFT-specific block results at the given height.
241+
func GetBlockResults(ctx context.Context, height int64, consensus consensus.Backend) (*BlockResults, error) {
242+
// Optimize for CometBTF-specific consensus backends.
243+
if cmt, ok := consensus.(Backend); ok {
244+
results, err := cmt.GetCometBFTBlockResults(ctx, height)
245+
if err != nil {
246+
return nil, err
247+
}
248+
return &BlockResults{
249+
Height: results.Height,
250+
Meta: &BlockResultsMeta{
251+
TxsResults: results.TxsResults,
252+
BeginBlockEvents: results.BeginBlockEvents,
253+
EndBlockEvents: results.EndBlockEvents,
254+
},
255+
}, nil
256+
257+
}
208258

259+
results, err := consensus.GetBlockResults(ctx, height)
260+
if err != nil {
261+
return nil, err
262+
}
263+
meta, err := NewBlockResultsMeta(results)
264+
if err != nil {
265+
return nil, err
266+
}
267+
268+
return &BlockResults{
269+
Height: results.Height,
270+
Meta: meta,
271+
}, nil
272+
}
273+
274+
// Backend is a CometBFT-specific consensus backend.
275+
type Backend interface {
209276
// GetCometBFTBlockResults returns the ABCI results from processing a block
210277
// at a specific height.
211-
GetCometBFTBlockResults(ctx context.Context, height int64) (*cmtrpctypes.ResultBlockResults, error)
212-
213-
// WatchCometBFTBlocks returns a stream of CometBFT blocks as they are
214-
// returned via the `EventDataNewBlock` query.
215-
WatchCometBFTBlocks() (<-chan *cmttypes.Block, *pubsub.Subscription, error)
278+
GetCometBFTBlockResults(ctx context.Context, height int64) (*cmtcoretypes.ResultBlockResults, error)
216279
}
217280

218281
// HaltHook is a function that gets called when consensus needs to halt for some reason.
@@ -297,8 +360,8 @@ type ServiceClient interface {
297360
// ServiceDescriptor returns the consensus service descriptor.
298361
ServiceDescriptor() ServiceDescriptor
299362

300-
// DeliverBlock delivers a new block.
301-
DeliverBlock(ctx context.Context, blk *cmttypes.Block) error
363+
// DeliverHeight delivers a new block height.
364+
DeliverHeight(ctx context.Context, height int64) error
302365

303366
// DeliverEvent delivers an event emitted by the consensus service.
304367
DeliverEvent(ctx context.Context, height int64, tx cmttypes.Tx, ev *types.Event) error
@@ -308,8 +371,8 @@ type ServiceClient interface {
308371
// all the delivery methods. Implementations should override them as needed.
309372
type BaseServiceClient struct{}
310373

311-
// DeliverBlock implements ServiceClient.
312-
func (bsc *BaseServiceClient) DeliverBlock(context.Context, *cmttypes.Block) error {
374+
// DeliverHeight implements ServiceClient.
375+
func (bsc *BaseServiceClient) DeliverHeight(context.Context, int64) error {
313376
return nil
314377
}
315378

go/consensus/cometbft/beacon/beacon.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
1919
"github.com/oasisprotocol/oasis-core/go/common/logging"
2020
"github.com/oasisprotocol/oasis-core/go/common/pubsub"
21+
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
2122
"github.com/oasisprotocol/oasis-core/go/consensus/api/events"
2223
tmapi "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/api"
2324
app "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/apps/beacon"
@@ -33,7 +34,7 @@ type ServiceClient struct {
3334

3435
logger *logging.Logger
3536

36-
consensus tmapi.Backend
37+
consensus consensus.Backend
3738
querier *app.QueryFactory
3839

3940
epochNotifier *pubsub.Broker
@@ -53,7 +54,7 @@ type ServiceClient struct {
5354
}
5455

5556
// New constructs a new CometBFT backed beacon service client.
56-
func New(baseEpoch beaconAPI.EpochTime, baseBlock int64, consensus tmapi.Backend, querier *app.QueryFactory) *ServiceClient {
57+
func New(baseEpoch beaconAPI.EpochTime, baseBlock int64, consensus consensus.Backend, querier *app.QueryFactory) *ServiceClient {
5758
return &ServiceClient{
5859
logger: logging.GetLogger("cometbft/beacon"),
5960
consensus: consensus,
@@ -246,12 +247,12 @@ func (sc *ServiceClient) ServiceDescriptor() tmapi.ServiceDescriptor {
246247
return tmapi.NewStaticServiceDescriptor("beacon", app.EventType, []cmtpubsub.Query{app.QueryApp})
247248
}
248249

249-
func (sc *ServiceClient) DeliverBlock(ctx context.Context, blk *cmttypes.Block) error {
250+
func (sc *ServiceClient) DeliverHeight(ctx context.Context, height int64) error {
250251
if sc.initialNotify {
251252
return nil
252253
}
253254

254-
q, err := sc.querier.QueryAt(ctx, blk.Height)
255+
q, err := sc.querier.QueryAt(ctx, height)
255256
if err != nil {
256257
return fmt.Errorf("epochtime: failed to query state: %w", err)
257258
}

go/consensus/cometbft/full/archive.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import (
2929
"github.com/oasisprotocol/oasis-core/go/consensus/cometbft/db"
3030
)
3131

32-
var _ api.Backend = (*archiveService)(nil)
32+
var _ consensusAPI.Backend = (*archiveService)(nil)
3333

3434
// ArchiveConfig contains configuration parameters for the archive node.
3535
type ArchiveConfig struct {
@@ -256,16 +256,16 @@ func (srv *archiveService) serviceClientWorker(ctx context.Context, svc api.Serv
256256
logger := srv.Logger.With("service", sd.Name())
257257
logger.Info("starting command dispatcher")
258258

259-
latestBlock, err := srv.GetCometBFTBlock(ctx, consensusAPI.HeightLatest)
259+
height, err := srv.GetLatestHeight(ctx)
260260
if err != nil {
261-
logger.Error("failed to fetch latest block",
261+
logger.Error("failed to fetch latest height",
262262
"err", err,
263263
)
264264
return
265265
}
266266

267-
if err := svc.DeliverBlock(ctx, latestBlock); err != nil {
268-
logger.Error("failed to deliver block to service client",
267+
if err := svc.DeliverHeight(ctx, height); err != nil {
268+
logger.Error("failed to deliver block height to service client",
269269
"err", err,
270270
)
271271
}

0 commit comments

Comments
 (0)