From 48d3f30cccc088629ef914b330bf83334324311b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Thu, 27 Jan 2022 20:28:03 +0100 Subject: [PATCH] feat: implement BlockResults RPC function (#263) * support saving and loading ABCIResponses in Store * impelement BlockResults RPC --- CHANGELOG-PENDING.md | 9 ++++---- rpc/client/client.go | 21 +++++++++++++++++-- store/store.go | 38 +++++++++++++++++++++++++++++----- store/store_test.go | 49 ++++++++++++++++++++++++++++++++++++++++++-- store/types.go | 8 ++++++++ 5 files changed, 112 insertions(+), 13 deletions(-) diff --git a/CHANGELOG-PENDING.md b/CHANGELOG-PENDING.md index 1aaa86c19..33f4916c5 100644 --- a/CHANGELOG-PENDING.md +++ b/CHANGELOG-PENDING.md @@ -11,14 +11,15 @@ Month, DD, YYYY ### FEATURES - [indexer] [Implement block and transaction indexing, enable TxSearch RPC endpoint #202](https://github.com/celestiaorg/optimint/pull/202) [@mattdf](https://github.com/mattdf) -- [rpc] [Tendermint URI RPC #224](https://github.com/celestiaorg/optimint/pull/224) [@tzdybal](https://github.com/tzdybal/) +- [rpc] [Tendermint URI RPC #224](https://github.com/celestiaorg/optimint/pull/224) [@tzdybal](https://github.com/tzdybal/) ### IMPROVEMENTS -- [ci] [Add more linters #219](https://github.com/celestiaorg/optimint/pull/219) [@tzdybal](https://github.com/tzdybal/) +- [ci] [Add more linters #219](https://github.com/celestiaorg/optimint/pull/219) [@tzdybal](https://github.com/tzdybal/) - [deps] [Update dependencies: grpc, cors, cobra, viper, tm-db #245](https://github.com/celestiaorg/optimint/pull/245) [@tzdybal](https://github.com/tzdybal/) -- [rpc] [Implement NumUnconfirmedTxs #255](https://github.com/celestiaorg/optimint/pull/255) [@tzdybal](https://github.com/tzdybal/) -- [rpc] [Implement BlockByHash #256](https://github.com/celestiaorg/optimint/pull/256) [@mauriceLC92](https://github.com/mauriceLC92) +- [rpc] [Implement NumUnconfirmedTxs #255](https://github.com/celestiaorg/optimint/pull/255) [@tzdybal](https://github.com/tzdybal/) +- [rpc] [Implement BlockByHash #256](https://github.com/celestiaorg/optimint/pull/256) [@mauriceLC92](https://github.com/mauriceLC92) +- [rpc] [Implement BlockResults #263](https://github.com/celestiaorg/optimint/pull/263) [@tzdybal](https://github.com/tzdybal/) ### BUG FIXES diff --git a/rpc/client/client.go b/rpc/client/client.go index 0fc128af1..63ad030fd 100644 --- a/rpc/client/client.go +++ b/rpc/client/client.go @@ -365,8 +365,25 @@ func (c *Client) BlockByHash(ctx context.Context, hash []byte) (*ctypes.ResultBl } func (c *Client) BlockResults(ctx context.Context, height *int64) (*ctypes.ResultBlockResults, error) { - // needs block store - panic("BlockResults - not implemented!") + var h uint64 + if height == nil { + h = c.node.Store.Height() + } else { + h = uint64(*height) + } + resp, err := c.node.Store.LoadBlockResponses(h) + if err != nil { + return nil, err + } + + return &ctypes.ResultBlockResults{ + Height: int64(h), + TxsResults: resp.DeliverTxs, + BeginBlockEvents: resp.BeginBlock.Events, + EndBlockEvents: resp.EndBlock.Events, + ValidatorUpdates: resp.EndBlock.ValidatorUpdates, + ConsensusParamUpdates: resp.EndBlock.ConsensusParamUpdates, + }, nil } func (c *Client) Commit(ctx context.Context, height *int64) (*ctypes.ResultCommit, error) { diff --git a/store/store.go b/store/store.go index dd9fa3066..65a341bd7 100644 --- a/store/store.go +++ b/store/store.go @@ -6,6 +6,7 @@ import ( "errors" "sync" + tmstate "github.com/tendermint/tendermint/proto/tendermint/state" "go.uber.org/multierr" "github.com/celestiaorg/optimint/state" @@ -13,10 +14,11 @@ import ( ) var ( - blockPrefix = [1]byte{1} - indexPrefix = [1]byte{2} - commitPrefix = [1]byte{3} - statePreffix = [1]byte{4} + blockPrefix = [1]byte{1} + indexPrefix = [1]byte{2} + commitPrefix = [1]byte{3} + statePrefix = [1]byte{4} + responsesPrefix = [1]byte{5} ) // DefaultStore is a default store implmementation. @@ -109,6 +111,26 @@ func (s *DefaultStore) LoadBlockByHash(hash [32]byte) (*types.Block, error) { return block, err } +// SaveBlockResponses saves block responses (events, tx responses, validator set updates, etc) in Store. +func (s *DefaultStore) SaveBlockResponses(height uint64, responses *tmstate.ABCIResponses) error { + data, err := responses.Marshal() + if err != nil { + return err + } + return s.db.Set(getResponsesKey(height), data) +} + +// LoadBlockResponses returns block results at given height, or error if it's not found in Store. +func (s *DefaultStore) LoadBlockResponses(height uint64) (*tmstate.ABCIResponses, error) { + data, err := s.db.Get(getResponsesKey(height)) + if err != nil { + return nil, err + } + var responses tmstate.ABCIResponses + err = responses.Unmarshal(data) + return &responses, err +} + // LoadCommit returns commit for a block at given height, or error if it's not found in Store. func (s *DefaultStore) LoadCommit(height uint64) (*types.Commit, error) { hash, err := s.loadHashFromIndex(height) @@ -184,5 +206,11 @@ func getIndexKey(height uint64) []byte { } func getStateKey() []byte { - return statePreffix[:] + return statePrefix[:] +} + +func getResponsesKey(height uint64) []byte { + buf := make([]byte, 8) + binary.BigEndian.PutUint64(buf, height) + return append(responsesPrefix[:], buf[:]...) } diff --git a/store/store_test.go b/store/store_test.go index 1d0352b3f..399af5e3c 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -5,11 +5,13 @@ import ( "os" "testing" + abcitypes "github.com/tendermint/tendermint/abci/types" + tmstate "github.com/tendermint/tendermint/proto/tendermint/state" + "github.com/celestiaorg/optimint/state" + "github.com/celestiaorg/optimint/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/celestiaorg/optimint/types" ) func TestStoreHeight(t *testing.T) { @@ -134,6 +136,49 @@ func TestRestart(t *testing.T) { assert.Equal(expectedHeight, s2.Height()) } +func TestBlockResponses(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + kv := NewDefaultInMemoryKVStore() + s := New(kv) + + expected := &tmstate.ABCIResponses{ + BeginBlock: &abcitypes.ResponseBeginBlock{ + Events: []abcitypes.Event{{ + Type: "test", + Attributes: []abcitypes.EventAttribute{{ + Key: []byte("foo"), + Value: []byte("bar"), + Index: false, + }}, + }}, + }, + DeliverTxs: nil, + EndBlock: &abcitypes.ResponseEndBlock{ + ValidatorUpdates: nil, + ConsensusParamUpdates: &abcitypes.ConsensusParams{ + Block: &abcitypes.BlockParams{ + MaxBytes: 12345, + MaxGas: 678909876, + }, + }, + }, + } + + err := s.SaveBlockResponses(1, expected) + assert.NoError(err) + + resp, err := s.LoadBlockResponses(123) + assert.Error(err) + assert.Nil(resp) + + resp, err = s.LoadBlockResponses(1) + assert.NoError(err) + assert.NotNil(resp) + assert.Equal(expected, resp) +} + func getRandomBlock(height uint64, nTxs int) *types.Block { block := &types.Block{ Header: types.Header{ diff --git a/store/types.go b/store/types.go index b1d9c5f1a..cf14bbdb8 100644 --- a/store/types.go +++ b/store/types.go @@ -1,6 +1,8 @@ package store import ( + tmstate "github.com/tendermint/tendermint/proto/tendermint/state" + "github.com/celestiaorg/optimint/state" "github.com/celestiaorg/optimint/types" ) @@ -18,6 +20,12 @@ type Store interface { // LoadBlockByHash returns block with given block header hash, or error if it's not found in Store. LoadBlockByHash(hash [32]byte) (*types.Block, error) + // SaveBlockResponses saves block responses (events, tx responses, validator set updates, etc) in Store. + SaveBlockResponses(height uint64, responses *tmstate.ABCIResponses) error + + // LoadBlockResponses returns block results at given height, or error if it's not found in Store. + LoadBlockResponses(height uint64) (*tmstate.ABCIResponses, error) + // LoadCommit returns commit for a block at given height, or error if it's not found in Store. LoadCommit(height uint64) (*types.Commit, error) // LoadCommitByHash returns commit for a block with given block header hash, or error if it's not found in Store.