From a8d86003085d88a6a78bb4f963298ef25b6acbd3 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 12 Jun 2020 12:49:14 +0400 Subject: [PATCH] [block#LastResultsHash] add Events + GasWanted/Used (#4845) Closes #1007 --- CHANGELOG_PENDING.md | 7 ++-- proto/types/validator.pb.go | 4 +-- scripts/protocgen.sh | 0 state/execution.go | 2 +- state/helpers_test.go | 9 ++++-- state/state_test.go | 56 ++++++++++++++++++++++---------- state/store.go | 44 ++++++++++++++++++++----- state/store_test.go | 23 +++++++++++++ types/results.go | 64 +++++++++++++------------------------ types/results_test.go | 45 ++++++++++++-------------- 10 files changed, 155 insertions(+), 99 deletions(-) mode change 100644 => 100755 scripts/protocgen.sh diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index aba94092b..eba36075e 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -65,6 +65,10 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - [crypto] [\#4721](https://github.com/tendermint/tendermint/pull/4721) Remove `SimpleHashFromMap()` and `SimpleProofsFromMap()` (@erikgrinaker) - [types] \#4798 Simplify `VerifyCommitTrusting` func + remove extra validation (@melekes) - [libs] \#4831 Remove `Bech32` pkg from Tendermint. This pkg now lives in the [cosmos-sdk](https://github.com/cosmos/cosmos-sdk/tree/4173ea5ebad906dd9b45325bed69b9c655504867/types/bech32) + - [rpc/client] \#4947 `Validators`, `TxSearch` `page`/`per_page` params become pointers (@melekes) + `UnconfirmedTxs` `limit` param is a pointer + - [types] \#4845 Remove `ABCIResult` + - Blockchain Protocol - [types] [\#4792](https://github.com/tendermint/tendermint/pull/4792) Sort validators by voting power to enable faster commit verification (@melekes) @@ -72,8 +76,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi Add `max_num` to consensus evidence parameters (default: 50 items). - [mempool] \#4940 Migrate mempool from amino binary encoding to Protobuf - [statesync] \#4943 Migrate statesync reactor from amino binary encoding to Protobuf - - [rpc/client] \#4947 `Validators`, `TxSearch` `page`/`per_page` params become pointers (@melekes) - `UnconfirmedTxs` `limit` param is a pointer + - [state] \#4845 Include BeginBlock#Events, EndBlock#Events, DeliverTx#Events, GasWanted and GasUsed into `LastResultsHash` (@melekes) ### FEATURES: diff --git a/proto/types/validator.pb.go b/proto/types/validator.pb.go index b39aee6bd..8a3dac774 100644 --- a/proto/types/validator.pb.go +++ b/proto/types/validator.pb.go @@ -162,9 +162,7 @@ func init() { } func init() { proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) } -func init() { - golang_proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) -} +func init() { golang_proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) } var fileDescriptor_2e7c6b38c20e5406 = []byte{ // 358 bytes of a gzipped FileDescriptorProto diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh old mode 100644 new mode 100755 diff --git a/state/execution.go b/state/execution.go index 739855675..36e901202 100644 --- a/state/execution.go +++ b/state/execution.go @@ -452,7 +452,7 @@ func updateState( LastHeightValidatorsChanged: lastHeightValsChanged, ConsensusParams: nextParams, LastHeightConsensusParamsChanged: lastHeightParamsChanged, - LastResultsHash: ABCIResponsesResultsHash(*abciResponses), + LastResultsHash: ABCIResponsesResultsHash(abciResponses), AppHash: nil, }, nil } diff --git a/state/helpers_test.go b/state/helpers_test.go index bc7ce603e..9c3bfc88c 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -172,7 +172,8 @@ func makeHeaderPartsResponsesValPubKeyChange( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } // If the pubkey is new, remove the old and add the new. _, val := state.NextValidators.GetByIndex(0) @@ -195,7 +196,8 @@ func makeHeaderPartsResponsesValPowerChange( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } // If the pubkey is new, remove the old and add the new. @@ -218,7 +220,8 @@ func makeHeaderPartsResponsesParams( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, } return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses } diff --git a/state/state_test.go b/state/state_test.go index 4cae6f97b..3db2f37ed 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -124,7 +124,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { // Height is implied to equal index+2, // as block 1 is created from genesis. added []*abci.ResponseDeliverTx - expected types.ABCIResults + expected []*abci.ResponseDeliverTx }{ 0: { nil, @@ -134,7 +134,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { []*abci.ResponseDeliverTx{ {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, }, - types.ABCIResults{ + []*abci.ResponseDeliverTx{ {Code: 32, Data: []byte("Hello")}, }}, 2: { @@ -148,9 +148,12 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { }, }, }, - types.ABCIResults{ + []*abci.ResponseDeliverTx{ {Code: 383, Data: nil}, - {Code: 0, Data: []byte("Gotcha!")}, + {Code: 0, Data: []byte("Gotcha!"), Events: []abci.Event{ + {Type: "type1", Attributes: []abci.EventAttribute{{Key: []byte("a"), Value: []byte("1")}}}, + {Type: "type2", Attributes: []abci.EventAttribute{{Key: []byte("build"), Value: []byte("stuff")}}}, + }}, }}, 3: { nil, @@ -173,6 +176,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { for i, tc := range cases { h := int64(i + 1) // last block height, one below what we save responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, DeliverTxs: tc.added, EndBlock: &abci.ResponseEndBlock{}, } @@ -183,8 +187,15 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { for i, tc := range cases { h := int64(i + 1) res, err := sm.LoadABCIResponses(stateDB, h) - assert.NoError(err, "%d", i) - assert.Equal(tc.expected.Hash(), sm.ABCIResponsesResultsHash(*res), "%d", i) + if assert.NoError(err, "%d", i) { + t.Log(res) + responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, + DeliverTxs: tc.expected, + EndBlock: &abci.ResponseEndBlock{}, + } + assert.Equal(sm.ABCIResponsesResultsHash(responses), sm.ABCIResponsesResultsHash(res), "%d", i) + } } } @@ -420,7 +431,8 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { block := makeBlock(state, state.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -534,7 +546,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -636,7 +649,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // -> proposers should alternate: oldState := updatedState3 abciResponses = &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -651,7 +665,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { for i := 0; i < 1000; i++ { // no validator updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -708,7 +723,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 10; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -739,7 +755,8 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) assert.NoError(t, err) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, } block := makeBlock(oldState, oldState.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -750,7 +767,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 200; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -785,7 +803,8 @@ func TestLargeGenesisValidator(t *testing.T) { assert.NoError(t, err) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, } block := makeBlock(oldState, oldState.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -799,7 +818,8 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) removeGenesisVal := abci.ValidatorUpdate{PubKey: gp, Power: 0} abciResponses = &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, } block = makeBlock(oldState, oldState.LastBlockHeight+1) blockID = types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -817,7 +837,8 @@ func TestLargeGenesisValidator(t *testing.T) { isProposerUnchanged := true for isProposerUnchanged { abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -840,7 +861,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 100; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) diff --git a/state/store.go b/state/store.go index c51393a7a..16517317b 100644 --- a/state/store.go +++ b/state/store.go @@ -7,6 +7,7 @@ import ( dbm "github.com/tendermint/tm-db" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" tmmath "github.com/tendermint/tendermint/libs/math" tmos "github.com/tendermint/tendermint/libs/os" tmstate "github.com/tendermint/tendermint/proto/state" @@ -138,8 +139,6 @@ func BootstrapState(db dbm.DB, state State) error { return db.SetSync(stateKey, state.Bytes()) } -//------------------------------------------------------------------------ - // PruneStates deletes states between the given heights (including from, excluding to). It is not // guaranteed to delete all states, since the last checkpointed state and states being pointed to by // e.g. `LastHeightChanged` must remain. The state at to must also exist. @@ -253,15 +252,44 @@ func PruneStates(db dbm.DB, from int64, to int64) error { return nil } -// ABCIResponsesResultsHash returns the merkle hash of the deliverTxs within ABCIResponses -func ABCIResponsesResultsHash(ar tmstate.ABCIResponses) []byte { +//------------------------------------------------------------------------ + +// ABCIResponsesResultsHash returns the root hash of a Merkle tree with 3 leafs: +// 1) proto encoded ResponseBeginBlock.Events +// 2) root hash of a Merkle tree of ResponseDeliverTx responses (see ABCIResults.Hash) +// 3) proto encoded ResponseEndBlock.Events +// +// See merkle.SimpleHashFromByteSlices +func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte { + // proto-encode BeginBlock events. + bbeBytes, err := proto.Marshal(&abci.ResponseBeginBlock{ + Events: ar.BeginBlock.Events, + }) + if err != nil { + panic(err) + } + + // Build a Merkle tree of proto-encoded DeliverTx results and get a hash. results := types.NewResults(ar.DeliverTxs) - return results.Hash() + + // proto-encode EndBlock events. + ebeBytes, err := proto.Marshal(&abci.ResponseEndBlock{ + Events: ar.EndBlock.Events, + }) + if err != nil { + panic(err) + } + + // Build a Merkle tree out of the above 3 binary slices. + return merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes}) } -// LoadABCIResponses loads the ABCIResponses for the given height from the database. -// This is useful for recovering from crashes where we called app.Commit and before we called -// s.Save(). It can also be used to produce Merkle proofs of the result of txs. +// LoadABCIResponses loads the ABCIResponses for the given height from the +// database. If not found, ErrNoABCIResponsesForHeight is returned. +// +// This is useful for recovering from crashes where we called app.Commit and +// before we called s.Save(). It can also be used to produce Merkle proofs of +// the result of txs. func LoadABCIResponses(db dbm.DB, height int64) (*tmstate.ABCIResponses, error) { buf, err := db.Get(calcABCIResponsesKey(height)) if err != nil { diff --git a/state/store_test.go b/state/store_test.go index 2d8e0067b..1086220c7 100644 --- a/state/store_test.go +++ b/state/store_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -14,6 +15,7 @@ import ( cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/merkle" tmrand "github.com/tendermint/tendermint/libs/rand" tmstate "github.com/tendermint/tendermint/proto/state" tmproto "github.com/tendermint/tendermint/proto/types" @@ -187,6 +189,27 @@ func TestPruneStates(t *testing.T) { } } +func TestABCIResponsesResultsHash(t *testing.T) { + responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, + DeliverTxs: []*abci.ResponseDeliverTx{ + {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, + }, + EndBlock: &abci.ResponseEndBlock{}, + } + + root := sm.ABCIResponsesResultsHash(responses) + + bbeBytes, _ := proto.Marshal(responses.BeginBlock) + results := types.NewResults(responses.DeliverTxs) + ebeBytes, _ := proto.Marshal(responses.EndBlock) + + root2, proofs := merkle.ProofsFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes}) + + assert.Equal(t, root2, root) + assert.NoError(t, proofs[1].Verify(root, results.Hash())) +} + func sliceToMap(s []int64) map[int64]bool { m := make(map[int64]bool, len(s)) for _, i := range s { diff --git a/types/results.go b/types/results.go index 05937d550..0f41fab3c 100644 --- a/types/results.go +++ b/types/results.go @@ -3,57 +3,23 @@ package types import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" - "github.com/tendermint/tendermint/libs/bytes" ) -//----------------------------------------------------------------------------- +// ABCIResults wraps the deliver tx results to return a proof. +type ABCIResults []*abci.ResponseDeliverTx -// ABCIResult is the deterministic component of a ResponseDeliverTx. -// TODO: add tags and other fields -// https://github.com/tendermint/tendermint/issues/1007 -type ABCIResult struct { - Code uint32 `json:"code"` - Data bytes.HexBytes `json:"data"` -} - -// Bytes returns the amino encoded ABCIResult -func (a ABCIResult) Bytes() []byte { - return cdcEncode(a) -} - -// ABCIResults wraps the deliver tx results to return a proof -type ABCIResults []ABCIResult - -// NewResults creates ABCIResults from the list of ResponseDeliverTx. +// NewResults strips non-deterministic fields from ResponseDeliverTx responses +// and returns ABCIResults. func NewResults(responses []*abci.ResponseDeliverTx) ABCIResults { res := make(ABCIResults, len(responses)) for i, d := range responses { - res[i] = NewResultFromResponse(d) + res[i] = deterministicResponseDeliverTx(d) } return res } -// NewResultFromResponse creates ABCIResult from ResponseDeliverTx. -func NewResultFromResponse(response *abci.ResponseDeliverTx) ABCIResult { - return ABCIResult{ - Code: response.Code, - Data: response.Data, - } -} - -// Bytes serializes the ABCIResponse using amino -func (a ABCIResults) Bytes() []byte { - bz, err := cdc.MarshalBinaryLengthPrefixed(a) - if err != nil { - panic(err) - } - return bz -} - -// Hash returns a merkle hash of all results +// Hash returns a merkle hash of all results. func (a ABCIResults) Hash() []byte { - // NOTE: we copy the impl of the merkle tree for txs - - // we should be consistent and either do it for both or not. return merkle.HashFromByteSlices(a.toByteSlices()) } @@ -67,7 +33,23 @@ func (a ABCIResults) toByteSlices() [][]byte { l := len(a) bzs := make([][]byte, l) for i := 0; i < l; i++ { - bzs[i] = a[i].Bytes() + bz, err := a[i].Marshal() + if err != nil { + panic(err) + } + bzs[i] = bz } return bzs } + +// deterministicResponseDeliverTx strips non-deterministic fields from +// ResponseDeliverTx and returns another ResponseDeliverTx. +func deterministicResponseDeliverTx(response *abci.ResponseDeliverTx) *abci.ResponseDeliverTx { + return &abci.ResponseDeliverTx{ + Code: response.Code, + Data: response.Data, + GasWanted: response.GasWanted, + GasUsed: response.GasUsed, + Events: response.Events, + } +} diff --git a/types/results_test.go b/types/results_test.go index 9ecfe35ca..5b1be3466 100644 --- a/types/results_test.go +++ b/types/results_test.go @@ -10,26 +10,31 @@ import ( ) func TestABCIResults(t *testing.T) { - a := ABCIResult{Code: 0, Data: nil} - b := ABCIResult{Code: 0, Data: []byte{}} - c := ABCIResult{Code: 0, Data: []byte("one")} - d := ABCIResult{Code: 14, Data: nil} - e := ABCIResult{Code: 14, Data: []byte("foo")} - f := ABCIResult{Code: 14, Data: []byte("bar")} + a := &abci.ResponseDeliverTx{Code: 0, Data: nil} + b := &abci.ResponseDeliverTx{Code: 0, Data: []byte{}} + c := &abci.ResponseDeliverTx{Code: 0, Data: []byte("one")} + d := &abci.ResponseDeliverTx{Code: 14, Data: nil} + e := &abci.ResponseDeliverTx{Code: 14, Data: []byte("foo")} + f := &abci.ResponseDeliverTx{Code: 14, Data: []byte("bar")} // Nil and []byte{} should produce the same bytes - require.Equal(t, a.Bytes(), a.Bytes()) - require.Equal(t, b.Bytes(), b.Bytes()) - require.Equal(t, a.Bytes(), b.Bytes()) + bzA, err := a.Marshal() + require.NoError(t, err) + bzB, err := b.Marshal() + require.NoError(t, err) + + require.Equal(t, bzA, bzB) // a and b should be the same, don't go in results. results := ABCIResults{a, c, d, e, f} // Make sure each result serializes differently - var last []byte - assert.Equal(t, last, a.Bytes()) // first one is empty + last := []byte{} + assert.Equal(t, last, bzA) // first one is empty for i, res := range results[1:] { - bz := res.Bytes() + bz, err := res.Marshal() + require.NoError(t, err) + assert.NotEqual(t, last, bz, "%d", i) last = bz } @@ -39,19 +44,11 @@ func TestABCIResults(t *testing.T) { assert.NotEmpty(t, root) for i, res := range results { + bz, err := res.Marshal() + require.NoError(t, err) + proof := results.ProveResult(i) - valid := proof.Verify(root, res.Bytes()) + valid := proof.Verify(root, bz) assert.NoError(t, valid, "%d", i) } } - -func TestABCIResultsBytes(t *testing.T) { - results := NewResults([]*abci.ResponseDeliverTx{ - {Code: 0, Data: []byte{}}, - {Code: 0, Data: []byte("one")}, - {Code: 14, Data: nil}, - {Code: 14, Data: []byte("foo")}, - {Code: 14, Data: []byte("bar")}, - }) - assert.NotNil(t, results.Bytes()) -}