mirror of
https://github.com/tendermint/tendermint.git
synced 2025-12-23 06:15:19 +00:00
[block#LastResultsHash] add Events + GasWanted/Used (#4845)
Closes #1007
This commit is contained in:
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
0
scripts/protocgen.sh
Normal file → Executable file
0
scripts/protocgen.sh
Normal file → Executable file
@@ -452,7 +452,7 @@ func updateState(
|
||||
LastHeightValidatorsChanged: lastHeightValsChanged,
|
||||
ConsensusParams: nextParams,
|
||||
LastHeightConsensusParamsChanged: lastHeightParamsChanged,
|
||||
LastResultsHash: ABCIResponsesResultsHash(*abciResponses),
|
||||
LastResultsHash: ABCIResponsesResultsHash(abciResponses),
|
||||
AppHash: nil,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user