From 1d336ea221a9dbf462d0e3135f73de79de504826 Mon Sep 17 00:00:00 2001 From: William Banfield Date: Mon, 7 Mar 2022 17:20:10 -0500 Subject: [PATCH] limit use of ABCIResponses --- abci/types/types.go | 35 ++++++++++ internal/state/execution.go | 2 +- internal/state/state_test.go | 131 ++++++++++++++--------------------- internal/state/store.go | 8 --- internal/state/store_test.go | 23 ------ light/rpc/client.go | 5 +- types/results.go | 54 --------------- types/results_test.go | 54 --------------- 8 files changed, 88 insertions(+), 224 deletions(-) delete mode 100644 types/results.go delete mode 100644 types/results_test.go diff --git a/abci/types/types.go b/abci/types/types.go index a7198b633..12c21e2da 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -6,6 +6,7 @@ import ( "github.com/gogo/protobuf/jsonpb" + "github.com/tendermint/tendermint/crypto/merkle" types "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -167,3 +168,37 @@ func RespondVerifyVoteExtension(ok bool) ResponseVerifyVoteExtension { Result: result, } } + +func MustHashResults(r []*ExecTxResult) []byte { + return merkle.HashFromByteSlices(mustResultsToByteSlices(r)) +} + +// ProveResult returns a merkle proof of one result from the set +func MustProveResult(r []*ExecTxResult, i int) merkle.Proof { + _, proofs := merkle.ProofsFromByteSlices(mustResultsToByteSlices(r)) + return *proofs[i] +} + +// deterministicExecTxResult strips non-deterministic fields from +// ResponseDeliverTx and returns another ResponseDeliverTx. +func deterministicExecTxResult(response *ExecTxResult) *ExecTxResult { + return &ExecTxResult{ + Code: response.Code, + Data: response.Data, + GasWanted: response.GasWanted, + GasUsed: response.GasUsed, + } +} + +func mustResultsToByteSlices(r []*ExecTxResult) [][]byte { + s := make([][]byte, len(r)) + for i, e := range r { + d := deterministicExecTxResult(e) + b, err := d.Marshal() + if err != nil { + panic(err) + } + s[i] = b + } + return s +} diff --git a/internal/state/execution.go b/internal/state/execution.go index 6daea338b..6711e865b 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -247,7 +247,7 @@ func (blockExec *BlockExecutor) ApplyBlock( } // Update the state with the block and responses. - state, err = state.Update(blockID, &block.Header, ABCIResponsesResultsHash(abciResponses), finalizeBlockResponse.ConsensusParamUpdates, validatorUpdates) + state, err = state.Update(blockID, &block.Header, abci.MustHashResults(finalizeBlockResponse.TxResults), finalizeBlockResponse.ConsensusParamUpdates, validatorUpdates) if err != nil { return state, fmt.Errorf("commit failed for application: %w", err) } diff --git a/internal/state/state_test.go b/internal/state/state_test.go index 9c2f6e3db..49575b2ad 100644 --- a/internal/state/state_test.go +++ b/internal/state/state_test.go @@ -205,14 +205,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { res, err := stateStore.LoadABCIResponses(h) if assert.NoError(t, err, "%d", i) { t.Log(res) - responses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - TxResults: tc.expected, - }, - } - sm.ABCIResponsesResultsHash(res) - sm.ABCIResponsesResultsHash(responses) - assert.Equal(t, sm.ABCIResponsesResultsHash(responses), sm.ABCIResponsesResultsHash(res), "%d", i) + assert.Equal(t, abci.MustHashResults(tc.expected), abci.MustHashResults(res.FinalizeBlock.TxResults), "%d", i) } } } @@ -278,7 +271,7 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { header, blockID, responses := makeHeaderPartsResponsesValPowerChange(t, state, power) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + state, err = state.Update(blockID, &header, abci.MustHashResults(responses.FinalizeBlock.TxResults), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) err := stateStore.Save(state) require.NoError(t, err) @@ -456,14 +449,12 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { bps, err := block.MakePartSet(testPartSize) require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err := state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err := state.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) curTotal := val1VotingPower // one increment step and one validator: 0 + power - total_power == 0 @@ -478,7 +469,7 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { updateAddVal := abci.ValidatorUpdate{PubKey: fvp, Power: val2VotingPower} validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) assert.NoError(t, err) - updatedState2, err := updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState2, err := updatedState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState2.NextValidators.Validators), 2) @@ -517,7 +508,7 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { // this will cause the diff of priorities (77) // to be larger than threshold == 2*totalVotingPower (22): - updatedState3, err := updatedState2.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState3, err := updatedState2.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState3.NextValidators.Validators), 2) @@ -575,15 +566,13 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err := state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err := state.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) // 0 + 10 (initial prio) - 10 (avg) - 10 (mostest - total) = -10 @@ -600,7 +589,7 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) assert.NoError(t, err) - updatedState2, err := updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState2, err := updatedState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState2.NextValidators.Validators), 2) @@ -640,10 +629,10 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { updatedVal2, ) - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState3, err := updatedState2.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState3, err := updatedState2.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) assert.Equal(t, updatedState3.Validators.Proposer.Address, updatedState3.NextValidators.Proposer.Address) @@ -679,15 +668,13 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // no changes in voting power and both validators have same voting power // -> proposers should alternate: oldState := updatedState3 - abciResponses = &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - oldState, err = oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + oldState, err = oldState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) expectedVal1Prio2 = 1 expectedVal2Prio2 = -1 @@ -696,15 +683,13 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { for i := 0; i < 1000; i++ { // no validator updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err := oldState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) // alternate (and cyclic priorities): assert.NotEqual( @@ -755,12 +740,10 @@ func TestLargeGenesisValidator(t *testing.T) { oldState := state for i := 0; i < 10; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) @@ -769,7 +752,7 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - updatedState, err := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err := oldState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) // no changes in voting power (ProposerPrio += VotingPower == Voting in 1st round; than shiftByAvg == 0, // than -Total == -Voting) @@ -791,10 +774,8 @@ func TestLargeGenesisValidator(t *testing.T) { firstAddedVal := abci.ValidatorUpdate{PubKey: fvp, Power: firstAddedValVotingPower} validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) assert.NoError(t, err) - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}, } block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) require.NoError(t, err) @@ -803,18 +784,16 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - updatedState, err := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err := oldState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) lastState := updatedState for i := 0; i < 200; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) block, err := statefactory.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit)) @@ -825,7 +804,7 @@ func TestLargeGenesisValidator(t *testing.T) { blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - updatedStateInner, err := lastState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedStateInner, err := lastState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) lastState = updatedStateInner } @@ -851,10 +830,8 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{addedVal}) assert.NoError(t, err) - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{addedVal}, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{addedVal}, } block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) require.NoError(t, err) @@ -862,7 +839,7 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - state, err = state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + state, err = state.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) } require.Equal(t, 10+2, len(state.NextValidators.Validators)) @@ -871,10 +848,8 @@ func TestLargeGenesisValidator(t *testing.T) { gp, err := encoding.PubKeyToProto(genesisPubKey) require.NoError(t, err) removeGenesisVal := abci.ValidatorUpdate{PubKey: gp, Power: 0} - abciResponses = &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}, } block, err = statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) @@ -884,9 +859,9 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err = state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err = state.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) // only the first added val (not the genesis val) should be left assert.Equal(t, 11, len(updatedState.NextValidators.Validators)) @@ -897,12 +872,10 @@ func TestLargeGenesisValidator(t *testing.T) { count := 0 isProposerUnchanged := true for isProposerUnchanged { - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) block, err = statefactory.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit)) require.NoError(t, err) @@ -911,7 +884,7 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - curState, err = curState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + curState, err = curState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { isProposerUnchanged = false @@ -927,12 +900,10 @@ func TestLargeGenesisValidator(t *testing.T) { proposers := make([]*types.Validator, numVals) for i := 0; i < 100; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) block, err := statefactory.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit)) @@ -943,7 +914,7 @@ func TestLargeGenesisValidator(t *testing.T) { blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} - updatedState, err = updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + updatedState, err = updatedState.Update(blockID, &block.Header, abci.MustHashResults(fb.TxResults), fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) if i > numVals { // expect proposers to cycle through after the first iteration (of numVals blocks): if proposers[i%numVals] == nil { @@ -1002,7 +973,7 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { var validatorUpdates []*types.Validator validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + state, err = state.Update(blockID, &header, abci.MustHashResults(responses.FinalizeBlock.TxResults), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) nextHeight := state.LastBlockHeight + 1 err = stateStore.Save(state) @@ -1080,7 +1051,7 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { header, blockID, responses := makeHeaderPartsResponsesParams(t, state, &cp) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + state, err = state.Update(blockID, &header, abci.MustHashResults(responses.FinalizeBlock.TxResults), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) err := stateStore.Save(state) diff --git a/internal/state/store.go b/internal/state/store.go index dbde5e0d1..d9a591f6a 100644 --- a/internal/state/store.go +++ b/internal/state/store.go @@ -396,14 +396,6 @@ func (store dbStore) reverseBatchDelete(batch dbm.Batch, start, end []byte) ([]b //------------------------------------------------------------------------ -// ABCIResponsesResultsHash returns the root hash of a Merkle tree of -// ResponseDeliverTx responses (see ABCIResults.Hash) -// -// See merkle.SimpleHashFromByteSlices -func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte { - return types.NewResults(ar.FinalizeBlock.TxResults).Hash() -} - // LoadABCIResponses loads the ABCIResponses for the given height from the // database. If not found, ErrNoABCIResponsesForHeight is returned. // diff --git a/internal/state/store_test.go b/internal/state/store_test.go index 0134d5987..59084fd10 100644 --- a/internal/state/store_test.go +++ b/internal/state/store_test.go @@ -7,7 +7,6 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -299,25 +298,3 @@ func TestPruneStates(t *testing.T) { }) } } - -func TestABCIResponsesResultsHash(t *testing.T) { - responses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - TxResults: []*abci.ExecTxResult{ - {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, - }, - }, - } - - root := sm.ABCIResponsesResultsHash(responses) - - // root should be Merkle tree root of FinalizeBlock tx responses - results := types.NewResults(responses.FinalizeBlock.TxResults) - assert.Equal(t, root, results.Hash()) - - // test we can prove first tx in FinalizeBlock - proof := results.ProveResult(0) - bz, err := results[0].Marshal() - require.NoError(t, err) - assert.NoError(t, proof.Verify(root, bz)) -} diff --git a/light/rpc/client.go b/light/rpc/client.go index 54b0a6258..81ea8957d 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -458,11 +458,8 @@ func (c *Client) BlockResults(ctx context.Context, height *int64) (*coretypes.Re return nil, err } - // Build a Merkle tree of proto-encoded FinalizeBlock tx results and get a hash. - results := types.NewResults(res.TxsResults) - // Build a Merkle tree out of the slice. - rH := merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash()}) + rH := merkle.HashFromByteSlices([][]byte{bbeBytes, abci.MustHashResults(res.TxsResults)}) // Verify block results. if !bytes.Equal(rH, trustedBlock.LastResultsHash) { diff --git a/types/results.go b/types/results.go deleted file mode 100644 index 511364000..000000000 --- a/types/results.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/merkle" -) - -// ABCIResults wraps the deliver tx results to return a proof. -type ABCIResults []*abci.ExecTxResult - -// NewResults strips non-deterministic fields from ResponseDeliverTx responses -// and returns ABCIResults. -func NewResults(responses []*abci.ExecTxResult) ABCIResults { - res := make(ABCIResults, len(responses)) - for i, d := range responses { - res[i] = deterministicExecTxResult(d) - } - return res -} - -// Hash returns a merkle hash of all results. -func (a ABCIResults) Hash() []byte { - return merkle.HashFromByteSlices(a.toByteSlices()) -} - -// ProveResult returns a merkle proof of one result from the set -func (a ABCIResults) ProveResult(i int) merkle.Proof { - _, proofs := merkle.ProofsFromByteSlices(a.toByteSlices()) - return *proofs[i] -} - -func (a ABCIResults) toByteSlices() [][]byte { - l := len(a) - bzs := make([][]byte, l) - for i := 0; i < l; i++ { - bz, err := a[i].Marshal() - if err != nil { - panic(err) - } - bzs[i] = bz - } - return bzs -} - -// deterministicExecTxResult strips non-deterministic fields from -// ResponseDeliverTx and returns another ResponseDeliverTx. -func deterministicExecTxResult(response *abci.ExecTxResult) *abci.ExecTxResult { - return &abci.ExecTxResult{ - Code: response.Code, - Data: response.Data, - GasWanted: response.GasWanted, - GasUsed: response.GasUsed, - } -} diff --git a/types/results_test.go b/types/results_test.go deleted file mode 100644 index da7eebed0..000000000 --- a/types/results_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" -) - -func TestABCIResults(t *testing.T) { - a := &abci.ExecTxResult{Code: 0, Data: nil} - b := &abci.ExecTxResult{Code: 0, Data: []byte{}} - c := &abci.ExecTxResult{Code: 0, Data: []byte("one")} - d := &abci.ExecTxResult{Code: 14, Data: nil} - e := &abci.ExecTxResult{Code: 14, Data: []byte("foo")} - f := &abci.ExecTxResult{Code: 14, Data: []byte("bar")} - - // Nil and []byte{} should produce the same 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 - last := []byte{} - assert.Equal(t, last, bzA) // first one is empty - for i, res := range results[1:] { - bz, err := res.Marshal() - require.NoError(t, err) - - assert.NotEqual(t, last, bz, "%d", i) - last = bz - } - - // Make sure that we can get a root hash from results and verify proofs. - root := results.Hash() - 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, bz) - assert.NoError(t, valid, "%d", i) - } -}