From d268e563838afc84e52eb5eb8567c067a7f11cfd Mon Sep 17 00:00:00 2001 From: Sergio Mena Date: Wed, 3 Aug 2022 17:24:24 +0200 Subject: [PATCH] Sync PrepareProposal with Spec. Main part (#9158) * ----start---- * [PARTIAL cherry-pick] ABCI Vote Extension 2 (#6885) * Cherry-picked #6567: state/types: refactor makeBlock, makeBlocks and makeTxs (#6567) * [Cherrypicked] types: remove panic from block methods (#7501) * [cherrypicked] abci++: synchronize PrepareProposal with the newest version of the spec (#8094) This change implements the logic for the PrepareProposal ABCI++ method call. The main logic for creating and issuing the PrepareProposal request lives in execution.go and is tested in a set of new tests in execution_test.go. This change also updates the mempool mock to use a mockery generated version and removes much of the plumbing for the no longer used ABCIResponses. * make proto-gen * Backported EvidenceList's method ToABCI from #7961 * make build * Fix mockery for Mempool * mockery * Backported abci Application mocks from #7961 * mockery2 * Fixed new PrepareProposal test cases in state/execution_test.go * Fixed returned errors in consensus/state.go * lint * Addressed @cmwaters' comment Co-authored-by: mconcat Co-authored-by: JayT106 Co-authored-by: Sam Kleinman Co-authored-by: William Banfield <4561443+williambanfield@users.noreply.github.com> --- abci/example/kvstore/kvstore.go | 3 +- abci/example/kvstore/persistent_kvstore.go | 53 +- abci/types/application.go | 5 +- abci/types/mocks/application.go | 224 +++ abci/types/mocks/base.go | 176 +++ abci/types/{result.go => types.go} | 0 abci/types/types.pb.go | 1521 ++++++++++++++++---- blockchain/v0/reactor.go | 10 +- blockchain/v0/reactor_test.go | 55 +- blockchain/v1/reactor.go | 8 +- blockchain/v1/reactor_test.go | 38 +- blockchain/v2/processor.go | 11 +- blockchain/v2/reactor_test.go | 62 +- consensus/byzantine_test.go | 20 +- consensus/common_test.go | 6 +- consensus/mempool_test.go | 2 +- consensus/replay_test.go | 147 +- consensus/state.go | 27 +- consensus/state_test.go | 141 +- evidence/mocks/block_store.go | 1 - evidence/pool_test.go | 31 +- mempool/mempool.go | 2 + mempool/mock/mempool.go | 43 - mempool/mocks/mempool.go | 184 +++ node/node_test.go | 12 +- proto/tendermint/abci/types.proto | 45 +- proxy/mocks/app_conn_consensus.go | 1 - proxy/mocks/app_conn_mempool.go | 1 - rpc/client/helpers.go | 2 +- rpc/core/tx.go | 13 +- state/execution.go | 71 +- state/execution_test.go | 282 +++- state/helpers_test.go | 44 +- state/mocks/evidence_pool.go | 1 - state/mocks/store.go | 1 - state/state.go | 4 +- state/state_test.go | 84 +- state/test/factory/block.go | 75 + state/txindex/mocks/tx_indexer.go | 1 - state/validation_test.go | 58 +- statesync/mocks/state_provider.go | 1 - store/store_test.go | 45 +- test/e2e/app/app.go | 3 +- test/factory/tx.go | 16 + test/maverick/consensus/state.go | 29 +- types/block.go | 10 +- types/block_test.go | 15 +- types/evidence.go | 10 + types/evidence_test.go | 5 +- types/tx.go | 223 ++- types/tx_test.go | 165 ++- types/vote_set.go | 4 + 52 files changed, 3199 insertions(+), 792 deletions(-) create mode 100644 abci/types/mocks/application.go create mode 100644 abci/types/mocks/base.go rename abci/types/{result.go => types.go} (100%) delete mode 100644 mempool/mock/mempool.go create mode 100644 mempool/mocks/mempool.go create mode 100644 state/test/factory/block.go create mode 100644 test/factory/tx.go diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index b76699097..d2b3f5d44 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -173,6 +173,5 @@ func (app *Application) Query(reqQuery types.RequestQuery) (resQuery types.Respo func (app *Application) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - return types.ResponsePrepareProposal{ - BlockData: req.BlockData} + return types.ResponsePrepareProposal{} } diff --git a/abci/example/kvstore/persistent_kvstore.go b/abci/example/kvstore/persistent_kvstore.go index 320f25502..465848f2a 100644 --- a/abci/example/kvstore/persistent_kvstore.go +++ b/abci/example/kvstore/persistent_kvstore.go @@ -76,6 +76,10 @@ func (app *PersistentKVStoreApplication) DeliverTx(req types.RequestDeliverTx) t return app.execValidatorTx(req.Tx) } + if isPrepareTx(req.Tx) { + return app.execPrepareTx(req.Tx) + } + // otherwise, update the key-value store return app.app.DeliverTx(req) } @@ -172,11 +176,7 @@ func (app *PersistentKVStoreApplication) ApplySnapshotChunk( func (app *PersistentKVStoreApplication) PrepareProposal( req types.RequestPrepareProposal) types.ResponsePrepareProposal { - if len(req.BlockData) > 1 && false { // this breaks TC: TestReactorValidatorSetChanges - req.BlockData[1] = []byte("modified tx") - } - - return types.ResponsePrepareProposal{BlockData: req.BlockData} + return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs)} } //--------------------------------------------- @@ -293,3 +293,46 @@ func (app *PersistentKVStoreApplication) updateValidator(v types.ValidatorUpdate return types.ResponseDeliverTx{Code: code.CodeTypeOK} } + +// ----------------------------- + +const PreparePrefix = "prepare" + +func isPrepareTx(tx []byte) bool { + return bytes.HasPrefix(tx, []byte(PreparePrefix)) +} + +// execPrepareTx is noop. tx data is considered as placeholder +// and is substitute at the PrepareProposal. +func (app *PersistentKVStoreApplication) execPrepareTx(tx []byte) types.ResponseDeliverTx { + // noop + return types.ResponseDeliverTx{} +} + +// substPrepareTx substitutes all the transactions prefixed with 'prepare' in the +// proposal for transactions with the prefix strips. +// It marks all of the original transactions as 'REMOVED' so that +// Tendermint will remove them from its mempool. +func (app *PersistentKVStoreApplication) substPrepareTx(blockData [][]byte) []*types.TxRecord { + trs := make([]*types.TxRecord, len(blockData)) + var removed []*types.TxRecord + for i, tx := range blockData { + if isPrepareTx(tx) { + removed = append(removed, &types.TxRecord{ + Tx: tx, + Action: types.TxRecord_REMOVED, + }) + trs[i] = &types.TxRecord{ + Tx: bytes.TrimPrefix(tx, []byte(PreparePrefix)), + Action: types.TxRecord_ADDED, + } + continue + } + trs[i] = &types.TxRecord{ + Tx: tx, + Action: types.TxRecord_UNMODIFIED, + } + } + + return append(trs, removed...) +} diff --git a/abci/types/application.go b/abci/types/application.go index fe69b6f05..47286e373 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -4,6 +4,7 @@ import ( context "golang.org/x/net/context" ) +//go:generate mockery --case underscore --name Application // Application is an interface that enables any finite, deterministic state machine // to be driven by a blockchain-based replication engine via the ABCI. // All methods take a RequestXxx argument and return a ResponseXxx argument, @@ -97,9 +98,7 @@ func (BaseApplication) ApplySnapshotChunk(req RequestApplySnapshotChunk) Respons } func (BaseApplication) PrepareProposal(req RequestPrepareProposal) ResponsePrepareProposal { - return ResponsePrepareProposal{ - BlockData: req.BlockData, - } + return ResponsePrepareProposal{} } //------------------------------------------------------- diff --git a/abci/types/mocks/application.go b/abci/types/mocks/application.go new file mode 100644 index 000000000..d945bf5f3 --- /dev/null +++ b/abci/types/mocks/application.go @@ -0,0 +1,224 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + types "github.com/tendermint/tendermint/abci/types" +) + +// Application is an autogenerated mock type for the Application type +type Application struct { + mock.Mock +} + +// ApplySnapshotChunk provides a mock function with given fields: _a0 +func (_m *Application) ApplySnapshotChunk(_a0 types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { + ret := _m.Called(_a0) + + var r0 types.ResponseApplySnapshotChunk + if rf, ok := ret.Get(0).(func(types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseApplySnapshotChunk) + } + + return r0 +} + +// BeginBlock provides a mock function with given fields: _a0 +func (_m *Application) BeginBlock(_a0 types.RequestBeginBlock) types.ResponseBeginBlock { + ret := _m.Called(_a0) + + var r0 types.ResponseBeginBlock + if rf, ok := ret.Get(0).(func(types.RequestBeginBlock) types.ResponseBeginBlock); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseBeginBlock) + } + + return r0 +} + +// CheckTx provides a mock function with given fields: _a0 +func (_m *Application) CheckTx(_a0 types.RequestCheckTx) types.ResponseCheckTx { + ret := _m.Called(_a0) + + var r0 types.ResponseCheckTx + if rf, ok := ret.Get(0).(func(types.RequestCheckTx) types.ResponseCheckTx); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseCheckTx) + } + + return r0 +} + +// Commit provides a mock function with given fields: +func (_m *Application) Commit() types.ResponseCommit { + ret := _m.Called() + + var r0 types.ResponseCommit + if rf, ok := ret.Get(0).(func() types.ResponseCommit); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(types.ResponseCommit) + } + + return r0 +} + +// DeliverTx provides a mock function with given fields: _a0 +func (_m *Application) DeliverTx(_a0 types.RequestDeliverTx) types.ResponseDeliverTx { + ret := _m.Called(_a0) + + var r0 types.ResponseDeliverTx + if rf, ok := ret.Get(0).(func(types.RequestDeliverTx) types.ResponseDeliverTx); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseDeliverTx) + } + + return r0 +} + +// EndBlock provides a mock function with given fields: _a0 +func (_m *Application) EndBlock(_a0 types.RequestEndBlock) types.ResponseEndBlock { + ret := _m.Called(_a0) + + var r0 types.ResponseEndBlock + if rf, ok := ret.Get(0).(func(types.RequestEndBlock) types.ResponseEndBlock); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseEndBlock) + } + + return r0 +} + +// Info provides a mock function with given fields: _a0 +func (_m *Application) Info(_a0 types.RequestInfo) types.ResponseInfo { + ret := _m.Called(_a0) + + var r0 types.ResponseInfo + if rf, ok := ret.Get(0).(func(types.RequestInfo) types.ResponseInfo); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseInfo) + } + + return r0 +} + +// InitChain provides a mock function with given fields: _a0 +func (_m *Application) InitChain(_a0 types.RequestInitChain) types.ResponseInitChain { + ret := _m.Called(_a0) + + var r0 types.ResponseInitChain + if rf, ok := ret.Get(0).(func(types.RequestInitChain) types.ResponseInitChain); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseInitChain) + } + + return r0 +} + +// ListSnapshots provides a mock function with given fields: _a0 +func (_m *Application) ListSnapshots(_a0 types.RequestListSnapshots) types.ResponseListSnapshots { + ret := _m.Called(_a0) + + var r0 types.ResponseListSnapshots + if rf, ok := ret.Get(0).(func(types.RequestListSnapshots) types.ResponseListSnapshots); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseListSnapshots) + } + + return r0 +} + +// LoadSnapshotChunk provides a mock function with given fields: _a0 +func (_m *Application) LoadSnapshotChunk(_a0 types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk { + ret := _m.Called(_a0) + + var r0 types.ResponseLoadSnapshotChunk + if rf, ok := ret.Get(0).(func(types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseLoadSnapshotChunk) + } + + return r0 +} + +// OfferSnapshot provides a mock function with given fields: _a0 +func (_m *Application) OfferSnapshot(_a0 types.RequestOfferSnapshot) types.ResponseOfferSnapshot { + ret := _m.Called(_a0) + + var r0 types.ResponseOfferSnapshot + if rf, ok := ret.Get(0).(func(types.RequestOfferSnapshot) types.ResponseOfferSnapshot); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseOfferSnapshot) + } + + return r0 +} + +// PrepareProposal provides a mock function with given fields: _a0 +func (_m *Application) PrepareProposal(_a0 types.RequestPrepareProposal) types.ResponsePrepareProposal { + ret := _m.Called(_a0) + + var r0 types.ResponsePrepareProposal + if rf, ok := ret.Get(0).(func(types.RequestPrepareProposal) types.ResponsePrepareProposal); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponsePrepareProposal) + } + + return r0 +} + +// Query provides a mock function with given fields: _a0 +func (_m *Application) Query(_a0 types.RequestQuery) types.ResponseQuery { + ret := _m.Called(_a0) + + var r0 types.ResponseQuery + if rf, ok := ret.Get(0).(func(types.RequestQuery) types.ResponseQuery); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseQuery) + } + + return r0 +} + +// SetOption provides a mock function with given fields: _a0 +func (_m *Application) SetOption(_a0 types.RequestSetOption) types.ResponseSetOption { + ret := _m.Called(_a0) + + var r0 types.ResponseSetOption + if rf, ok := ret.Get(0).(func(types.RequestSetOption) types.ResponseSetOption); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(types.ResponseSetOption) + } + + return r0 +} + +type mockConstructorTestingTNewApplication interface { + mock.TestingT + Cleanup(func()) +} + +// NewApplication creates a new instance of Application. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewApplication(t mockConstructorTestingTNewApplication) *Application { + mock := &Application{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/abci/types/mocks/base.go b/abci/types/mocks/base.go new file mode 100644 index 000000000..caf9fc0d2 --- /dev/null +++ b/abci/types/mocks/base.go @@ -0,0 +1,176 @@ +package mocks + +import ( + types "github.com/tendermint/tendermint/abci/types" +) + +// BaseMock provides a wrapper around the generated Application mock and a BaseApplication. +// BaseMock first tries to use the mock's implementation of the method. +// If no functionality was provided for the mock by the user, BaseMock dispatches +// to the BaseApplication and uses its functionality. +// BaseMock allows users to provide mocked functionality for only the methods that matter +// for their test while avoiding a panic if the code calls Application methods that are +// not relevant to the test. +type BaseMock struct { + base *types.BaseApplication + *Application +} + +func NewBaseMock() BaseMock { + return BaseMock{ + base: types.NewBaseApplication(), + Application: new(Application), + } +} + +// Info/Query Connection +// Return application info +func (m BaseMock) Info(input types.RequestInfo) types.ResponseInfo { + var ret types.ResponseInfo + defer func() { + if r := recover(); r != nil { + ret = m.base.Info(input) + } + }() + ret = m.Application.Info(input) + return ret +} + +func (m BaseMock) Query(input types.RequestQuery) types.ResponseQuery { + var ret types.ResponseQuery + defer func() { + if r := recover(); r != nil { + ret = m.base.Query(input) + } + }() + ret = m.Application.Query(input) + return ret +} + +// Mempool Connection +// Validate a tx for the mempool +func (m BaseMock) CheckTx(input types.RequestCheckTx) types.ResponseCheckTx { + var ret types.ResponseCheckTx + defer func() { + if r := recover(); r != nil { + ret = m.base.CheckTx(input) + } + }() + ret = m.Application.CheckTx(input) + return ret +} + +// Consensus Connection +// Initialize blockchain w validators/other info from TendermintCore +func (m BaseMock) InitChain(input types.RequestInitChain) types.ResponseInitChain { + var ret types.ResponseInitChain + defer func() { + if r := recover(); r != nil { + ret = m.base.InitChain(input) + } + }() + ret = m.Application.InitChain(input) + return ret +} + +func (m BaseMock) PrepareProposal(input types.RequestPrepareProposal) types.ResponsePrepareProposal { + var ret types.ResponsePrepareProposal + defer func() { + if r := recover(); r != nil { + ret = m.base.PrepareProposal(input) + } + }() + ret = m.Application.PrepareProposal(input) + return ret +} + +// Commit the state and return the application Merkle root hash +func (m BaseMock) Commit() types.ResponseCommit { + var ret types.ResponseCommit + defer func() { + if r := recover(); r != nil { + ret = m.base.Commit() + } + }() + ret = m.Application.Commit() + return ret +} + +// State Sync Connection +// List available snapshots +func (m BaseMock) ListSnapshots(input types.RequestListSnapshots) types.ResponseListSnapshots { + var ret types.ResponseListSnapshots + defer func() { + if r := recover(); r != nil { + ret = m.base.ListSnapshots(input) + } + }() + ret = m.Application.ListSnapshots(input) + return ret +} + +func (m BaseMock) OfferSnapshot(input types.RequestOfferSnapshot) types.ResponseOfferSnapshot { + var ret types.ResponseOfferSnapshot + defer func() { + if r := recover(); r != nil { + ret = m.base.OfferSnapshot(input) + } + }() + ret = m.Application.OfferSnapshot(input) + return ret +} + +func (m BaseMock) LoadSnapshotChunk(input types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk { + var ret types.ResponseLoadSnapshotChunk + defer func() { + if r := recover(); r != nil { + ret = m.base.LoadSnapshotChunk(input) + } + }() + ret = m.Application.LoadSnapshotChunk(input) + return ret +} + +func (m BaseMock) ApplySnapshotChunk(input types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { + var ret types.ResponseApplySnapshotChunk + defer func() { + if r := recover(); r != nil { + ret = m.base.ApplySnapshotChunk(input) + } + }() + ret = m.Application.ApplySnapshotChunk(input) + return ret +} + +func (m BaseMock) BeginBlock(input types.RequestBeginBlock) types.ResponseBeginBlock { + var ret types.ResponseBeginBlock + defer func() { + if r := recover(); r != nil { + ret = m.base.BeginBlock(input) + } + }() + ret = m.Application.BeginBlock(input) + return ret +} + +func (m BaseMock) DeliverTx(input types.RequestDeliverTx) types.ResponseDeliverTx { + var ret types.ResponseDeliverTx + defer func() { + if r := recover(); r != nil { + ret = m.base.DeliverTx(input) + } + }() + ret = m.Application.DeliverTx(input) + return ret +} + +func (m BaseMock) EndBlock(input types.RequestEndBlock) types.ResponseEndBlock { + var ret types.ResponseEndBlock + defer func() { + if r := recover(); r != nil { + ret = m.base.EndBlock(input) + } + }() + ret = m.Application.EndBlock(input) + return ret +} diff --git a/abci/types/result.go b/abci/types/types.go similarity index 100% rename from abci/types/result.go rename to abci/types/types.go diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 957a99c1c..2fd9ed1a5 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -160,6 +160,38 @@ func (ResponseApplySnapshotChunk_Result) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{33, 0} } +// TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal +type TxRecord_TxAction int32 + +const ( + TxRecord_UNKNOWN TxRecord_TxAction = 0 + TxRecord_UNMODIFIED TxRecord_TxAction = 1 + TxRecord_ADDED TxRecord_TxAction = 2 + TxRecord_REMOVED TxRecord_TxAction = 3 +) + +var TxRecord_TxAction_name = map[int32]string{ + 0: "UNKNOWN", + 1: "UNMODIFIED", + 2: "ADDED", + 3: "REMOVED", +} + +var TxRecord_TxAction_value = map[string]int32{ + "UNKNOWN": 0, + "UNMODIFIED": 1, + "ADDED": 2, + "REMOVED": 3, +} + +func (x TxRecord_TxAction) String() string { + return proto.EnumName(TxRecord_TxAction_name, int32(x)) +} + +func (TxRecord_TxAction) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{42, 0} +} + type Request struct { // Types that are valid to be assigned to Value: // *Request_Echo @@ -1229,15 +1261,15 @@ func (m *RequestApplySnapshotChunk) GetSender() string { } type RequestPrepareProposal struct { - // block_data is an array of transactions that will be included in a block, + Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + Header types1.Header `protobuf:"bytes,2,opt,name=header,proto3" json:"header"` + // txs is an array of transactions that will be included in a block, // sent to the app for possible modifications. - // applications can not exceed the size of the data passed to it. - BlockData [][]byte `protobuf:"bytes,1,rep,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` - // If an application decides to populate block_data with extra information, they can not exceed this value. - BlockDataSize int64 `protobuf:"varint,2,opt,name=block_data_size,json=blockDataSize,proto3" json:"block_data_size,omitempty"` - // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal - // preparation. The votes here will then form the last commit that gets sent in the proposed block. - Votes []*types1.Vote `protobuf:"bytes,3,rep,name=votes,proto3" json:"votes,omitempty"` + Txs [][]byte `protobuf:"bytes,3,rep,name=txs,proto3" json:"txs,omitempty"` + LocalLastCommit ExtendedCommitInfo `protobuf:"bytes,4,opt,name=local_last_commit,json=localLastCommit,proto3" json:"local_last_commit"` + ByzantineValidators []Evidence `protobuf:"bytes,5,rep,name=byzantine_validators,json=byzantineValidators,proto3" json:"byzantine_validators"` + // the modified transactions cannot exceed this size. + MaxTxBytes int64 `protobuf:"varint,6,opt,name=max_tx_bytes,json=maxTxBytes,proto3" json:"max_tx_bytes,omitempty"` } func (m *RequestPrepareProposal) Reset() { *m = RequestPrepareProposal{} } @@ -1273,27 +1305,48 @@ func (m *RequestPrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_RequestPrepareProposal proto.InternalMessageInfo -func (m *RequestPrepareProposal) GetBlockData() [][]byte { +func (m *RequestPrepareProposal) GetHash() []byte { if m != nil { - return m.BlockData + return m.Hash } return nil } -func (m *RequestPrepareProposal) GetBlockDataSize() int64 { +func (m *RequestPrepareProposal) GetHeader() types1.Header { if m != nil { - return m.BlockDataSize + return m.Header + } + return types1.Header{} +} + +func (m *RequestPrepareProposal) GetTxs() [][]byte { + if m != nil { + return m.Txs + } + return nil +} + +func (m *RequestPrepareProposal) GetLocalLastCommit() ExtendedCommitInfo { + if m != nil { + return m.LocalLastCommit + } + return ExtendedCommitInfo{} +} + +func (m *RequestPrepareProposal) GetByzantineValidators() []Evidence { + if m != nil { + return m.ByzantineValidators + } + return nil +} + +func (m *RequestPrepareProposal) GetMaxTxBytes() int64 { + if m != nil { + return m.MaxTxBytes } return 0 } -func (m *RequestPrepareProposal) GetVotes() []*types1.Vote { - if m != nil { - return m.Votes - } - return nil -} - type Response struct { // Types that are valid to be assigned to Value: // *Response_Exception @@ -2582,7 +2635,8 @@ func (m *ResponseApplySnapshotChunk) GetRejectSenders() []string { } type ResponsePrepareProposal struct { - BlockData [][]byte `protobuf:"bytes,1,rep,name=block_data,json=blockData,proto3" json:"block_data,omitempty"` + ModifiedTx bool `protobuf:"varint,1,opt,name=modified_tx,json=modifiedTx,proto3" json:"modified_tx,omitempty"` + TxRecords []*TxRecord `protobuf:"bytes,2,rep,name=tx_records,json=txRecords,proto3" json:"tx_records,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2618,9 +2672,16 @@ func (m *ResponsePrepareProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ResponsePrepareProposal proto.InternalMessageInfo -func (m *ResponsePrepareProposal) GetBlockData() [][]byte { +func (m *ResponsePrepareProposal) GetModifiedTx() bool { if m != nil { - return m.BlockData + return m.ModifiedTx + } + return false +} + +func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { + if m != nil { + return m.TxRecords } return nil } @@ -2802,6 +2863,58 @@ func (m *LastCommitInfo) GetVotes() []VoteInfo { return nil } +type ExtendedCommitInfo struct { + Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"` + Votes []ExtendedVoteInfo `protobuf:"bytes,2,rep,name=votes,proto3" json:"votes"` +} + +func (m *ExtendedCommitInfo) Reset() { *m = ExtendedCommitInfo{} } +func (m *ExtendedCommitInfo) String() string { return proto.CompactTextString(m) } +func (*ExtendedCommitInfo) ProtoMessage() {} +func (*ExtendedCommitInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{38} +} +func (m *ExtendedCommitInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtendedCommitInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtendedCommitInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtendedCommitInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtendedCommitInfo.Merge(m, src) +} +func (m *ExtendedCommitInfo) XXX_Size() int { + return m.Size() +} +func (m *ExtendedCommitInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ExtendedCommitInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtendedCommitInfo proto.InternalMessageInfo + +func (m *ExtendedCommitInfo) GetRound() int32 { + if m != nil { + return m.Round + } + return 0 +} + +func (m *ExtendedCommitInfo) GetVotes() []ExtendedVoteInfo { + if m != nil { + return m.Votes + } + return nil +} + // Event allows application developers to attach additional information to // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. // Later, transactions may be queried using these events. @@ -2814,7 +2927,7 @@ func (m *Event) Reset() { *m = Event{} } func (m *Event) String() string { return proto.CompactTextString(m) } func (*Event) ProtoMessage() {} func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{38} + return fileDescriptor_252557cfdd89a31a, []int{39} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2868,7 +2981,7 @@ func (m *EventAttribute) Reset() { *m = EventAttribute{} } func (m *EventAttribute) String() string { return proto.CompactTextString(m) } func (*EventAttribute) ProtoMessage() {} func (*EventAttribute) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{39} + return fileDescriptor_252557cfdd89a31a, []int{40} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2932,7 +3045,7 @@ func (m *TxResult) Reset() { *m = TxResult{} } func (m *TxResult) String() string { return proto.CompactTextString(m) } func (*TxResult) ProtoMessage() {} func (*TxResult) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{40} + return fileDescriptor_252557cfdd89a31a, []int{41} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2989,6 +3102,58 @@ func (m *TxResult) GetResult() ResponseDeliverTx { return ResponseDeliverTx{} } +type TxRecord struct { + Action TxRecord_TxAction `protobuf:"varint,1,opt,name=action,proto3,enum=tendermint.abci.TxRecord_TxAction" json:"action,omitempty"` + Tx []byte `protobuf:"bytes,2,opt,name=tx,proto3" json:"tx,omitempty"` +} + +func (m *TxRecord) Reset() { *m = TxRecord{} } +func (m *TxRecord) String() string { return proto.CompactTextString(m) } +func (*TxRecord) ProtoMessage() {} +func (*TxRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{42} +} +func (m *TxRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxRecord.Merge(m, src) +} +func (m *TxRecord) XXX_Size() int { + return m.Size() +} +func (m *TxRecord) XXX_DiscardUnknown() { + xxx_messageInfo_TxRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_TxRecord proto.InternalMessageInfo + +func (m *TxRecord) GetAction() TxRecord_TxAction { + if m != nil { + return m.Action + } + return TxRecord_UNKNOWN +} + +func (m *TxRecord) GetTx() []byte { + if m != nil { + return m.Tx + } + return nil +} + // Validator type Validator struct { Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` @@ -3000,7 +3165,7 @@ func (m *Validator) Reset() { *m = Validator{} } func (m *Validator) String() string { return proto.CompactTextString(m) } func (*Validator) ProtoMessage() {} func (*Validator) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{41} + return fileDescriptor_252557cfdd89a31a, []int{43} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3053,7 +3218,7 @@ func (m *ValidatorUpdate) Reset() { *m = ValidatorUpdate{} } func (m *ValidatorUpdate) String() string { return proto.CompactTextString(m) } func (*ValidatorUpdate) ProtoMessage() {} func (*ValidatorUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{42} + return fileDescriptor_252557cfdd89a31a, []int{44} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3106,7 +3271,7 @@ func (m *VoteInfo) Reset() { *m = VoteInfo{} } func (m *VoteInfo) String() string { return proto.CompactTextString(m) } func (*VoteInfo) ProtoMessage() {} func (*VoteInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{43} + return fileDescriptor_252557cfdd89a31a, []int{45} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3149,6 +3314,66 @@ func (m *VoteInfo) GetSignedLastBlock() bool { return false } +type ExtendedVoteInfo struct { + Validator Validator `protobuf:"bytes,1,opt,name=validator,proto3" json:"validator"` + SignedLastBlock bool `protobuf:"varint,2,opt,name=signed_last_block,json=signedLastBlock,proto3" json:"signed_last_block,omitempty"` + VoteExtension []byte `protobuf:"bytes,3,opt,name=vote_extension,json=voteExtension,proto3" json:"vote_extension,omitempty"` +} + +func (m *ExtendedVoteInfo) Reset() { *m = ExtendedVoteInfo{} } +func (m *ExtendedVoteInfo) String() string { return proto.CompactTextString(m) } +func (*ExtendedVoteInfo) ProtoMessage() {} +func (*ExtendedVoteInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_252557cfdd89a31a, []int{46} +} +func (m *ExtendedVoteInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtendedVoteInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtendedVoteInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtendedVoteInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtendedVoteInfo.Merge(m, src) +} +func (m *ExtendedVoteInfo) XXX_Size() int { + return m.Size() +} +func (m *ExtendedVoteInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ExtendedVoteInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtendedVoteInfo proto.InternalMessageInfo + +func (m *ExtendedVoteInfo) GetValidator() Validator { + if m != nil { + return m.Validator + } + return Validator{} +} + +func (m *ExtendedVoteInfo) GetSignedLastBlock() bool { + if m != nil { + return m.SignedLastBlock + } + return false +} + +func (m *ExtendedVoteInfo) GetVoteExtension() []byte { + if m != nil { + return m.VoteExtension + } + return nil +} + type Evidence struct { Type EvidenceType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.abci.EvidenceType" json:"type,omitempty"` // The offending validator @@ -3167,7 +3392,7 @@ func (m *Evidence) Reset() { *m = Evidence{} } func (m *Evidence) String() string { return proto.CompactTextString(m) } func (*Evidence) ProtoMessage() {} func (*Evidence) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{44} + return fileDescriptor_252557cfdd89a31a, []int{47} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3243,7 +3468,7 @@ func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (*Snapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{45} + return fileDescriptor_252557cfdd89a31a, []int{48} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3312,6 +3537,7 @@ func init() { proto.RegisterEnum("tendermint.abci.EvidenceType", EvidenceType_name, EvidenceType_value) proto.RegisterEnum("tendermint.abci.ResponseOfferSnapshot_Result", ResponseOfferSnapshot_Result_name, ResponseOfferSnapshot_Result_value) proto.RegisterEnum("tendermint.abci.ResponseApplySnapshotChunk_Result", ResponseApplySnapshotChunk_Result_name, ResponseApplySnapshotChunk_Result_value) + proto.RegisterEnum("tendermint.abci.TxRecord_TxAction", TxRecord_TxAction_name, TxRecord_TxAction_value) proto.RegisterType((*Request)(nil), "tendermint.abci.Request") proto.RegisterType((*RequestEcho)(nil), "tendermint.abci.RequestEcho") proto.RegisterType((*RequestFlush)(nil), "tendermint.abci.RequestFlush") @@ -3350,12 +3576,15 @@ func init() { proto.RegisterType((*ConsensusParams)(nil), "tendermint.abci.ConsensusParams") proto.RegisterType((*BlockParams)(nil), "tendermint.abci.BlockParams") proto.RegisterType((*LastCommitInfo)(nil), "tendermint.abci.LastCommitInfo") + proto.RegisterType((*ExtendedCommitInfo)(nil), "tendermint.abci.ExtendedCommitInfo") proto.RegisterType((*Event)(nil), "tendermint.abci.Event") proto.RegisterType((*EventAttribute)(nil), "tendermint.abci.EventAttribute") proto.RegisterType((*TxResult)(nil), "tendermint.abci.TxResult") + proto.RegisterType((*TxRecord)(nil), "tendermint.abci.TxRecord") proto.RegisterType((*Validator)(nil), "tendermint.abci.Validator") proto.RegisterType((*ValidatorUpdate)(nil), "tendermint.abci.ValidatorUpdate") proto.RegisterType((*VoteInfo)(nil), "tendermint.abci.VoteInfo") + proto.RegisterType((*ExtendedVoteInfo)(nil), "tendermint.abci.ExtendedVoteInfo") proto.RegisterType((*Evidence)(nil), "tendermint.abci.Evidence") proto.RegisterType((*Snapshot)(nil), "tendermint.abci.Snapshot") } @@ -3363,190 +3592,201 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 2917 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0x4b, 0x93, 0x23, 0xc5, - 0xb5, 0xd6, 0x5b, 0xaa, 0xd3, 0xad, 0x47, 0xe7, 0x0c, 0x33, 0x42, 0xcc, 0x74, 0x0f, 0x45, 0x00, - 0xc3, 0x00, 0xdd, 0x97, 0x26, 0xe0, 0x0e, 0x17, 0xee, 0x85, 0x96, 0x46, 0x83, 0x9a, 0x69, 0xba, - 0xfb, 0x66, 0x6b, 0x06, 0xbf, 0x98, 0xa2, 0xa4, 0xca, 0x96, 0x8a, 0x91, 0xaa, 0x8a, 0xaa, 0x54, - 0xd3, 0x3d, 0x4b, 0x87, 0xbd, 0xc1, 0xe1, 0x08, 0x96, 0xde, 0xf0, 0x3f, 0xbc, 0x70, 0x78, 0xe3, - 0x0d, 0x11, 0xde, 0xb0, 0xf4, 0xc2, 0x81, 0x1d, 0xb0, 0x70, 0xd8, 0x7f, 0xc0, 0x2b, 0x87, 0x1d, - 0xf9, 0xa8, 0x97, 0xa4, 0x6a, 0xa9, 0xc1, 0x3b, 0xef, 0x32, 0x4f, 0x9e, 0x73, 0xb2, 0x32, 0x2b, - 0xf3, 0x3b, 0xdf, 0x39, 0x55, 0xf0, 0x14, 0x25, 0x96, 0x41, 0xdc, 0xb1, 0x69, 0xd1, 0x2d, 0xbd, - 0xd7, 0x37, 0xb7, 0xe8, 0x99, 0x43, 0xbc, 0x4d, 0xc7, 0xb5, 0xa9, 0x8d, 0xaa, 0xe1, 0xe0, 0x26, - 0x1b, 0x6c, 0x5c, 0x8f, 0x68, 0xf7, 0xdd, 0x33, 0x87, 0xda, 0x5b, 0x8e, 0x6b, 0xdb, 0xc7, 0x42, - 0xbf, 0x71, 0x2d, 0x32, 0xcc, 0xfd, 0x44, 0xbd, 0xc5, 0x46, 0xa5, 0xf1, 0x23, 0x72, 0xe6, 0x8f, - 0x5e, 0x9f, 0xb1, 0x75, 0x74, 0x57, 0x1f, 0xfb, 0xc3, 0x1b, 0x03, 0xdb, 0x1e, 0x8c, 0xc8, 0x16, - 0xef, 0xf5, 0x26, 0xc7, 0x5b, 0xd4, 0x1c, 0x13, 0x8f, 0xea, 0x63, 0x47, 0x2a, 0x5c, 0x1e, 0xd8, - 0x03, 0x9b, 0x37, 0xb7, 0x58, 0x4b, 0x48, 0xd5, 0xbf, 0x94, 0xa0, 0x88, 0xc9, 0x27, 0x13, 0xe2, - 0x51, 0xb4, 0x0d, 0x39, 0xd2, 0x1f, 0xda, 0xf5, 0xf4, 0x8d, 0xf4, 0xcd, 0x95, 0xed, 0x6b, 0x9b, - 0x53, 0x8b, 0xdb, 0x94, 0x7a, 0xed, 0xfe, 0xd0, 0xee, 0xa4, 0x30, 0xd7, 0x45, 0xaf, 0x41, 0xfe, - 0x78, 0x34, 0xf1, 0x86, 0xf5, 0x0c, 0x37, 0xba, 0x9e, 0x64, 0x74, 0x97, 0x29, 0x75, 0x52, 0x58, - 0x68, 0xb3, 0xa9, 0x4c, 0xeb, 0xd8, 0xae, 0x67, 0xcf, 0x9f, 0x6a, 0xd7, 0x3a, 0xe6, 0x53, 0x31, - 0x5d, 0xd4, 0x04, 0xf0, 0x08, 0xd5, 0x6c, 0x87, 0x9a, 0xb6, 0x55, 0xcf, 0x71, 0xcb, 0xa7, 0x93, - 0x2c, 0x8f, 0x08, 0x3d, 0xe0, 0x8a, 0x9d, 0x14, 0x56, 0x3c, 0xbf, 0xc3, 0x7c, 0x98, 0x96, 0x49, - 0xb5, 0xfe, 0x50, 0x37, 0xad, 0x7a, 0xfe, 0x7c, 0x1f, 0xbb, 0x96, 0x49, 0x5b, 0x4c, 0x91, 0xf9, - 0x30, 0xfd, 0x0e, 0x5b, 0xf2, 0x27, 0x13, 0xe2, 0x9e, 0xd5, 0x0b, 0xe7, 0x2f, 0xf9, 0xff, 0x99, - 0x12, 0x5b, 0x32, 0xd7, 0x46, 0x6d, 0x58, 0xe9, 0x91, 0x81, 0x69, 0x69, 0xbd, 0x91, 0xdd, 0x7f, - 0x54, 0x2f, 0x72, 0x63, 0x35, 0xc9, 0xb8, 0xc9, 0x54, 0x9b, 0x4c, 0xb3, 0x93, 0xc2, 0xd0, 0x0b, - 0x7a, 0xe8, 0x2d, 0x28, 0xf5, 0x87, 0xa4, 0xff, 0x48, 0xa3, 0xa7, 0xf5, 0x12, 0xf7, 0xb1, 0x91, - 0xe4, 0xa3, 0xc5, 0xf4, 0xba, 0xa7, 0x9d, 0x14, 0x2e, 0xf6, 0x45, 0x93, 0xad, 0xdf, 0x20, 0x23, - 0xf3, 0x84, 0xb8, 0xcc, 0x5e, 0x39, 0x7f, 0xfd, 0x77, 0x84, 0x26, 0xf7, 0xa0, 0x18, 0x7e, 0x07, - 0xbd, 0x0d, 0x0a, 0xb1, 0x0c, 0xb9, 0x0c, 0xe0, 0x2e, 0x6e, 0x24, 0x9e, 0x15, 0xcb, 0xf0, 0x17, - 0x51, 0x22, 0xb2, 0x8d, 0x6e, 0x43, 0xa1, 0x6f, 0x8f, 0xc7, 0x26, 0xad, 0xaf, 0x70, 0xeb, 0xf5, - 0xc4, 0x05, 0x70, 0xad, 0x4e, 0x0a, 0x4b, 0x7d, 0xb4, 0x0f, 0x95, 0x91, 0xe9, 0x51, 0xcd, 0xb3, - 0x74, 0xc7, 0x1b, 0xda, 0xd4, 0xab, 0xaf, 0x72, 0x0f, 0xcf, 0x26, 0x79, 0xd8, 0x33, 0x3d, 0x7a, - 0xe4, 0x2b, 0x77, 0x52, 0xb8, 0x3c, 0x8a, 0x0a, 0x98, 0x3f, 0xfb, 0xf8, 0x98, 0xb8, 0x81, 0xc3, - 0x7a, 0xf9, 0x7c, 0x7f, 0x07, 0x4c, 0xdb, 0xb7, 0x67, 0xfe, 0xec, 0xa8, 0x00, 0xfd, 0x18, 0x2e, - 0x8d, 0x6c, 0xdd, 0x08, 0xdc, 0x69, 0xfd, 0xe1, 0xc4, 0x7a, 0x54, 0xaf, 0x70, 0xa7, 0x2f, 0x24, - 0x3e, 0xa4, 0xad, 0x1b, 0xbe, 0x8b, 0x16, 0x33, 0xe8, 0xa4, 0xf0, 0xda, 0x68, 0x5a, 0x88, 0x1e, - 0xc2, 0x65, 0xdd, 0x71, 0x46, 0x67, 0xd3, 0xde, 0xab, 0xdc, 0xfb, 0xad, 0x24, 0xef, 0x3b, 0xcc, - 0x66, 0xda, 0x3d, 0xd2, 0x67, 0xa4, 0xa8, 0x0b, 0x35, 0xc7, 0x25, 0x8e, 0xee, 0x12, 0xcd, 0x71, - 0x6d, 0xc7, 0xf6, 0xf4, 0x51, 0xbd, 0xc6, 0x7d, 0x3f, 0x9f, 0xe4, 0xfb, 0x50, 0xe8, 0x1f, 0x4a, - 0xf5, 0x4e, 0x0a, 0x57, 0x9d, 0xb8, 0xa8, 0x59, 0x84, 0xfc, 0x89, 0x3e, 0x9a, 0x10, 0xf5, 0x79, - 0x58, 0x89, 0x00, 0x08, 0xaa, 0x43, 0x71, 0x4c, 0x3c, 0x4f, 0x1f, 0x10, 0x8e, 0x37, 0x0a, 0xf6, - 0xbb, 0x6a, 0x05, 0x56, 0xa3, 0xa0, 0xa1, 0x8e, 0x03, 0x43, 0x06, 0x07, 0xcc, 0xf0, 0x84, 0xb8, - 0x1e, 0xc3, 0x00, 0x69, 0x28, 0xbb, 0xe8, 0x19, 0x28, 0xf3, 0x43, 0xa9, 0xf9, 0xe3, 0x0c, 0x93, - 0x72, 0x78, 0x95, 0x0b, 0x1f, 0x48, 0xa5, 0x0d, 0x58, 0x71, 0xb6, 0x9d, 0x40, 0x25, 0xcb, 0x55, - 0xc0, 0xd9, 0x76, 0xa4, 0x82, 0xfa, 0x3f, 0x50, 0x9b, 0xc6, 0x10, 0x54, 0x83, 0xec, 0x23, 0x72, - 0x26, 0xe7, 0x63, 0x4d, 0x74, 0x59, 0x2e, 0x8b, 0xcf, 0xa1, 0x60, 0xb9, 0xc6, 0xdf, 0x67, 0x02, - 0xe3, 0x00, 0x3c, 0xd0, 0x6d, 0xc8, 0x31, 0x2c, 0x96, 0xb0, 0xda, 0xd8, 0x14, 0x40, 0xbd, 0xe9, - 0x03, 0xf5, 0x66, 0xd7, 0x07, 0xea, 0x66, 0xe9, 0xcb, 0xaf, 0x37, 0x52, 0x9f, 0xff, 0x69, 0x23, - 0x8d, 0xb9, 0x05, 0x7a, 0x92, 0xdd, 0x75, 0xdd, 0xb4, 0x34, 0xd3, 0x90, 0xf3, 0x14, 0x79, 0x7f, - 0xd7, 0x40, 0xf7, 0xa0, 0xd6, 0xb7, 0x2d, 0x8f, 0x58, 0xde, 0xc4, 0xd3, 0x44, 0x20, 0x90, 0x60, - 0x3a, 0x7b, 0x17, 0x5b, 0xbe, 0xe2, 0x21, 0xd7, 0xc3, 0xd5, 0x7e, 0x5c, 0x80, 0xee, 0x02, 0x9c, - 0xe8, 0x23, 0xd3, 0xd0, 0xa9, 0xed, 0x7a, 0xf5, 0xdc, 0x8d, 0xec, 0x5c, 0x37, 0x0f, 0x7c, 0x95, - 0xfb, 0x8e, 0xa1, 0x53, 0xd2, 0xcc, 0xb1, 0xa7, 0xc5, 0x11, 0x4b, 0xf4, 0x1c, 0x54, 0x75, 0xc7, - 0xd1, 0x3c, 0xaa, 0x53, 0xa2, 0xf5, 0xce, 0x28, 0xf1, 0x38, 0xc4, 0xae, 0xe2, 0xb2, 0xee, 0x38, - 0x47, 0x4c, 0xda, 0x64, 0x42, 0xf4, 0x2c, 0x54, 0x18, 0x9c, 0x9a, 0xfa, 0x48, 0x1b, 0x12, 0x73, - 0x30, 0xa4, 0x1c, 0x4a, 0xb3, 0xb8, 0x2c, 0xa5, 0x1d, 0x2e, 0x54, 0x8d, 0xe0, 0x20, 0x70, 0x28, - 0x45, 0x08, 0x72, 0x86, 0x4e, 0x75, 0xbe, 0x91, 0xab, 0x98, 0xb7, 0x99, 0xcc, 0xd1, 0xe9, 0x50, - 0x6e, 0x0f, 0x6f, 0xa3, 0x2b, 0x50, 0x90, 0x6e, 0xb3, 0xdc, 0xad, 0xec, 0xb1, 0x77, 0xe6, 0xb8, - 0xf6, 0x09, 0xe1, 0xb1, 0xa3, 0x84, 0x45, 0x47, 0xfd, 0x59, 0x06, 0xd6, 0x66, 0x40, 0x97, 0xf9, - 0x1d, 0xea, 0xde, 0xd0, 0x9f, 0x8b, 0xb5, 0xd1, 0xeb, 0xcc, 0xaf, 0x6e, 0x10, 0x57, 0x06, 0xbb, - 0x7a, 0x74, 0x8b, 0x44, 0x20, 0xef, 0xf0, 0x71, 0xb9, 0x35, 0x52, 0x1b, 0x1d, 0x40, 0x6d, 0xa4, - 0x7b, 0x54, 0x13, 0x20, 0xa6, 0x45, 0x02, 0xdf, 0x2c, 0x74, 0xef, 0xe9, 0x3e, 0xec, 0xb1, 0xc3, - 0x2e, 0x1d, 0x55, 0x46, 0x31, 0x29, 0xc2, 0x70, 0xb9, 0x77, 0xf6, 0x58, 0xb7, 0xa8, 0x69, 0x11, - 0x6d, 0xe6, 0xcd, 0x3d, 0x39, 0xe3, 0xb4, 0x7d, 0x62, 0x1a, 0xc4, 0xea, 0xfb, 0xaf, 0xec, 0x52, - 0x60, 0x1c, 0xbc, 0x52, 0x4f, 0xc5, 0x50, 0x89, 0x87, 0x0d, 0x54, 0x81, 0x0c, 0x3d, 0x95, 0x1b, - 0x90, 0xa1, 0xa7, 0xe8, 0xbf, 0x20, 0xc7, 0x16, 0xc9, 0x17, 0x5f, 0x99, 0x13, 0xb3, 0xa5, 0x5d, - 0xf7, 0xcc, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x70, 0x1b, 0x82, 0x50, 0x32, 0xed, 0x55, 0x7d, 0x01, - 0xaa, 0x53, 0xb1, 0x22, 0xf2, 0xfe, 0xd2, 0xd1, 0xf7, 0xa7, 0x56, 0xa1, 0x1c, 0x0b, 0x0c, 0xea, - 0x15, 0xb8, 0x3c, 0x0f, 0xe7, 0xd5, 0x61, 0x20, 0x8f, 0xe1, 0x35, 0x7a, 0x0d, 0x4a, 0x01, 0xd0, - 0x8b, 0xdb, 0x38, 0xbb, 0x57, 0xbe, 0x32, 0x0e, 0x54, 0xd9, 0x35, 0x64, 0xc7, 0x9a, 0x9f, 0x87, - 0x0c, 0x7f, 0xf0, 0xa2, 0xee, 0x38, 0x1d, 0xdd, 0x1b, 0xaa, 0x1f, 0x41, 0x3d, 0x09, 0xc4, 0xa7, - 0x96, 0x91, 0x0b, 0x8e, 0xe1, 0x15, 0x28, 0x1c, 0xdb, 0xee, 0x58, 0xa7, 0xdc, 0x59, 0x19, 0xcb, - 0x1e, 0x3b, 0x9e, 0x02, 0xd0, 0xb3, 0x5c, 0x2c, 0x3a, 0xaa, 0x06, 0x4f, 0x26, 0x02, 0x39, 0x33, - 0x31, 0x2d, 0x83, 0x88, 0xfd, 0x2c, 0x63, 0xd1, 0x09, 0x1d, 0x89, 0x87, 0x15, 0x1d, 0x36, 0xad, - 0xc7, 0xd7, 0xca, 0xfd, 0x2b, 0x58, 0xf6, 0xd4, 0x5f, 0xa6, 0xe1, 0xca, 0x7c, 0x38, 0x47, 0xd7, - 0x01, 0x04, 0xa0, 0xca, 0x6b, 0x97, 0xbd, 0xb9, 0x8a, 0x15, 0x2e, 0xb9, 0xc3, 0xee, 0xde, 0x73, - 0x50, 0x0d, 0x87, 0x35, 0xcf, 0x7c, 0x2c, 0xce, 0x46, 0x16, 0x97, 0x03, 0x9d, 0x23, 0xf3, 0x31, - 0x41, 0x2f, 0x41, 0xfe, 0xc4, 0x66, 0x60, 0x90, 0xe5, 0xe7, 0xf3, 0xca, 0xec, 0xb5, 0x79, 0x60, - 0x53, 0x82, 0x85, 0x92, 0xfa, 0x1b, 0x05, 0x4a, 0x98, 0x78, 0x0e, 0xc3, 0x28, 0xd4, 0x04, 0x85, - 0x9c, 0xf6, 0x89, 0xa0, 0x7c, 0xe9, 0x44, 0xca, 0x24, 0xb4, 0xdb, 0xbe, 0x26, 0xe3, 0x2b, 0x81, - 0x19, 0x7a, 0x55, 0xd2, 0xda, 0x64, 0x86, 0x2a, 0xcd, 0xa3, 0xbc, 0xf6, 0x75, 0x9f, 0xd7, 0x66, - 0x13, 0x29, 0x8a, 0xb0, 0x9a, 0x22, 0xb6, 0xaf, 0x4a, 0x62, 0x9b, 0x5b, 0x30, 0x59, 0x8c, 0xd9, - 0xb6, 0x62, 0xcc, 0x36, 0xbf, 0x60, 0x99, 0x09, 0xd4, 0xb6, 0x15, 0xa3, 0xb6, 0x85, 0x05, 0x4e, - 0x12, 0xb8, 0xed, 0xeb, 0x3e, 0xb7, 0x2d, 0x2e, 0x58, 0xf6, 0x14, 0xb9, 0xbd, 0x1b, 0x27, 0xb7, - 0x82, 0x98, 0x3e, 0x93, 0x68, 0x9d, 0xc8, 0x6e, 0xff, 0x37, 0xc2, 0x6e, 0x95, 0x44, 0x6a, 0x29, - 0x9c, 0xcc, 0xa1, 0xb7, 0xad, 0x18, 0xbd, 0x85, 0x05, 0x7b, 0x90, 0xc0, 0x6f, 0xdf, 0x89, 0xf2, - 0xdb, 0x95, 0x44, 0x8a, 0x2c, 0x0f, 0xcd, 0x3c, 0x82, 0xfb, 0x46, 0x40, 0x70, 0x57, 0x13, 0x19, - 0xba, 0x5c, 0xc3, 0x34, 0xc3, 0x3d, 0x98, 0x61, 0xb8, 0x82, 0x91, 0x3e, 0x97, 0xe8, 0x62, 0x01, - 0xc5, 0x3d, 0x98, 0xa1, 0xb8, 0x95, 0x05, 0x0e, 0x17, 0x70, 0xdc, 0x9f, 0xcc, 0xe7, 0xb8, 0xc9, - 0x2c, 0x54, 0x3e, 0xe6, 0x72, 0x24, 0x57, 0x4b, 0x20, 0xb9, 0x82, 0x88, 0xbe, 0x98, 0xe8, 0x7e, - 0x69, 0x96, 0x7b, 0x7f, 0x0e, 0xcb, 0x5d, 0xe3, 0xce, 0x6f, 0x26, 0x3a, 0xbf, 0x08, 0xcd, 0x7d, - 0x81, 0xb1, 0x89, 0x29, 0x3c, 0x62, 0x88, 0x4c, 0x5c, 0xd7, 0x76, 0x25, 0x83, 0x14, 0x1d, 0xf5, - 0x26, 0xe3, 0x37, 0x21, 0xf6, 0x9c, 0x43, 0x89, 0x79, 0xe4, 0x8b, 0xe0, 0x8d, 0xfa, 0xeb, 0x74, - 0x68, 0xcb, 0x29, 0x41, 0x94, 0x1b, 0x29, 0x92, 0x1b, 0x45, 0x98, 0x72, 0x26, 0xce, 0x94, 0x37, - 0x60, 0x85, 0x45, 0xb4, 0x29, 0x12, 0xac, 0x3b, 0x3e, 0x09, 0x46, 0xb7, 0x60, 0x8d, 0x53, 0x16, - 0x81, 0xef, 0x32, 0x8c, 0xe5, 0x38, 0xb8, 0x57, 0xd9, 0x80, 0x38, 0xf3, 0x22, 0x9e, 0xbd, 0x0c, - 0x97, 0x22, 0xba, 0x41, 0xa4, 0x14, 0xcc, 0xaf, 0x16, 0x68, 0xef, 0xc8, 0x90, 0xf9, 0x7e, 0xb8, - 0x41, 0x21, 0xc1, 0x46, 0x90, 0xeb, 0xdb, 0x06, 0x91, 0x71, 0x8c, 0xb7, 0x19, 0xe9, 0x1e, 0xd9, - 0x03, 0x19, 0xad, 0x58, 0x93, 0x69, 0x05, 0xe0, 0xaa, 0x08, 0xec, 0x54, 0x7f, 0x97, 0x0e, 0xfd, - 0x85, 0x9c, 0x7b, 0x1e, 0x3d, 0x4e, 0xff, 0x7b, 0xe8, 0x71, 0xe6, 0x3b, 0xd3, 0xe3, 0x28, 0x8f, - 0xc8, 0xc6, 0x79, 0xc4, 0xdf, 0xd3, 0xe1, 0x1b, 0x0e, 0xc8, 0xee, 0x77, 0xdb, 0x91, 0x90, 0x14, - 0xe4, 0xf9, 0xfb, 0x92, 0xa4, 0x40, 0xa6, 0x30, 0x05, 0x3e, 0x6f, 0x3c, 0x85, 0x29, 0x0a, 0x9a, - 0xc0, 0x3b, 0xe8, 0x36, 0x28, 0xbc, 0x62, 0xa5, 0xd9, 0x8e, 0x27, 0x71, 0xfc, 0xa9, 0xe8, 0x5a, - 0x45, 0x61, 0x6a, 0xf3, 0x90, 0xe9, 0x1c, 0x38, 0x1e, 0x2e, 0x39, 0xb2, 0x15, 0xe1, 0x3b, 0x4a, - 0x8c, 0x76, 0x5f, 0x03, 0x85, 0x3d, 0xbd, 0xe7, 0xe8, 0x7d, 0xc2, 0x31, 0x59, 0xc1, 0xa1, 0x40, - 0x7d, 0x08, 0x68, 0x36, 0x2a, 0xa0, 0x0e, 0x14, 0xc8, 0x09, 0xb1, 0xa8, 0xc7, 0x59, 0xc7, 0x14, - 0x67, 0x90, 0x9c, 0x96, 0x58, 0xb4, 0x59, 0x67, 0x9b, 0xfc, 0xb7, 0xaf, 0x37, 0x6a, 0x42, 0xfb, - 0x25, 0x7b, 0x6c, 0x52, 0x32, 0x76, 0xe8, 0x19, 0x96, 0xf6, 0xea, 0x1f, 0x33, 0x8c, 0x60, 0xc6, - 0x22, 0xc6, 0xdc, 0xbd, 0xf5, 0x2f, 0x50, 0x26, 0x92, 0x5c, 0x2c, 0xb7, 0xdf, 0xeb, 0x00, 0x03, - 0xdd, 0xd3, 0x3e, 0xd5, 0x2d, 0x4a, 0x0c, 0xb9, 0xe9, 0x11, 0x09, 0x6a, 0x40, 0x89, 0xf5, 0x26, - 0x1e, 0x31, 0x64, 0x9e, 0x13, 0xf4, 0x23, 0xeb, 0x2c, 0x7e, 0xbf, 0x75, 0xc6, 0x77, 0xb9, 0x34, - 0xb5, 0xcb, 0x11, 0xf2, 0xa7, 0x44, 0xc9, 0x1f, 0x7b, 0x36, 0xc7, 0x35, 0x6d, 0xd7, 0xa4, 0x67, - 0xfc, 0xd5, 0x64, 0x71, 0xd0, 0x67, 0xe9, 0xf4, 0x98, 0x8c, 0x1d, 0xdb, 0x1e, 0x69, 0x02, 0xbc, - 0x56, 0xb8, 0xe9, 0xaa, 0x14, 0xb6, 0x39, 0x86, 0xfd, 0x3c, 0x13, 0x5e, 0xbf, 0x90, 0xe4, 0xff, - 0xc7, 0x6d, 0xb0, 0xfa, 0x0b, 0x9e, 0xf9, 0xc7, 0x39, 0x01, 0x3a, 0x82, 0xb5, 0xe0, 0xfa, 0x6b, - 0x13, 0x0e, 0x0b, 0xfe, 0x81, 0x5e, 0x16, 0x3f, 0x6a, 0x27, 0x71, 0xb1, 0x87, 0x7e, 0x00, 0x57, - 0xa7, 0xa0, 0x2d, 0x70, 0x9d, 0x59, 0x12, 0xe1, 0x9e, 0x88, 0x23, 0x9c, 0xef, 0x39, 0xdc, 0xab, - 0xec, 0xf7, 0xbc, 0x74, 0xbb, 0x2c, 0x99, 0x8c, 0x32, 0x9c, 0xb9, 0x6f, 0xff, 0x19, 0x28, 0xbb, - 0x84, 0xea, 0xa6, 0xa5, 0xc5, 0xd2, 0xf5, 0x55, 0x21, 0x94, 0x45, 0x80, 0x43, 0x78, 0x62, 0x2e, - 0xd3, 0x41, 0xff, 0x0d, 0x4a, 0x48, 0x92, 0xd2, 0x09, 0x99, 0x6f, 0x90, 0xcd, 0x85, 0xba, 0xea, - 0x6f, 0xd3, 0xa1, 0xcb, 0x78, 0x7e, 0xd8, 0x86, 0x82, 0x4b, 0xbc, 0xc9, 0x48, 0x64, 0x6c, 0x95, - 0xed, 0x97, 0x97, 0xe3, 0x48, 0x4c, 0x3a, 0x19, 0x51, 0x2c, 0x8d, 0xd5, 0x87, 0x50, 0x10, 0x12, - 0xb4, 0x02, 0xc5, 0xfb, 0xfb, 0xf7, 0xf6, 0x0f, 0x3e, 0xd8, 0xaf, 0xa5, 0x10, 0x40, 0x61, 0xa7, - 0xd5, 0x6a, 0x1f, 0x76, 0x6b, 0x69, 0xa4, 0x40, 0x7e, 0xa7, 0x79, 0x80, 0xbb, 0xb5, 0x0c, 0x13, - 0xe3, 0xf6, 0x7b, 0xed, 0x56, 0xb7, 0x96, 0x45, 0x6b, 0x50, 0x16, 0x6d, 0xed, 0xee, 0x01, 0x7e, - 0x7f, 0xa7, 0x5b, 0xcb, 0x45, 0x44, 0x47, 0xed, 0xfd, 0x3b, 0x6d, 0x5c, 0xcb, 0xab, 0xaf, 0xb0, - 0x94, 0x30, 0x81, 0x55, 0x85, 0xc9, 0x5f, 0x3a, 0x92, 0xfc, 0xa9, 0xbf, 0xca, 0x40, 0x23, 0x99, - 0x2a, 0xa1, 0xf7, 0xa6, 0x16, 0xbe, 0x7d, 0x01, 0x9e, 0x35, 0xb5, 0x7a, 0xf4, 0x2c, 0x54, 0x5c, - 0x72, 0x4c, 0x68, 0x7f, 0x28, 0xa8, 0x9b, 0x88, 0x98, 0x65, 0x5c, 0x96, 0x52, 0x6e, 0xe4, 0x09, - 0xb5, 0x8f, 0x49, 0x9f, 0x6a, 0x02, 0x8a, 0xc4, 0xa1, 0x53, 0x98, 0x1a, 0x93, 0x1e, 0x09, 0xa1, - 0xfa, 0xd1, 0x85, 0xf6, 0x52, 0x81, 0x3c, 0x6e, 0x77, 0xf1, 0x0f, 0x6b, 0x59, 0x84, 0xa0, 0xc2, - 0x9b, 0xda, 0xd1, 0xfe, 0xce, 0xe1, 0x51, 0xe7, 0x80, 0xed, 0xe5, 0x25, 0xa8, 0xfa, 0x7b, 0xe9, - 0x0b, 0xf3, 0xea, 0x6d, 0xb8, 0x9a, 0xc0, 0xf3, 0x16, 0xe4, 0xbf, 0xea, 0x3f, 0xd3, 0x50, 0x9d, - 0xba, 0x5a, 0x68, 0x1b, 0xf2, 0x22, 0x71, 0x48, 0xfa, 0x88, 0xc2, 0x91, 0x41, 0xde, 0x43, 0xa1, - 0x8a, 0xde, 0x82, 0x12, 0x91, 0x15, 0x9a, 0x79, 0x57, 0x58, 0xa4, 0xc8, 0x7e, 0x0d, 0x47, 0x9a, - 0x06, 0x16, 0xe8, 0x6d, 0x50, 0x02, 0x8c, 0x90, 0xd9, 0xea, 0xd3, 0x73, 0x32, 0x6c, 0x5f, 0x45, - 0xda, 0x87, 0x36, 0xe8, 0x8d, 0x90, 0x26, 0xe6, 0x66, 0xd3, 0x15, 0x69, 0x2e, 0x14, 0xa4, 0xb1, - 0xaf, 0xaf, 0xb6, 0x60, 0x25, 0xb2, 0x1e, 0xf4, 0x14, 0x28, 0x63, 0xfd, 0x54, 0x56, 0xfe, 0x44, - 0xed, 0xa6, 0x34, 0xd6, 0x4f, 0x45, 0xd1, 0xef, 0x2a, 0x14, 0xd9, 0xe0, 0x40, 0xf7, 0x64, 0x95, - 0xa0, 0x30, 0xd6, 0x4f, 0xdf, 0xd5, 0x3d, 0xf5, 0x43, 0xa8, 0xc4, 0xab, 0x5e, 0xec, 0x0c, 0xbb, - 0xf6, 0xc4, 0x32, 0xb8, 0x8f, 0x3c, 0x16, 0x1d, 0xf4, 0x9a, 0x5f, 0x46, 0xc8, 0x24, 0x5c, 0xf6, - 0x07, 0x36, 0x25, 0x91, 0xaa, 0x99, 0xac, 0x27, 0x3c, 0x86, 0x3c, 0x87, 0x2d, 0x06, 0x41, 0xbc, - 0x7e, 0x25, 0x29, 0x32, 0x6b, 0xa3, 0x0f, 0x01, 0x74, 0x4a, 0x5d, 0xb3, 0x37, 0x09, 0x1d, 0x6f, - 0xcc, 0x87, 0xbd, 0x1d, 0x5f, 0xaf, 0x79, 0x4d, 0xe2, 0xdf, 0xe5, 0xd0, 0x34, 0x82, 0x81, 0x11, - 0x87, 0xea, 0x3e, 0x54, 0xe2, 0xb6, 0xd1, 0x4a, 0xf2, 0xea, 0x9c, 0x4a, 0x72, 0x40, 0xc3, 0x02, - 0x12, 0x97, 0x15, 0xb5, 0x4a, 0xde, 0x51, 0x3f, 0x4b, 0x43, 0xa9, 0x7b, 0x2a, 0x2f, 0x44, 0x42, - 0x99, 0x2c, 0x34, 0xcd, 0x44, 0x8b, 0x42, 0xa2, 0xee, 0x96, 0x0d, 0xaa, 0x79, 0xef, 0x04, 0x57, - 0x3e, 0xb7, 0x6c, 0x9a, 0xec, 0x97, 0x35, 0x25, 0xcc, 0xbd, 0x09, 0x4a, 0x70, 0xaa, 0x58, 0xae, - 0xa1, 0x1b, 0x86, 0x4b, 0x3c, 0x4f, 0xae, 0xcd, 0xef, 0xf2, 0xaa, 0xab, 0xfd, 0xa9, 0x2c, 0x3b, - 0x65, 0xb1, 0xe8, 0xa8, 0x06, 0x54, 0xa7, 0x02, 0x1e, 0x7a, 0x13, 0x8a, 0xce, 0xa4, 0xa7, 0xf9, - 0xdb, 0x33, 0x75, 0x79, 0x7c, 0xde, 0x39, 0xe9, 0x8d, 0xcc, 0xfe, 0x3d, 0x72, 0xe6, 0x3f, 0x8c, - 0x33, 0xe9, 0xdd, 0x13, 0xbb, 0x28, 0x66, 0xc9, 0x44, 0x67, 0x39, 0x81, 0x92, 0x7f, 0x28, 0xd0, - 0xff, 0x45, 0xef, 0x89, 0x5f, 0x8b, 0x4f, 0x0c, 0xc2, 0xd2, 0x7d, 0xe4, 0x9a, 0xdc, 0x82, 0x35, - 0xcf, 0x1c, 0x58, 0xc4, 0xd0, 0xc2, 0x6c, 0x87, 0xcf, 0x56, 0xc2, 0x55, 0x31, 0xb0, 0xe7, 0xa7, - 0x3a, 0xea, 0x3f, 0xd2, 0x50, 0xf2, 0x2f, 0x2c, 0x7a, 0x25, 0x72, 0xee, 0x2a, 0x73, 0x4a, 0x42, - 0xbe, 0x62, 0x58, 0x38, 0x8d, 0x3f, 0x6b, 0xe6, 0xe2, 0xcf, 0x9a, 0x54, 0x01, 0xf7, 0x3f, 0x45, - 0xe4, 0x2e, 0xfc, 0x29, 0xe2, 0x25, 0x40, 0xd4, 0xa6, 0xfa, 0x48, 0x3b, 0xb1, 0xa9, 0x69, 0x0d, - 0x34, 0xb1, 0xd9, 0x82, 0x8b, 0xd5, 0xf8, 0xc8, 0x03, 0x3e, 0x70, 0xc8, 0xf7, 0xfd, 0xa7, 0x69, - 0x28, 0x05, 0x51, 0xf5, 0xa2, 0x75, 0xd0, 0x2b, 0x50, 0x90, 0x81, 0x43, 0x14, 0x42, 0x65, 0x2f, - 0x28, 0xc9, 0xe7, 0x22, 0x25, 0xf9, 0x06, 0x94, 0xc6, 0x84, 0xea, 0x1c, 0x9f, 0x45, 0xc2, 0x19, - 0xf4, 0x6f, 0xbd, 0x01, 0x2b, 0x91, 0x92, 0x34, 0xbb, 0x79, 0xfb, 0xed, 0x0f, 0x6a, 0xa9, 0x46, - 0xf1, 0xb3, 0x2f, 0x6e, 0x64, 0xf7, 0xc9, 0xa7, 0xec, 0xcc, 0xe2, 0x76, 0xab, 0xd3, 0x6e, 0xdd, - 0xab, 0xa5, 0x1b, 0x2b, 0x9f, 0x7d, 0x71, 0xa3, 0x88, 0x09, 0xaf, 0x24, 0xdd, 0xea, 0xc0, 0x6a, - 0xf4, 0xad, 0xc4, 0x63, 0x0f, 0x82, 0xca, 0x9d, 0xfb, 0x87, 0x7b, 0xbb, 0xad, 0x9d, 0x6e, 0x5b, - 0x7b, 0x70, 0xd0, 0x6d, 0xd7, 0xd2, 0xe8, 0x2a, 0x5c, 0xda, 0xdb, 0x7d, 0xb7, 0xd3, 0xd5, 0x5a, - 0x7b, 0xbb, 0xed, 0xfd, 0xae, 0xb6, 0xd3, 0xed, 0xee, 0xb4, 0xee, 0xd5, 0x32, 0xdb, 0x7f, 0x05, - 0xa8, 0xee, 0x34, 0x5b, 0xbb, 0x2c, 0x6e, 0x9a, 0x7d, 0x5d, 0x56, 0xea, 0x72, 0x3c, 0xdf, 0x3f, - 0xf7, 0x0b, 0x7b, 0xe3, 0xfc, 0x42, 0x25, 0xba, 0x0b, 0x79, 0x5e, 0x0a, 0x40, 0xe7, 0x7f, 0x72, - 0x6f, 0x2c, 0xa8, 0x5c, 0xb2, 0x87, 0xe1, 0xd7, 0xe3, 0xdc, 0x6f, 0xf0, 0x8d, 0xf3, 0x0b, 0x99, - 0x08, 0x83, 0x12, 0xe6, 0xf2, 0x8b, 0xbf, 0xc9, 0x37, 0x96, 0x28, 0x6e, 0x32, 0x9f, 0x61, 0x42, - 0xb1, 0xf8, 0x1b, 0x75, 0x63, 0x09, 0x00, 0x43, 0x7b, 0x50, 0xf4, 0x73, 0xc0, 0x45, 0x5f, 0xcd, - 0x1b, 0x0b, 0x0b, 0x8f, 0xec, 0x15, 0x88, 0x5c, 0xfd, 0xfc, 0x5f, 0x00, 0x1a, 0x0b, 0xaa, 0xa8, - 0x68, 0x17, 0x0a, 0x92, 0x25, 0x2f, 0xf8, 0x12, 0xde, 0x58, 0x54, 0x48, 0x64, 0x9b, 0x16, 0x16, - 0x41, 0x16, 0xff, 0xd8, 0xd0, 0x58, 0xa2, 0x40, 0x8c, 0xee, 0x03, 0x44, 0x32, 0xf3, 0x25, 0xfe, - 0x58, 0x68, 0x2c, 0x53, 0xf8, 0x45, 0x07, 0x50, 0x0a, 0x12, 0xa5, 0x85, 0xff, 0x0f, 0x34, 0x16, - 0x57, 0x60, 0xd1, 0x43, 0x28, 0xc7, 0x33, 0x84, 0xe5, 0xfe, 0x0a, 0x68, 0x2c, 0x59, 0x5a, 0x65, - 0xfe, 0xe3, 0xe9, 0xc2, 0x72, 0x7f, 0x09, 0x34, 0x96, 0xac, 0xb4, 0xa2, 0x8f, 0x61, 0x6d, 0x96, - 0xce, 0x2f, 0xff, 0xd3, 0x40, 0xe3, 0x02, 0xb5, 0x57, 0x34, 0x06, 0x34, 0x27, 0x0d, 0xb8, 0xc0, - 0x3f, 0x04, 0x8d, 0x8b, 0x94, 0x62, 0x91, 0x01, 0xd5, 0x69, 0x6e, 0xbd, 0xec, 0x3f, 0x05, 0x8d, - 0xa5, 0xcb, 0xb2, 0xcd, 0xf6, 0x97, 0xdf, 0xac, 0xa7, 0xbf, 0xfa, 0x66, 0x3d, 0xfd, 0xe7, 0x6f, - 0xd6, 0xd3, 0x9f, 0x7f, 0xbb, 0x9e, 0xfa, 0xea, 0xdb, 0xf5, 0xd4, 0x1f, 0xbe, 0x5d, 0x4f, 0xfd, - 0xe8, 0xc5, 0x81, 0x49, 0x87, 0x93, 0xde, 0x66, 0xdf, 0x1e, 0x6f, 0x45, 0x7f, 0xa3, 0x9a, 0xf7, - 0x6b, 0x57, 0xaf, 0xc0, 0xc3, 0xe1, 0xab, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x54, 0x3f, 0x72, - 0x96, 0xfa, 0x25, 0x00, 0x00, + // 3097 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcb, 0x77, 0x23, 0xc5, + 0xd5, 0xd7, 0xfb, 0x71, 0x6d, 0x49, 0xed, 0x9a, 0x61, 0x46, 0x88, 0xc1, 0x1e, 0x7a, 0x0e, 0x30, + 0x0c, 0xe0, 0xf9, 0x30, 0x07, 0xbe, 0xe1, 0xf5, 0x81, 0x2d, 0x6b, 0x90, 0xe7, 0x61, 0xf9, 0x2b, + 0xcb, 0xc3, 0xf7, 0x25, 0x61, 0x9a, 0xb6, 0xba, 0x6c, 0x35, 0x23, 0x75, 0x37, 0xdd, 0x25, 0x23, + 0xb3, 0xcc, 0x49, 0x36, 0x64, 0xc3, 0x2e, 0xd9, 0xb0, 0xcc, 0xff, 0x90, 0x45, 0x4e, 0x36, 0x6c, + 0x38, 0x27, 0x1b, 0x96, 0x59, 0xe4, 0x90, 0x1c, 0x58, 0xe4, 0x24, 0xff, 0x40, 0x56, 0x39, 0xc9, + 0xa9, 0x47, 0xbf, 0x24, 0xb5, 0x25, 0x03, 0x27, 0x9b, 0xec, 0xaa, 0x6e, 0xdd, 0x7b, 0xab, 0xeb, + 0xf5, 0xab, 0xdf, 0xbd, 0x5d, 0xf0, 0x04, 0x25, 0x96, 0x41, 0xdc, 0xa1, 0x69, 0xd1, 0x9b, 0xfa, + 0x61, 0xcf, 0xbc, 0x49, 0x4f, 0x1d, 0xe2, 0xad, 0x3b, 0xae, 0x4d, 0x6d, 0x54, 0x0b, 0x1b, 0xd7, + 0x59, 0x63, 0xe3, 0xc9, 0x88, 0x76, 0xcf, 0x3d, 0x75, 0xa8, 0x7d, 0xd3, 0x71, 0x6d, 0xfb, 0x48, + 0xe8, 0x37, 0xae, 0x44, 0x9a, 0xb9, 0x9f, 0xa8, 0xb7, 0x58, 0xab, 0x34, 0x7e, 0x44, 0x4e, 0xfd, + 0xd6, 0x27, 0xa7, 0x6c, 0x1d, 0xdd, 0xd5, 0x87, 0x7e, 0xf3, 0xda, 0xb1, 0x6d, 0x1f, 0x0f, 0xc8, + 0x4d, 0x5e, 0x3b, 0x1c, 0x1d, 0xdd, 0xa4, 0xe6, 0x90, 0x78, 0x54, 0x1f, 0x3a, 0x52, 0xe1, 0xe2, + 0xb1, 0x7d, 0x6c, 0xf3, 0xe2, 0x4d, 0x56, 0x12, 0x52, 0xf5, 0x2f, 0x25, 0x28, 0x62, 0xf2, 0xd1, + 0x88, 0x78, 0x14, 0x6d, 0x40, 0x8e, 0xf4, 0xfa, 0x76, 0x3d, 0x7d, 0x35, 0x7d, 0x7d, 0x69, 0xe3, + 0xca, 0xfa, 0xc4, 0xe0, 0xd6, 0xa5, 0x5e, 0xab, 0xd7, 0xb7, 0xdb, 0x29, 0xcc, 0x75, 0xd1, 0x2b, + 0x90, 0x3f, 0x1a, 0x8c, 0xbc, 0x7e, 0x3d, 0xc3, 0x8d, 0x9e, 0x4c, 0x32, 0xba, 0xcd, 0x94, 0xda, + 0x29, 0x2c, 0xb4, 0x59, 0x57, 0xa6, 0x75, 0x64, 0xd7, 0xb3, 0x67, 0x77, 0xb5, 0x63, 0x1d, 0xf1, + 0xae, 0x98, 0x2e, 0xda, 0x02, 0xf0, 0x08, 0xd5, 0x6c, 0x87, 0x9a, 0xb6, 0x55, 0xcf, 0x71, 0xcb, + 0xa7, 0x92, 0x2c, 0xf7, 0x09, 0xed, 0x70, 0xc5, 0x76, 0x0a, 0x97, 0x3d, 0xbf, 0xc2, 0x7c, 0x98, + 0x96, 0x49, 0xb5, 0x5e, 0x5f, 0x37, 0xad, 0x7a, 0xfe, 0x6c, 0x1f, 0x3b, 0x96, 0x49, 0x9b, 0x4c, + 0x91, 0xf9, 0x30, 0xfd, 0x0a, 0x1b, 0xf2, 0x47, 0x23, 0xe2, 0x9e, 0xd6, 0x0b, 0x67, 0x0f, 0xf9, + 0x7f, 0x99, 0x12, 0x1b, 0x32, 0xd7, 0x46, 0x2d, 0x58, 0x3a, 0x24, 0xc7, 0xa6, 0xa5, 0x1d, 0x0e, + 0xec, 0xde, 0xa3, 0x7a, 0x91, 0x1b, 0xab, 0x49, 0xc6, 0x5b, 0x4c, 0x75, 0x8b, 0x69, 0xb6, 0x53, + 0x18, 0x0e, 0x83, 0x1a, 0x7a, 0x13, 0x4a, 0xbd, 0x3e, 0xe9, 0x3d, 0xd2, 0xe8, 0xb8, 0x5e, 0xe2, + 0x3e, 0xd6, 0x92, 0x7c, 0x34, 0x99, 0x5e, 0x77, 0xdc, 0x4e, 0xe1, 0x62, 0x4f, 0x14, 0xd9, 0xf8, + 0x0d, 0x32, 0x30, 0x4f, 0x88, 0xcb, 0xec, 0xcb, 0x67, 0x8f, 0x7f, 0x5b, 0x68, 0x72, 0x0f, 0x65, + 0xc3, 0xaf, 0xa0, 0xb7, 0xa1, 0x4c, 0x2c, 0x43, 0x0e, 0x03, 0xb8, 0x8b, 0xab, 0x89, 0x7b, 0xc5, + 0x32, 0xfc, 0x41, 0x94, 0x88, 0x2c, 0xa3, 0x5b, 0x50, 0xe8, 0xd9, 0xc3, 0xa1, 0x49, 0xeb, 0x4b, + 0xdc, 0x7a, 0x35, 0x71, 0x00, 0x5c, 0xab, 0x9d, 0xc2, 0x52, 0x1f, 0xed, 0x42, 0x75, 0x60, 0x7a, + 0x54, 0xf3, 0x2c, 0xdd, 0xf1, 0xfa, 0x36, 0xf5, 0xea, 0xcb, 0xdc, 0xc3, 0xd3, 0x49, 0x1e, 0xee, + 0x99, 0x1e, 0xdd, 0xf7, 0x95, 0xdb, 0x29, 0x5c, 0x19, 0x44, 0x05, 0xcc, 0x9f, 0x7d, 0x74, 0x44, + 0xdc, 0xc0, 0x61, 0xbd, 0x72, 0xb6, 0xbf, 0x0e, 0xd3, 0xf6, 0xed, 0x99, 0x3f, 0x3b, 0x2a, 0x40, + 0x3f, 0x86, 0x0b, 0x03, 0x5b, 0x37, 0x02, 0x77, 0x5a, 0xaf, 0x3f, 0xb2, 0x1e, 0xd5, 0xab, 0xdc, + 0xe9, 0x73, 0x89, 0x1f, 0x69, 0xeb, 0x86, 0xef, 0xa2, 0xc9, 0x0c, 0xda, 0x29, 0xbc, 0x32, 0x98, + 0x14, 0xa2, 0x87, 0x70, 0x51, 0x77, 0x9c, 0xc1, 0xe9, 0xa4, 0xf7, 0x1a, 0xf7, 0x7e, 0x23, 0xc9, + 0xfb, 0x26, 0xb3, 0x99, 0x74, 0x8f, 0xf4, 0x29, 0x29, 0xea, 0x82, 0xe2, 0xb8, 0xc4, 0xd1, 0x5d, + 0xa2, 0x39, 0xae, 0xed, 0xd8, 0x9e, 0x3e, 0xa8, 0x2b, 0xdc, 0xf7, 0xb3, 0x49, 0xbe, 0xf7, 0x84, + 0xfe, 0x9e, 0x54, 0x6f, 0xa7, 0x70, 0xcd, 0x89, 0x8b, 0xb6, 0x8a, 0x90, 0x3f, 0xd1, 0x07, 0x23, + 0xa2, 0x3e, 0x0b, 0x4b, 0x11, 0x00, 0x41, 0x75, 0x28, 0x0e, 0x89, 0xe7, 0xe9, 0xc7, 0x84, 0xe3, + 0x4d, 0x19, 0xfb, 0x55, 0xb5, 0x0a, 0xcb, 0x51, 0xd0, 0x50, 0x87, 0x81, 0x21, 0x83, 0x03, 0x66, + 0x78, 0x42, 0x5c, 0x8f, 0x61, 0x80, 0x34, 0x94, 0x55, 0x74, 0x0d, 0x2a, 0x7c, 0x53, 0x6a, 0x7e, + 0x3b, 0xc3, 0xa4, 0x1c, 0x5e, 0xe6, 0xc2, 0x07, 0x52, 0x69, 0x0d, 0x96, 0x9c, 0x0d, 0x27, 0x50, + 0xc9, 0x72, 0x15, 0x70, 0x36, 0x1c, 0xa9, 0xa0, 0xbe, 0x0e, 0xca, 0x24, 0x86, 0x20, 0x05, 0xb2, + 0x8f, 0xc8, 0xa9, 0xec, 0x8f, 0x15, 0xd1, 0x45, 0x39, 0x2c, 0xde, 0x47, 0x19, 0xcb, 0x31, 0xfe, + 0x3e, 0x13, 0x18, 0x07, 0xe0, 0x81, 0x6e, 0x41, 0x8e, 0x61, 0xb1, 0x84, 0xd5, 0xc6, 0xba, 0x00, + 0xea, 0x75, 0x1f, 0xa8, 0xd7, 0xbb, 0x3e, 0x50, 0x6f, 0x95, 0xbe, 0xfc, 0x7a, 0x2d, 0xf5, 0xd9, + 0x9f, 0xd6, 0xd2, 0x98, 0x5b, 0xa0, 0xc7, 0xd9, 0x59, 0xd7, 0x4d, 0x4b, 0x33, 0x0d, 0xd9, 0x4f, + 0x91, 0xd7, 0x77, 0x0c, 0x74, 0x17, 0x94, 0x9e, 0x6d, 0x79, 0xc4, 0xf2, 0x46, 0x9e, 0x26, 0x2e, + 0x02, 0x09, 0xa6, 0xd3, 0x67, 0xb1, 0xe9, 0x2b, 0xee, 0x71, 0x3d, 0x5c, 0xeb, 0xc5, 0x05, 0xe8, + 0x36, 0xc0, 0x89, 0x3e, 0x30, 0x0d, 0x9d, 0xda, 0xae, 0x57, 0xcf, 0x5d, 0xcd, 0xce, 0x74, 0xf3, + 0xc0, 0x57, 0x39, 0x70, 0x0c, 0x9d, 0x92, 0xad, 0x1c, 0xfb, 0x5a, 0x1c, 0xb1, 0x44, 0xcf, 0x40, + 0x4d, 0x77, 0x1c, 0xcd, 0xa3, 0x3a, 0x25, 0xda, 0xe1, 0x29, 0x25, 0x1e, 0x87, 0xd8, 0x65, 0x5c, + 0xd1, 0x1d, 0x67, 0x9f, 0x49, 0xb7, 0x98, 0x10, 0x3d, 0x0d, 0x55, 0x06, 0xa7, 0xa6, 0x3e, 0xd0, + 0xfa, 0xc4, 0x3c, 0xee, 0x53, 0x0e, 0xa5, 0x59, 0x5c, 0x91, 0xd2, 0x36, 0x17, 0xaa, 0x46, 0xb0, + 0x11, 0x38, 0x94, 0x22, 0x04, 0x39, 0x43, 0xa7, 0x3a, 0x9f, 0xc8, 0x65, 0xcc, 0xcb, 0x4c, 0xe6, + 0xe8, 0xb4, 0x2f, 0xa7, 0x87, 0x97, 0xd1, 0x25, 0x28, 0x48, 0xb7, 0x59, 0xee, 0x56, 0xd6, 0xd8, + 0x9a, 0x39, 0xae, 0x7d, 0x42, 0xf8, 0xdd, 0x51, 0xc2, 0xa2, 0xa2, 0xfe, 0x2c, 0x03, 0x2b, 0x53, + 0xa0, 0xcb, 0xfc, 0xf6, 0x75, 0xaf, 0xef, 0xf7, 0xc5, 0xca, 0xe8, 0x55, 0xe6, 0x57, 0x37, 0x88, + 0x2b, 0x2f, 0xbb, 0x7a, 0x74, 0x8a, 0xc4, 0x45, 0xde, 0xe6, 0xed, 0x72, 0x6a, 0xa4, 0x36, 0xea, + 0x80, 0x32, 0xd0, 0x3d, 0xaa, 0x09, 0x10, 0xd3, 0x22, 0x17, 0xdf, 0x34, 0x74, 0xdf, 0xd3, 0x7d, + 0xd8, 0x63, 0x9b, 0x5d, 0x3a, 0xaa, 0x0e, 0x62, 0x52, 0x84, 0xe1, 0xe2, 0xe1, 0xe9, 0x27, 0xba, + 0x45, 0x4d, 0x8b, 0x68, 0x53, 0x2b, 0xf7, 0xf8, 0x94, 0xd3, 0xd6, 0x89, 0x69, 0x10, 0xab, 0xe7, + 0x2f, 0xd9, 0x85, 0xc0, 0x38, 0x58, 0x52, 0x4f, 0xc5, 0x50, 0x8d, 0x5f, 0x1b, 0xa8, 0x0a, 0x19, + 0x3a, 0x96, 0x13, 0x90, 0xa1, 0x63, 0xf4, 0x5f, 0x90, 0x63, 0x83, 0xe4, 0x83, 0xaf, 0xce, 0xb8, + 0xb3, 0xa5, 0x5d, 0xf7, 0xd4, 0x21, 0x98, 0x6b, 0xaa, 0x6a, 0x70, 0x1a, 0x82, 0xab, 0x64, 0xd2, + 0xab, 0xfa, 0x1c, 0xd4, 0x26, 0xee, 0x8a, 0xc8, 0xfa, 0xa5, 0xa3, 0xeb, 0xa7, 0xd6, 0xa0, 0x12, + 0xbb, 0x18, 0xd4, 0x4b, 0x70, 0x71, 0x16, 0xce, 0xab, 0xfd, 0x40, 0x1e, 0xc3, 0x6b, 0xf4, 0x0a, + 0x94, 0x02, 0xa0, 0x17, 0xa7, 0x71, 0x7a, 0xae, 0x7c, 0x65, 0x1c, 0xa8, 0xb2, 0x63, 0xc8, 0xb6, + 0x35, 0xdf, 0x0f, 0x19, 0xfe, 0xe1, 0x45, 0xdd, 0x71, 0xda, 0xba, 0xd7, 0x57, 0x3f, 0x80, 0x7a, + 0x12, 0x88, 0x4f, 0x0c, 0x23, 0x17, 0x6c, 0xc3, 0x4b, 0x50, 0x38, 0xb2, 0xdd, 0xa1, 0x4e, 0xb9, + 0xb3, 0x0a, 0x96, 0x35, 0xb6, 0x3d, 0x05, 0xa0, 0x67, 0xb9, 0x58, 0x54, 0x54, 0x0d, 0x1e, 0x4f, + 0x04, 0x72, 0x66, 0x62, 0x5a, 0x06, 0x11, 0xf3, 0x59, 0xc1, 0xa2, 0x12, 0x3a, 0x12, 0x1f, 0x2b, + 0x2a, 0xac, 0x5b, 0x8f, 0x8f, 0x95, 0xfb, 0x2f, 0x63, 0x59, 0x53, 0xbf, 0xc8, 0xc0, 0xa5, 0xd9, + 0x70, 0xfe, 0x83, 0x1e, 0x02, 0x05, 0xb2, 0x74, 0xcc, 0x30, 0x2a, 0x7b, 0x7d, 0x19, 0xb3, 0x22, + 0x3a, 0x80, 0x95, 0x81, 0xdd, 0xd3, 0x07, 0x5a, 0xe4, 0x70, 0x48, 0x5a, 0x77, 0x6d, 0x7a, 0x0b, + 0x8f, 0xb9, 0xc4, 0x98, 0x3a, 0x1b, 0x35, 0xee, 0x23, 0x3c, 0x36, 0x89, 0x87, 0x23, 0xff, 0xdd, + 0x0f, 0x07, 0xba, 0x0a, 0xcb, 0x43, 0x7d, 0xac, 0xd1, 0xb1, 0x44, 0x35, 0x01, 0x57, 0x30, 0xd4, + 0xc7, 0xdd, 0x31, 0x87, 0x34, 0xf5, 0xb7, 0x65, 0x28, 0x61, 0xe2, 0x39, 0x0c, 0x59, 0xd1, 0x16, + 0x94, 0xc9, 0xb8, 0x47, 0x04, 0x51, 0x4d, 0x27, 0x12, 0x3d, 0xa1, 0xdd, 0xf2, 0x35, 0x19, 0xcb, + 0x0a, 0xcc, 0xd0, 0xcb, 0x92, 0x8c, 0x27, 0xf3, 0x6a, 0x69, 0x1e, 0x65, 0xe3, 0xaf, 0xfa, 0x6c, + 0x3c, 0x9b, 0x48, 0xac, 0x84, 0xd5, 0x04, 0x1d, 0x7f, 0x59, 0xd2, 0xf1, 0xdc, 0x9c, 0xce, 0x62, + 0x7c, 0xbc, 0x19, 0xe3, 0xe3, 0xf9, 0x39, 0xc3, 0x4c, 0x20, 0xe4, 0xcd, 0x18, 0x21, 0x2f, 0xcc, + 0x71, 0x92, 0xc0, 0xc8, 0x5f, 0xf5, 0x19, 0x79, 0x71, 0xce, 0xb0, 0x27, 0x28, 0xf9, 0xed, 0x38, + 0x25, 0x2f, 0x25, 0xec, 0x3d, 0xdf, 0x3a, 0x91, 0x93, 0xbf, 0x15, 0xe1, 0xe4, 0xe5, 0x44, 0x42, + 0x2c, 0x9c, 0xcc, 0x20, 0xe5, 0xcd, 0x18, 0x29, 0x87, 0x39, 0x73, 0x90, 0xc0, 0xca, 0xdf, 0x89, + 0xb2, 0xf2, 0xa5, 0x44, 0x62, 0x2f, 0x37, 0xcd, 0x2c, 0x5a, 0xfe, 0x5a, 0x40, 0xcb, 0x97, 0x13, + 0xe3, 0x0a, 0x39, 0x86, 0x49, 0x5e, 0xde, 0x99, 0xe2, 0xe5, 0x82, 0x47, 0x3f, 0x93, 0xe8, 0x62, + 0x0e, 0x31, 0xef, 0x4c, 0x11, 0xf3, 0xea, 0x1c, 0x87, 0x73, 0x98, 0xf9, 0x4f, 0x66, 0x33, 0xf3, + 0x64, 0xee, 0x2c, 0x3f, 0x73, 0x31, 0x6a, 0xae, 0x25, 0x50, 0x73, 0x41, 0x9f, 0x9f, 0x4f, 0x74, + 0xbf, 0x30, 0x37, 0x3f, 0x98, 0xc1, 0xcd, 0x57, 0xb8, 0xf3, 0xeb, 0x89, 0xce, 0xcf, 0x43, 0xce, + 0x9f, 0x63, 0x1c, 0x68, 0x02, 0x8f, 0xd8, 0x3d, 0x42, 0x5c, 0xd7, 0x76, 0x25, 0xef, 0x15, 0x15, + 0xf5, 0x3a, 0x63, 0x65, 0x21, 0xf6, 0x9c, 0x41, 0xe4, 0xf9, 0x7d, 0x1d, 0xc1, 0x1b, 0xf5, 0x37, + 0xe9, 0xd0, 0x96, 0x13, 0x99, 0x28, 0xa3, 0x2b, 0x4b, 0x46, 0x17, 0xe1, 0xf7, 0x99, 0x38, 0xbf, + 0x5f, 0x83, 0x25, 0x76, 0x0f, 0x4f, 0x50, 0x77, 0xdd, 0xf1, 0xa9, 0x3b, 0xba, 0x01, 0x2b, 0xfc, + 0x2e, 0x11, 0x51, 0x80, 0xbc, 0x7c, 0x73, 0x1c, 0xab, 0x6b, 0xac, 0x41, 0xec, 0x79, 0x71, 0x0b, + 0xbf, 0x08, 0x17, 0x22, 0xba, 0xc1, 0xfd, 0x2e, 0xf8, 0xaa, 0x12, 0x68, 0x6f, 0xca, 0x8b, 0xfe, + 0x7e, 0x38, 0x41, 0x61, 0x58, 0x80, 0x20, 0xd7, 0xb3, 0x0d, 0x22, 0x6f, 0x5f, 0x5e, 0x66, 0xf7, + 0xdc, 0xc0, 0x3e, 0x96, 0x77, 0x2c, 0x2b, 0x32, 0xad, 0x00, 0x5c, 0xcb, 0x02, 0x3b, 0xd5, 0x2f, + 0xd2, 0xa1, 0xbf, 0x30, 0x52, 0x98, 0x45, 0xea, 0xd3, 0x3f, 0x0c, 0xa9, 0xcf, 0x7c, 0x67, 0x52, + 0x1f, 0x65, 0x3f, 0xd9, 0x38, 0xfb, 0xf9, 0x7b, 0x3a, 0x5c, 0xe1, 0x80, 0xa2, 0x7f, 0xb7, 0x19, + 0x09, 0xa9, 0x4c, 0x9e, 0xaf, 0x97, 0xa4, 0x32, 0x32, 0xf0, 0x2a, 0xf0, 0x7e, 0xe3, 0x81, 0x57, + 0x51, 0x90, 0x1b, 0x5e, 0x41, 0xb7, 0xa0, 0xcc, 0xf3, 0x6c, 0x9a, 0xed, 0x78, 0x12, 0xc7, 0x9f, + 0x88, 0x8e, 0x55, 0xa4, 0xd3, 0xd6, 0xf7, 0x98, 0x4e, 0xc7, 0xf1, 0x70, 0xc9, 0x91, 0xa5, 0x08, + 0x4b, 0x2b, 0xc7, 0x82, 0x85, 0x2b, 0x50, 0x66, 0x5f, 0xef, 0x39, 0x7a, 0x8f, 0x70, 0x4c, 0x2e, + 0xe3, 0x50, 0xa0, 0x3e, 0x04, 0x34, 0x7d, 0x2b, 0xa0, 0x36, 0x14, 0xc8, 0x09, 0xb1, 0x28, 0x5b, + 0x35, 0x36, 0xdd, 0x97, 0x66, 0x90, 0x0d, 0x62, 0xd1, 0xad, 0x3a, 0x9b, 0xe4, 0xbf, 0x7d, 0xbd, + 0xa6, 0x08, 0xed, 0x17, 0xec, 0xa1, 0x49, 0xc9, 0xd0, 0xa1, 0xa7, 0x58, 0xda, 0xab, 0x7f, 0xcc, + 0x30, 0x5a, 0x1c, 0xbb, 0x31, 0x66, 0xce, 0xad, 0x7f, 0x80, 0x32, 0x91, 0x90, 0x68, 0xb1, 0xf9, + 0x5e, 0x05, 0x38, 0xd6, 0x3d, 0xed, 0x63, 0xdd, 0xa2, 0xc4, 0x90, 0x93, 0x1e, 0x91, 0xa0, 0x06, + 0x94, 0x58, 0x6d, 0xe4, 0x11, 0x43, 0xd2, 0x9d, 0xa0, 0x1e, 0x19, 0x67, 0xf1, 0xfb, 0x8d, 0x33, + 0x3e, 0xcb, 0xa5, 0x89, 0x59, 0x8e, 0x50, 0xd6, 0x72, 0x94, 0xb2, 0xb2, 0x6f, 0x73, 0x5c, 0xd3, + 0x76, 0x4d, 0x7a, 0xca, 0x97, 0x26, 0x8b, 0x83, 0x3a, 0xba, 0x06, 0x95, 0x21, 0x19, 0x3a, 0xb6, + 0x3d, 0xd0, 0x04, 0x78, 0x2d, 0x71, 0xd3, 0x65, 0x29, 0x6c, 0x71, 0x0c, 0xfb, 0x79, 0x26, 0x3c, + 0x7e, 0x61, 0x68, 0xf2, 0x1f, 0x37, 0xc1, 0xea, 0x2f, 0x78, 0xbe, 0x22, 0xce, 0x09, 0xd0, 0x3e, + 0xac, 0x04, 0xc7, 0x5f, 0x1b, 0x71, 0x58, 0xf0, 0x37, 0xf4, 0xa2, 0xf8, 0xa1, 0x9c, 0xc4, 0xc5, + 0x1e, 0xfa, 0x3f, 0xb8, 0x3c, 0x01, 0x6d, 0x81, 0xeb, 0xcc, 0x82, 0x08, 0xf7, 0x58, 0x1c, 0xe1, + 0x7c, 0xcf, 0xe1, 0x5c, 0x65, 0xbf, 0xe7, 0xa1, 0xdb, 0x61, 0x21, 0x70, 0x94, 0xe1, 0xcc, 0x5c, + 0xfd, 0x6b, 0x50, 0x71, 0x09, 0xd5, 0x4d, 0x4b, 0x8b, 0x25, 0x19, 0x96, 0x85, 0x50, 0xa6, 0x2e, + 0xf6, 0xe0, 0xb1, 0x99, 0x4c, 0x07, 0xfd, 0x37, 0x94, 0x43, 0x92, 0x94, 0x4e, 0x08, 0x49, 0x82, + 0x18, 0x34, 0xd4, 0x55, 0x7f, 0x97, 0x0e, 0x5d, 0xc6, 0xa3, 0xda, 0x16, 0x14, 0x5c, 0xe2, 0x8d, + 0x06, 0x22, 0xce, 0xac, 0x6e, 0xbc, 0xb8, 0x18, 0x47, 0x62, 0xd2, 0xd1, 0x80, 0x62, 0x69, 0xac, + 0x3e, 0x84, 0x82, 0x90, 0xa0, 0x25, 0x28, 0x1e, 0xec, 0xde, 0xdd, 0xed, 0xbc, 0xb7, 0xab, 0xa4, + 0x10, 0x40, 0x61, 0xb3, 0xd9, 0x6c, 0xed, 0x75, 0x95, 0x34, 0x2a, 0x43, 0x7e, 0x73, 0xab, 0x83, + 0xbb, 0x4a, 0x86, 0x89, 0x71, 0xeb, 0x4e, 0xab, 0xd9, 0x55, 0xb2, 0x68, 0x05, 0x2a, 0xa2, 0xac, + 0xdd, 0xee, 0xe0, 0xfb, 0x9b, 0x5d, 0x25, 0x17, 0x11, 0xed, 0xb7, 0x76, 0xb7, 0x5b, 0x58, 0xc9, + 0xab, 0x2f, 0xb1, 0x40, 0x36, 0x81, 0x55, 0x85, 0x21, 0x6b, 0x3a, 0x12, 0xb2, 0xaa, 0xbf, 0xca, + 0x40, 0x23, 0x99, 0x2a, 0xa1, 0x3b, 0x13, 0x03, 0xdf, 0x38, 0x07, 0xcf, 0x9a, 0x18, 0x3d, 0x7a, + 0x1a, 0xaa, 0x2e, 0x39, 0x22, 0xb4, 0xd7, 0x17, 0xd4, 0x4d, 0xdc, 0x98, 0x15, 0x5c, 0x91, 0x52, + 0x6e, 0xe4, 0x09, 0xb5, 0x0f, 0x49, 0x8f, 0x6a, 0x02, 0x8a, 0xc4, 0xa6, 0x2b, 0x33, 0x35, 0x26, + 0xdd, 0x17, 0x42, 0xf5, 0x83, 0x73, 0xcd, 0x65, 0x19, 0xf2, 0xb8, 0xd5, 0xc5, 0xff, 0xaf, 0x64, + 0x11, 0x82, 0x2a, 0x2f, 0x6a, 0xfb, 0xbb, 0x9b, 0x7b, 0xfb, 0xed, 0x0e, 0x9b, 0xcb, 0x0b, 0x50, + 0xf3, 0xe7, 0xd2, 0x17, 0xe6, 0x55, 0x0a, 0x97, 0x13, 0x78, 0x1e, 0xa3, 0x49, 0x43, 0xdb, 0x30, + 0x8f, 0x4c, 0x62, 0x68, 0x32, 0xd5, 0x52, 0xc2, 0xe0, 0x8b, 0xba, 0x63, 0x74, 0x0b, 0x80, 0x8e, + 0x35, 0x97, 0xf4, 0x6c, 0xd7, 0xf0, 0x99, 0xc1, 0xf4, 0x26, 0xec, 0x8e, 0x31, 0xd7, 0xc0, 0x65, + 0x2a, 0x4b, 0x9e, 0xfa, 0xcf, 0x34, 0xd4, 0x26, 0x8e, 0x25, 0xda, 0x80, 0xbc, 0x08, 0x3a, 0x92, + 0x7e, 0x1b, 0x71, 0x54, 0x91, 0x67, 0x58, 0xa8, 0xa2, 0x37, 0xa1, 0x44, 0x64, 0xd8, 0x3d, 0xeb, + 0xf8, 0x8b, 0x34, 0x82, 0x1f, 0x98, 0x4b, 0xd3, 0xc0, 0x02, 0xbd, 0x0d, 0xe5, 0x00, 0x5f, 0x64, + 0xa4, 0xfb, 0xd4, 0xb4, 0x79, 0x80, 0x4c, 0xd2, 0x3e, 0xb4, 0x41, 0xaf, 0x85, 0x14, 0x33, 0x37, + 0x1d, 0xea, 0x48, 0x73, 0xa1, 0x20, 0x8d, 0x7d, 0x7d, 0xb5, 0x09, 0x4b, 0x91, 0xf1, 0xa0, 0x27, + 0xa0, 0x3c, 0xd4, 0xfd, 0xac, 0x80, 0xc8, 0x56, 0x95, 0x86, 0xba, 0xc8, 0x09, 0xa0, 0xcb, 0x50, + 0x64, 0x8d, 0xc7, 0xba, 0xc0, 0xb8, 0x2c, 0x2e, 0x0c, 0xf5, 0xf1, 0xbb, 0xba, 0xa7, 0xbe, 0x0f, + 0xd5, 0x78, 0x9e, 0x8f, 0xed, 0x7f, 0xd7, 0x1e, 0x59, 0x06, 0xf7, 0x91, 0xc7, 0xa2, 0x82, 0x5e, + 0x81, 0xfc, 0x89, 0x2d, 0x20, 0x72, 0xf6, 0x1a, 0x3d, 0xb0, 0x29, 0x89, 0xe4, 0x42, 0x84, 0xb6, + 0x6a, 0x02, 0x9a, 0x4e, 0x97, 0x24, 0x74, 0xf1, 0x56, 0xbc, 0x8b, 0xa7, 0x12, 0x13, 0x2f, 0xb3, + 0xbb, 0xfa, 0x04, 0xf2, 0x1c, 0x5d, 0x19, 0x52, 0xf2, 0xe4, 0xa0, 0x64, 0xf2, 0xac, 0x8c, 0xde, + 0x07, 0xd0, 0x29, 0x75, 0xcd, 0xc3, 0x51, 0xd8, 0xc1, 0xda, 0x6c, 0x74, 0xde, 0xf4, 0xf5, 0xb6, + 0xae, 0x48, 0x98, 0xbe, 0x18, 0x9a, 0x46, 0xa0, 0x3a, 0xe2, 0x50, 0xdd, 0x85, 0x6a, 0xdc, 0x36, + 0x9a, 0xa6, 0x5f, 0x9e, 0x91, 0xa6, 0x0f, 0xd8, 0x62, 0xc0, 0x35, 0xb3, 0x22, 0x11, 0xcc, 0x2b, + 0xea, 0xa7, 0x69, 0x28, 0xb1, 0x4d, 0xcf, 0xcf, 0x6d, 0x42, 0x0e, 0x32, 0x34, 0xcd, 0x44, 0x33, + 0x6e, 0x22, 0xa9, 0x99, 0x0d, 0x52, 0xa5, 0xef, 0x04, 0xc8, 0x94, 0x5b, 0x34, 0x9a, 0xf7, 0xd3, + 0x65, 0x12, 0x8d, 0x7f, 0x29, 0x3f, 0x86, 0x9d, 0x3b, 0xf4, 0x3a, 0x14, 0xf4, 0x5e, 0x90, 0x4c, + 0xaa, 0xce, 0x70, 0xe7, 0xab, 0xae, 0x77, 0xc7, 0x9b, 0x5c, 0x13, 0x4b, 0x0b, 0xf9, 0x69, 0x99, + 0x20, 0xdf, 0xfa, 0x36, 0xf3, 0x2b, 0x74, 0xe2, 0xe0, 0x54, 0x05, 0x38, 0xd8, 0xbd, 0xdf, 0xd9, + 0xde, 0xb9, 0xbd, 0xd3, 0xda, 0x96, 0x00, 0xb5, 0xbd, 0xdd, 0xda, 0x56, 0x32, 0x4c, 0x0f, 0xb7, + 0xee, 0x77, 0x1e, 0xb4, 0xb6, 0x95, 0xac, 0xfa, 0x06, 0x94, 0x83, 0xa3, 0xc5, 0x82, 0x35, 0xdd, + 0x30, 0x5c, 0xe2, 0x79, 0x72, 0xd6, 0xfd, 0x2a, 0x4f, 0xb6, 0xdb, 0x1f, 0xcb, 0x6c, 0x63, 0x16, + 0x8b, 0x8a, 0x6a, 0x40, 0x6d, 0x82, 0x31, 0xa0, 0x37, 0xa0, 0xe8, 0x8c, 0x0e, 0x35, 0x7f, 0xe1, + 0x26, 0x10, 0xc4, 0x27, 0xee, 0xa3, 0xc3, 0x81, 0xd9, 0xbb, 0x4b, 0x4e, 0xfd, 0x69, 0x72, 0x46, + 0x87, 0x77, 0xc5, 0xfa, 0x8a, 0x5e, 0x32, 0xd1, 0x5e, 0x7e, 0x9a, 0x86, 0x92, 0xbf, 0x5f, 0xd1, + 0xff, 0x44, 0xd1, 0xc2, 0xff, 0x07, 0x93, 0x48, 0x63, 0xa4, 0xff, 0x08, 0x58, 0xdc, 0x80, 0x15, + 0xcf, 0x3c, 0xb6, 0x88, 0xa1, 0x85, 0xf1, 0x22, 0xef, 0xae, 0x84, 0x6b, 0xa2, 0xe1, 0x9e, 0x1f, + 0x2c, 0xde, 0xc9, 0x95, 0xb2, 0x4a, 0xee, 0x4e, 0xae, 0x94, 0x53, 0xf2, 0xea, 0xaf, 0xd3, 0xa0, + 0x4c, 0x1e, 0x9e, 0x7f, 0xe7, 0xc7, 0xb0, 0xbb, 0x8a, 0x1d, 0x52, 0x8d, 0xb0, 0x8f, 0x08, 0x22, + 0xe6, 0x65, 0x5c, 0x61, 0xd2, 0x96, 0x2f, 0x54, 0xff, 0x91, 0x86, 0x92, 0x0f, 0xb5, 0xe8, 0xa5, + 0xc8, 0x31, 0xae, 0xce, 0x48, 0x04, 0xfa, 0x8a, 0x61, 0x92, 0x3f, 0x3e, 0xa4, 0xcc, 0xf9, 0x87, + 0x94, 0xf4, 0xb7, 0xc6, 0xff, 0x6d, 0x96, 0x3b, 0xf7, 0x6f, 0xb3, 0x17, 0x00, 0x51, 0x9b, 0xea, + 0x03, 0xed, 0xc4, 0xa6, 0xa6, 0x75, 0xac, 0x89, 0x1d, 0x22, 0x18, 0xb8, 0xc2, 0x5b, 0x1e, 0xf0, + 0x86, 0xbd, 0x60, 0xb3, 0x04, 0x5c, 0xea, 0xbc, 0x39, 0xfb, 0x4b, 0x50, 0x90, 0x74, 0x41, 0x24, + 0xed, 0x65, 0x2d, 0xc8, 0x9c, 0xe7, 0x22, 0x99, 0xf3, 0x06, 0x94, 0x86, 0x84, 0xea, 0x9c, 0x50, + 0x8a, 0x34, 0x43, 0x50, 0xbf, 0xf1, 0x1a, 0x2c, 0x45, 0x7e, 0x9f, 0x30, 0x20, 0xdb, 0x6d, 0xbd, + 0xa7, 0xa4, 0x1a, 0xc5, 0x4f, 0x3f, 0xbf, 0x9a, 0xdd, 0x25, 0x1f, 0xb3, 0x83, 0x86, 0x5b, 0xcd, + 0x76, 0xab, 0x79, 0x57, 0x49, 0x37, 0x96, 0x3e, 0xfd, 0xfc, 0x6a, 0x11, 0x13, 0x9e, 0x3f, 0xbc, + 0xd1, 0x86, 0xe5, 0xe8, 0xaa, 0xc4, 0x0f, 0x35, 0x82, 0xea, 0xf6, 0xc1, 0xde, 0xbd, 0x9d, 0xe6, + 0x66, 0xb7, 0xa5, 0x3d, 0xe8, 0x74, 0x5b, 0x4a, 0x1a, 0x5d, 0x86, 0x0b, 0xf7, 0x76, 0xde, 0x6d, + 0x77, 0xb5, 0xe6, 0xbd, 0x9d, 0xd6, 0x6e, 0x57, 0xdb, 0xec, 0x76, 0x37, 0x9b, 0x77, 0x95, 0xcc, + 0xc6, 0x5f, 0x01, 0x6a, 0x9b, 0x5b, 0xcd, 0x1d, 0xc6, 0x96, 0xcc, 0x9e, 0x2e, 0xf3, 0xb3, 0x39, + 0x9e, 0xe5, 0x39, 0xf3, 0x35, 0x48, 0xe3, 0xec, 0xf4, 0x34, 0xba, 0x0d, 0x79, 0x9e, 0x00, 0x42, + 0x67, 0x3f, 0x0f, 0x69, 0xcc, 0xc9, 0x57, 0xb3, 0x8f, 0xe1, 0xa7, 0xe8, 0xcc, 0xf7, 0x22, 0x8d, + 0xb3, 0xd3, 0xd7, 0x08, 0x43, 0x39, 0xcc, 0xe0, 0xcc, 0x7f, 0x3f, 0xd2, 0x58, 0x20, 0xa5, 0xcd, + 0x7c, 0x86, 0x61, 0xe4, 0xfc, 0xf7, 0x14, 0x8d, 0x05, 0xee, 0x03, 0x74, 0x0f, 0x8a, 0x7e, 0xe4, + 0x3f, 0xef, 0x85, 0x47, 0x63, 0x6e, 0xba, 0x99, 0x2d, 0x81, 0xc8, 0xd0, 0x9c, 0xfd, 0x5c, 0xa5, + 0x31, 0x27, 0x77, 0x8e, 0x76, 0xa0, 0x20, 0x63, 0xa3, 0x39, 0xaf, 0x36, 0x1a, 0xf3, 0xd2, 0xc7, + 0x6c, 0xd2, 0xc2, 0xd4, 0xd7, 0xfc, 0x47, 0x38, 0x8d, 0x05, 0x7e, 0x0b, 0xa0, 0x03, 0x80, 0x48, + 0x3e, 0x66, 0x81, 0xd7, 0x35, 0x8d, 0x45, 0xd2, 0xfd, 0xa8, 0x03, 0xa5, 0x20, 0x3c, 0x9e, 0xfb, + 0xd6, 0xa5, 0x31, 0x3f, 0xef, 0x8e, 0x1e, 0x42, 0x25, 0x1e, 0x17, 0x2e, 0xf6, 0x82, 0xa5, 0xb1, + 0x60, 0x42, 0x9d, 0xf9, 0x8f, 0x07, 0x89, 0x8b, 0xbd, 0x68, 0x69, 0x2c, 0x98, 0x5f, 0x47, 0x1f, + 0xc2, 0xca, 0x74, 0x10, 0xb7, 0xf8, 0x03, 0x97, 0xc6, 0x39, 0x32, 0xee, 0x68, 0x08, 0x68, 0x46, + 0xf0, 0x77, 0x8e, 0xf7, 0x2e, 0x8d, 0xf3, 0x24, 0xe0, 0x91, 0x01, 0xb5, 0xc9, 0x88, 0x6a, 0xd1, + 0xf7, 0x2f, 0x8d, 0x85, 0x93, 0xf1, 0x5b, 0xad, 0x2f, 0xbf, 0x59, 0x4d, 0x7f, 0xf5, 0xcd, 0x6a, + 0xfa, 0xcf, 0xdf, 0xac, 0xa6, 0x3f, 0xfb, 0x76, 0x35, 0xf5, 0xd5, 0xb7, 0xab, 0xa9, 0x3f, 0x7c, + 0xbb, 0x9a, 0xfa, 0xd1, 0xf3, 0xc7, 0x26, 0xed, 0x8f, 0x0e, 0xd7, 0x7b, 0xf6, 0xf0, 0x66, 0xf4, + 0xc9, 0xdf, 0xac, 0x67, 0x88, 0x87, 0x05, 0x7e, 0x1d, 0xbe, 0xfc, 0xaf, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xf8, 0x2c, 0x9d, 0xd4, 0xa6, 0x28, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5142,10 +5382,15 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.Votes) > 0 { - for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + if m.MaxTxBytes != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.MaxTxBytes)) + i-- + dAtA[i] = 0x30 + } + if len(m.ByzantineValidators) > 0 { + for iNdEx := len(m.ByzantineValidators) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.ByzantineValidators[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -5153,22 +5398,44 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- + dAtA[i] = 0x2a + } + } + { + size, err := m.LocalLastCommit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Txs[iNdEx]) + copy(dAtA[i:], m.Txs[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Txs[iNdEx]))) + i-- dAtA[i] = 0x1a } } - if m.BlockDataSize != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) - i-- - dAtA[i] = 0x10 - } - if len(m.BlockData) > 0 { - for iNdEx := len(m.BlockData) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.BlockData[iNdEx]) - copy(dAtA[i:], m.BlockData[iNdEx]) - i = encodeVarintTypes(dAtA, i, uint64(len(m.BlockData[iNdEx]))) - i-- - dAtA[i] = 0xa + { + size, err := m.Header.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -6325,20 +6592,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA43 := make([]byte, len(m.RefetchChunks)*10) - var j42 int + dAtA45 := make([]byte, len(m.RefetchChunks)*10) + var j44 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA43[j42] = uint8(uint64(num)&0x7f | 0x80) + dAtA45[j44] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j42++ + j44++ } - dAtA43[j42] = uint8(num) - j42++ + dAtA45[j44] = uint8(num) + j44++ } - i -= j42 - copy(dAtA[i:], dAtA43[:j42]) - i = encodeVarintTypes(dAtA, i, uint64(j42)) + i -= j44 + copy(dAtA[i:], dAtA45[:j44]) + i = encodeVarintTypes(dAtA, i, uint64(j44)) i-- dAtA[i] = 0x12 } @@ -6370,15 +6637,30 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.BlockData) > 0 { - for iNdEx := len(m.BlockData) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.BlockData[iNdEx]) - copy(dAtA[i:], m.BlockData[iNdEx]) - i = encodeVarintTypes(dAtA, i, uint64(len(m.BlockData[iNdEx]))) + if len(m.TxRecords) > 0 { + for iNdEx := len(m.TxRecords) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxRecords[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 } } + if m.ModifiedTx { + i-- + if m.ModifiedTx { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -6528,6 +6810,48 @@ func (m *LastCommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExtendedCommitInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtendedCommitInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtendedCommitInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Votes) > 0 { + for iNdEx := len(m.Votes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Votes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Round != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Round)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *Event) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6669,6 +6993,41 @@ func (m *TxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TxRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Tx) > 0 { + i -= len(m.Tx) + copy(dAtA[i:], m.Tx) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Tx))) + i-- + dAtA[i] = 0x12 + } + if m.Action != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Action)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *Validator) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6785,6 +7144,56 @@ func (m *VoteInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ExtendedVoteInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtendedVoteInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtendedVoteInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.VoteExtension) > 0 { + i -= len(m.VoteExtension) + copy(dAtA[i:], m.VoteExtension) + i = encodeVarintTypes(dAtA, i, uint64(len(m.VoteExtension))) + i-- + dAtA[i] = 0x1a + } + if m.SignedLastBlock { + i-- + if m.SignedLastBlock { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + { + size, err := m.Validator.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Evidence) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -6810,12 +7219,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n51, err51 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err51 != nil { - return 0, err51 + n54, err54 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err54 != nil { + return 0, err54 } - i -= n51 - i = encodeVarintTypes(dAtA, i, uint64(n51)) + i -= n54 + i = encodeVarintTypes(dAtA, i, uint64(n54)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -7364,21 +7773,29 @@ func (m *RequestPrepareProposal) Size() (n int) { } var l int _ = l - if len(m.BlockData) > 0 { - for _, b := range m.BlockData { + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.Header.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.Txs) > 0 { + for _, b := range m.Txs { l = len(b) n += 1 + l + sovTypes(uint64(l)) } } - if m.BlockDataSize != 0 { - n += 1 + sovTypes(uint64(m.BlockDataSize)) - } - if len(m.Votes) > 0 { - for _, e := range m.Votes { + l = m.LocalLastCommit.Size() + n += 1 + l + sovTypes(uint64(l)) + if len(m.ByzantineValidators) > 0 { + for _, e := range m.ByzantineValidators { l = e.Size() n += 1 + l + sovTypes(uint64(l)) } } + if m.MaxTxBytes != 0 { + n += 1 + sovTypes(uint64(m.MaxTxBytes)) + } return n } @@ -7963,9 +8380,12 @@ func (m *ResponsePrepareProposal) Size() (n int) { } var l int _ = l - if len(m.BlockData) > 0 { - for _, b := range m.BlockData { - l = len(b) + if m.ModifiedTx { + n += 2 + } + if len(m.TxRecords) > 0 { + for _, e := range m.TxRecords { + l = e.Size() n += 1 + l + sovTypes(uint64(l)) } } @@ -8030,6 +8450,24 @@ func (m *LastCommitInfo) Size() (n int) { return n } +func (m *ExtendedCommitInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Round != 0 { + n += 1 + sovTypes(uint64(m.Round)) + } + if len(m.Votes) > 0 { + for _, e := range m.Votes { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + func (m *Event) Size() (n int) { if m == nil { return 0 @@ -8090,6 +8528,22 @@ func (m *TxResult) Size() (n int) { return n } +func (m *TxRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Action != 0 { + n += 1 + sovTypes(uint64(m.Action)) + } + l = len(m.Tx) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *Validator) Size() (n int) { if m == nil { return 0 @@ -8134,6 +8588,24 @@ func (m *VoteInfo) Size() (n int) { return n } +func (m *ExtendedVoteInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Validator.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.SignedLastBlock { + n += 2 + } + l = len(m.VoteExtension) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + func (m *Evidence) Size() (n int) { if m == nil { return 0 @@ -10490,7 +10962,7 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockData", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -10517,31 +10989,14 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BlockData = append(m.BlockData, make([]byte, postIndex-iNdEx)) - copy(m.BlockData[len(m.BlockData)-1], dAtA[iNdEx:postIndex]) + m.Hash = append(m.Hash[:0], dAtA[iNdEx:postIndex]...) + if m.Hash == nil { + m.Hash = []byte{} + } iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockDataSize", wireType) - } - m.BlockDataSize = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.BlockDataSize |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -10568,11 +11023,128 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Votes = append(m.Votes, &types1.Vote{}) - if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Header.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Txs = append(m.Txs, make([]byte, postIndex-iNdEx)) + copy(m.Txs[len(m.Txs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LocalLastCommit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LocalLastCommit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ByzantineValidators", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ByzantineValidators = append(m.ByzantineValidators, Evidence{}) + if err := m.ByzantineValidators[len(m.ByzantineValidators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTxBytes", wireType) + } + m.MaxTxBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTxBytes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -13643,10 +14215,10 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockData", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ModifiedTx", wireType) } - var byteLen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -13656,23 +14228,45 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + m.ModifiedTx = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.BlockData = append(m.BlockData, make([]byte, postIndex-iNdEx)) - copy(m.BlockData[len(m.BlockData)-1], dAtA[iNdEx:postIndex]) + m.TxRecords = append(m.TxRecords, &TxRecord{}) + if err := m.TxRecords[len(m.TxRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -14080,6 +14674,109 @@ func (m *LastCommitInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExtendedCommitInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtendedCommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtendedCommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Round", wireType) + } + m.Round = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Round |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Votes = append(m.Votes, ExtendedVoteInfo{}) + if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Event) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14489,6 +15186,109 @@ func (m *TxResult) Unmarshal(dAtA []byte) error { } return nil } +func (m *TxRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Action", wireType) + } + m.Action = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Action |= TxRecord_TxAction(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tx", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tx = append(m.Tx[:0], dAtA[iNdEx:postIndex]...) + if m.Tx == nil { + m.Tx = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Validator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14797,6 +15597,143 @@ func (m *VoteInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *ExtendedVoteInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtendedVoteInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtendedVoteInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Validator", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Validator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SignedLastBlock", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SignedLastBlock = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VoteExtension", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VoteExtension = append(m.VoteExtension[:0], dAtA[iNdEx:postIndex]...) + if m.VoteExtension == nil { + m.VoteExtension = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Evidence) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/blockchain/v0/reactor.go b/blockchain/v0/reactor.go index c14d2d34a..93a1e7174 100644 --- a/blockchain/v0/reactor.go +++ b/blockchain/v0/reactor.go @@ -360,14 +360,20 @@ FOR_LOOP: didProcessCh <- struct{}{} } - firstParts := first.MakePartSet(types.BlockPartSizeBytes) + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + bcR.Logger.Error("failed to make ", + "height", first.Height, + "err", err.Error()) + break FOR_LOOP + } firstPartSetHeader := firstParts.Header() firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstPartSetHeader} // Finally, verify the first block using the second's commit // NOTE: we can probably make this more efficient, but note that calling // first.Hash() doesn't verify the tx contents, so MakePartSet() is // currently necessary. - err := state.Validators.VerifyCommitLight( + err = state.Validators.VerifyCommitLight( chainID, firstID, first.Height, second.LastCommit) if err == nil { diff --git a/blockchain/v0/reactor_test.go b/blockchain/v0/reactor_test.go index a88b499f4..6184b5b78 100644 --- a/blockchain/v0/reactor_test.go +++ b/blockchain/v0/reactor_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -15,10 +16,11 @@ import ( abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -52,6 +54,7 @@ type BlockchainReactorPair struct { } func newBlockchainReactor( + t *testing.T, logger log.Logger, genDoc *types.GenesisDoc, privVals []types.PrivValidator, @@ -78,6 +81,18 @@ func newBlockchainReactor( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + // Make the BlockchainReactor itself. // NOTE we have to create and commit the blocks first because // pool.height is determined from the store. @@ -85,7 +100,7 @@ func newBlockchainReactor( db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -112,9 +127,10 @@ func newBlockchainReactor( lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - thisBlock := makeBlock(blockHeight, state, lastCommit) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) @@ -140,8 +156,8 @@ func TestNoBlockResponse(t *testing.T) { reactorPairs := make([]BlockchainReactorPair, 2) - reactorPairs[0] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, maxBlockHeight) - reactorPairs[1] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight) + reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) p2p.MakeConnectedSwitches(config.P2P, 2, func(i int, s *p2p.Switch) *p2p.Switch { s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor) @@ -202,7 +218,7 @@ func TestBadBlockStopsPeer(t *testing.T) { // Other chain needs a different validator set otherGenDoc, otherPrivVals := randGenesisDoc(1, false, 30) - otherChain := newBlockchainReactor(log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight) + otherChain := newBlockchainReactor(t, log.TestingLogger(), otherGenDoc, otherPrivVals, maxBlockHeight) defer func() { err := otherChain.reactor.Stop() @@ -213,10 +229,10 @@ func TestBadBlockStopsPeer(t *testing.T) { reactorPairs := make([]BlockchainReactorPair, 4) - reactorPairs[0] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, maxBlockHeight) - reactorPairs[1] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) - reactorPairs[2] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) - reactorPairs[3] = newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[0] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, maxBlockHeight) + reactorPairs[1] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[2] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) + reactorPairs[3] = newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) switches := p2p.MakeConnectedSwitches(config.P2P, 4, func(i int, s *p2p.Switch) *p2p.Switch { s.AddReactor("BLOCKCHAIN", reactorPairs[i].reactor) @@ -254,7 +270,7 @@ func TestBadBlockStopsPeer(t *testing.T) { // race, but can't be easily avoided. reactorPairs[3].reactor.store = otherChain.reactor.store - lastReactorPair := newBlockchainReactor(log.TestingLogger(), genDoc, privVals, 0) + lastReactorPair := newBlockchainReactor(t, log.TestingLogger(), genDoc, privVals, 0) reactorPairs = append(reactorPairs, lastReactorPair) switches = append(switches, p2p.MakeConnectedSwitches(config.P2P, 1, func(i int, s *p2p.Switch) *p2p.Switch { @@ -278,21 +294,6 @@ func TestBadBlockStopsPeer(t *testing.T) { assert.True(t, lastReactorPair.reactor.Switch.Peers().Size() < len(reactorPairs)-1) } -//---------------------------------------------- -// utility funcs - -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < 10; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - -func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) - return block -} - type testApp struct { abci.BaseApplication } diff --git a/blockchain/v1/reactor.go b/blockchain/v1/reactor.go index 95e165c45..4b12f70e9 100644 --- a/blockchain/v1/reactor.go +++ b/blockchain/v1/reactor.go @@ -465,7 +465,13 @@ func (bcR *BlockchainReactor) processBlock() error { chainID := bcR.initialState.ChainID - firstParts := first.MakePartSet(types.BlockPartSizeBytes) + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + bcR.Logger.Error("failed to make ", + "height", first.Height, + "err", err.Error()) + return err + } firstPartSetHeader := firstParts.Header() firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstPartSetHeader} // Finally, verify the first block using the second's commit diff --git a/blockchain/v1/reactor_test.go b/blockchain/v1/reactor_test.go index c0f371905..53bcc36fd 100644 --- a/blockchain/v1/reactor_test.go +++ b/blockchain/v1/reactor_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -16,11 +17,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -110,6 +112,18 @@ func newBlockchainReactor( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + // Make the BlockchainReactor itself. // NOTE we have to create and commit the blocks first because // pool.height is determined from the store. @@ -117,7 +131,7 @@ func newBlockchainReactor( db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -133,9 +147,10 @@ func newBlockchainReactor( lastCommit = types.NewCommit(vote.Height, vote.Round, lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - thisBlock := makeBlock(blockHeight, state, lastCommit) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) @@ -345,21 +360,6 @@ outerFor: assert.True(t, lastReactorPair.bcR.Switch.Peers().Size() < len(reactorPairs)-1) } -//---------------------------------------------- -// utility funcs - -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < 10; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - -func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) - return block -} - type testApp struct { abci.BaseApplication } diff --git a/blockchain/v2/processor.go b/blockchain/v2/processor.go index f9036f3b9..44bf934fd 100644 --- a/blockchain/v2/processor.go +++ b/blockchain/v2/processor.go @@ -158,11 +158,12 @@ func (state *pcState) handle(event Event) (Event, error) { return noOp, nil } - var ( - first, second = firstItem.block, secondItem.block - firstParts = first.MakePartSet(types.BlockPartSizeBytes) - firstID = types.BlockID{Hash: first.Hash(), PartSetHeader: firstParts.Header()} - ) + first, second := firstItem.block, secondItem.block + firstParts, err := first.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + panic(fmt.Sprintf("failed to make part set, height %d: %v ", first.Height, err.Error())) + } + firstID := types.BlockID{Hash: first.Hash(), PartSetHeader: firstParts.Header()} // verify if +second+ last commit "confirms" +first+ block err = state.context.verifyCommit(tmState.ChainID, firstID, first.Height, second.LastCommit) diff --git a/blockchain/v2/reactor_test.go b/blockchain/v2/reactor_test.go index 808b16050..f5ca11421 100644 --- a/blockchain/v2/reactor_test.go +++ b/blockchain/v2/reactor_test.go @@ -10,6 +10,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -19,12 +20,13 @@ import ( cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/service" - "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/p2p/conn" bcproto "github.com/tendermint/tendermint/proto/tendermint/blockchain" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -142,8 +144,8 @@ type testReactorParams struct { mockA bool } -func newTestReactor(p testReactorParams) *BlockchainReactor { - store, state, _ := newReactorStore(p.genDoc, p.privVals, p.startHeight) +func newTestReactor(t *testing.T, p testReactorParams) *BlockchainReactor { + store, state, _ := newReactorStore(t, p.genDoc, p.privVals, p.startHeight) reporter := behaviour.NewMockReporter() var appl blockApplier @@ -151,6 +153,18 @@ func newTestReactor(p testReactorParams) *BlockchainReactor { if p.mockA { appl = &mockBlockApplier{} } else { + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + app := &testApp{} cc := proxy.NewLocalClientCreator(app) proxyApp := proxy.NewAppConns(cc) @@ -160,7 +174,7 @@ func newTestReactor(p testReactorParams) *BlockchainReactor { } db := dbm.NewMemDB() stateStore := sm.NewStore(db) - appl = sm.NewBlockExecutor(stateStore, p.logger, proxyApp.Consensus(), mock.Mempool{}, sm.EmptyEvidencePool{}) + appl = sm.NewBlockExecutor(stateStore, p.logger, proxyApp.Consensus(), mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -391,7 +405,7 @@ func TestReactorHelperMode(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - reactor := newTestReactor(params) + reactor := newTestReactor(t, params) mockSwitch := &mockSwitchIo{switchedToConsensus: false} reactor.io = mockSwitch err := reactor.Start() @@ -434,7 +448,7 @@ func TestReactorSetSwitchNil(t *testing.T) { defer os.RemoveAll(config.RootDir) genDoc, privVals := randGenesisDoc(config.ChainID(), 1, false, 30) - reactor := newTestReactor(testReactorParams{ + reactor := newTestReactor(t, testReactorParams{ logger: log.TestingLogger(), genDoc: genDoc, privVals: privVals, @@ -445,21 +459,6 @@ func TestReactorSetSwitchNil(t *testing.T) { assert.Nil(t, reactor.io) } -//---------------------------------------------- -// utility funcs - -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < 10; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - -func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) - return block -} - type testApp struct { abci.BaseApplication } @@ -488,6 +487,7 @@ func randGenesisDoc(chainID string, numValidators int, randPower bool, minPower // Why are we importing the entire blockExecutor dependency graph here // when we have the facilities to func newReactorStore( + t *testing.T, genDoc *types.GenesisDoc, privVals []types.PrivValidator, maxBlockHeight int64) (*store.BlockStore, sm.State, *sm.BlockExecutor) { @@ -510,10 +510,22 @@ func newReactorStore( panic(fmt.Errorf("error constructing state from genesis file: %w", err)) } + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + db := dbm.NewMemDB() stateStore = sm.NewStore(db) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) if err = stateStore.Save(state); err != nil { panic(err) } @@ -539,9 +551,11 @@ func newReactorStore( lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - thisBlock := makeBlock(blockHeight, state, lastCommit) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) + + thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) - thisParts := thisBlock.MakePartSet(types.BlockPartSizeBytes) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} state, _, err = blockExec.ApplyBlock(state, blockID, thisBlock) diff --git a/consensus/byzantine_test.go b/consensus/byzantine_test.go index 1f14b11aa..594c7d9a2 100644 --- a/consensus/byzantine_test.go +++ b/consensus/byzantine_test.go @@ -187,7 +187,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } var commit *types.Commit - var votes []*types.Vote switch { case lazyProposer.Height == lazyProposer.state.InitialHeight: // We're creating a proposal for the first block. @@ -196,7 +195,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { case lazyProposer.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = lazyProposer.LastCommit.MakeCommit() - votes = lazyProposer.LastCommit.GetVotes() default: // This shouldn't happen. lazyProposer.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") return @@ -213,9 +211,11 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } proposerAddr := lazyProposer.privValidatorPubKey.Address() - block, blockParts := lazyProposer.blockExec.CreateProposalBlock( - lazyProposer.Height, lazyProposer.state, commit, proposerAddr, votes, - ) + block, err := lazyProposer.blockExec.CreateProposalBlock( + lazyProposer.Height, lazyProposer.state, commit, proposerAddr, nil) + require.NoError(t, err) + blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) // Flush the WAL. Otherwise, we may not recompute the same proposal to sign, // and the privValidator will refuse to sign anything. @@ -463,7 +463,10 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St // Avoid sending on internalMsgQueue and running consensus state. // Create a new proposal block from state/txs from the mempool. - block1, blockParts1 := cs.createProposalBlock() + block1, err := cs.createProposalBlock() + require.NoError(t, err) + blockParts1, err := block1.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) polRound, propBlockID := cs.ValidRound, types.BlockID{Hash: block1.Hash(), PartSetHeader: blockParts1.Header()} proposal1 := types.NewProposal(height, round, polRound, propBlockID) p1 := proposal1.ToProto() @@ -477,7 +480,10 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int32, cs *St deliverTxsRange(cs, 0, 1) // Create a new proposal block from state/txs from the mempool. - block2, blockParts2 := cs.createProposalBlock() + block2, err := cs.createProposalBlock() + require.NoError(t, err) + blockParts2, err := block2.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) polRound, propBlockID = cs.ValidRound, types.BlockID{Hash: block2.Hash(), PartSetHeader: blockParts2.Header()} proposal2 := types.NewProposal(height, round, polRound, propBlockID) p2 := proposal2.ToProto() diff --git a/consensus/common_test.go b/consensus/common_test.go index 09512f49d..a8375279c 100644 --- a/consensus/common_test.go +++ b/consensus/common_test.go @@ -201,13 +201,17 @@ func startTestRound(cs *State, height int64, round int32) { // Create proposal block from cs1 but sign it with vs. func decideProposal( + t *testing.T, cs1 *State, vs *validatorStub, height int64, round int32, ) (proposal *types.Proposal, block *types.Block) { cs1.mtx.Lock() - block, blockParts := cs1.createProposalBlock() + block, err := cs1.createProposalBlock() + require.NoError(t, err) + blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) validRound := cs1.ValidRound chainID := cs1.state.ChainID cs1.mtx.Unlock() diff --git a/consensus/mempool_test.go b/consensus/mempool_test.go index a0cdae1df..183fedefd 100644 --- a/consensus/mempool_test.go +++ b/consensus/mempool_test.go @@ -259,5 +259,5 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + return abci.ResponsePrepareProposal{} } diff --git a/consensus/replay_test.go b/consensus/replay_test.go index a081e262e..61bc5f438 100644 --- a/consensus/replay_test.go +++ b/consensus/replay_test.go @@ -31,6 +31,7 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/types" ) @@ -362,9 +363,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower) err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx1, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ := css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts := propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err := css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(vss[1].Height, round, -1, blockID) @@ -392,9 +395,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25) err = assertMempool(css[0].txNotifier).CheckTx(updateValidatorTx1, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal = types.NewProposal(vss[2].Height, round, -1, blockID) @@ -429,9 +434,11 @@ func TestSimulateValidatorsChange(t *testing.T) { require.NoError(t, err) newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower) err = assertMempool(css[0].txNotifier).CheckTx(newValidatorTx3, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} newVss := make([]*validatorStub, nVals+1) copy(newVss, vss[:nVals+1]) @@ -504,9 +511,11 @@ func TestSimulateValidatorsChange(t *testing.T) { incrementHeight(vss...) removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0) err = assertMempool(css[0].txNotifier).CheckTx(removeValidatorTx3, nil, mempl.TxInfo{}) - assert.Nil(t, err) - propBlock, _ = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) - propBlockParts = propBlock.MakePartSet(partSize) + assert.NoError(t, err) + propBlock, err = css[0].createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) + propBlockParts, err = propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID = types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} newVss = make([]*validatorStub, nVals+3) copy(newVss, vss[:nVals+3]) @@ -665,7 +674,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin config = sim.Config chain = append([]*types.Block{}, sim.Chain...) // copy chain commits = sim.Commits - store = newMockBlockStore(config, genesisState.ConsensusParams) + store = newMockBlockStore(t, config, genesisState.ConsensusParams) } else { // test single node testConfig := ResetConfig(fmt.Sprintf("%s_%v_s", t.Name(), mode)) defer os.RemoveAll(testConfig.RootDir) @@ -690,7 +699,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin require.NoError(t, err) pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, genesisState, store = stateAndStore(config, pubKey, kvstore.ProtocolVersion) + stateDB, genesisState, store = stateAndStore(t, config, pubKey, kvstore.ProtocolVersion) } stateStore := sm.NewStore(stateDB) @@ -699,7 +708,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin state := genesisState.Copy() // run the chain through state.ApplyBlock to build up the tendermint state - state = buildTMStateFromChain(config, stateStore, state, chain, nBlocks, mode) + state = buildTMStateFromChain(t, config, stateStore, state, chain, nBlocks, mode) latestAppHash := state.AppHash // make a new client creator @@ -715,7 +724,7 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin stateStore := sm.NewStore(stateDB1) err := stateStore.Save(genesisState) require.NoError(t, err) - buildAppStateFromChain(proxyApp, stateStore, genesisState, chain, nBlocks, mode) + buildAppStateFromChain(t, proxyApp, stateStore, genesisState, chain, nBlocks, mode) } // Prune block store if requested @@ -775,19 +784,19 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin } } -func applyBlock(stateStore sm.Store, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State { +func applyBlock(t *testing.T, stateStore sm.Store, st sm.State, blk *types.Block, proxyApp proxy.AppConns) sm.State { testPartSize := types.BlockPartSizeBytes blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), mempool, evpool) - blkID := types.BlockID{Hash: blk.Hash(), PartSetHeader: blk.MakePartSet(testPartSize).Header()} + bps, err := blk.MakePartSet(testPartSize) + require.NoError(t, err) + blkID := types.BlockID{Hash: blk.Hash(), PartSetHeader: bps.Header()} newState, _, err := blockExec.ApplyBlock(st, blkID, blk) - if err != nil { - panic(err) - } + require.NoError(t, err) return newState } -func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, +func buildAppStateFromChain(t *testing.T, proxyApp proxy.AppConns, stateStore sm.Store, state sm.State, chain []*types.Block, nBlocks int, mode uint) { // start a new app without handshake, play nBlocks blocks if err := proxyApp.Start(); err != nil { @@ -809,18 +818,18 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, case 0: for i := 0; i < nBlocks; i++ { block := chain[i] - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } case 1, 2, 3: for i := 0; i < nBlocks-1; i++ { block := chain[i] - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } if mode == 2 || mode == 3 { // update the kvstore height and apphash // as if we ran commit but not - state = applyBlock(stateStore, state, chain[nBlocks-1], proxyApp) + state = applyBlock(t, stateStore, state, chain[nBlocks-1], proxyApp) } default: panic(fmt.Sprintf("unknown mode %v", mode)) @@ -829,6 +838,7 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateStore sm.Store, } func buildTMStateFromChain( + t *testing.T, config *cfg.Config, stateStore sm.Store, state sm.State, @@ -859,19 +869,19 @@ func buildTMStateFromChain( case 0: // sync right up for _, block := range chain { - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } case 1, 2, 3: // sync up to the penultimate as if we stored the block. // whether we commit or not depends on the appHash for _, block := range chain[:len(chain)-1] { - state = applyBlock(stateStore, state, block, proxyApp) + state = applyBlock(t, stateStore, state, block, proxyApp) } // apply the final block to a state copy so we can // get the right next appHash but keep the state back - applyBlock(stateStore, state, chain[len(chain)-1], proxyApp) + applyBlock(t, stateStore, state, chain[len(chain)-1], proxyApp) default: panic(fmt.Sprintf("unknown mode %v", mode)) } @@ -890,12 +900,14 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) { const appVersion = 0x0 pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, state, store := stateAndStore(config, pubKey, appVersion) + stateDB, state, store := stateAndStore(t, config, pubKey, appVersion) stateStore := sm.NewStore(stateDB) genDoc, _ := sm.MakeGenesisDocFromFile(config.GenesisFile()) state.LastValidators = state.Validators.Copy() // mode = 0 for committing all the blocks - blocks := makeBlocks(3, &state, privVal) + blocks, err := sf.MakeBlocks(3, &state, privVal) + require.NoError(t, err) + store.chain = blocks // 2. Tendermint must panic if app returns wrong hash for the first block @@ -947,52 +959,6 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) { } } -func makeBlocks(n int, state *sm.State, privVal types.PrivValidator) []*types.Block { - blocks := make([]*types.Block, 0) - - var ( - prevBlock *types.Block - prevBlockMeta *types.BlockMeta - ) - - appHeight := byte(0x01) - for i := 0; i < n; i++ { - height := int64(i + 1) - - block, parts := makeBlock(*state, prevBlock, prevBlockMeta, privVal, height) - blocks = append(blocks, block) - - prevBlock = block - prevBlockMeta = types.NewBlockMeta(block, parts) - - // update state - state.AppHash = []byte{appHeight} - appHeight++ - state.LastBlockHeight = height - } - - return blocks -} - -func makeBlock(state sm.State, lastBlock *types.Block, lastBlockMeta *types.BlockMeta, - privVal types.PrivValidator, height int64) (*types.Block, *types.PartSet) { - - lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - if height > 1 { - vote, _ := types.MakeVote( - lastBlock.Header.Height, - lastBlockMeta.BlockID, - state.Validators, - privVal, - lastBlock.Header.ChainID, - time.Now()) - lastCommit = types.NewCommit(vote.Height, vote.Round, - lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) - } - - return state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) -} - type badApp struct { abci.BaseApplication numBlocks byte @@ -1144,17 +1110,19 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} { // fresh state and mock store func stateAndStore( + t *testing.T, config *cfg.Config, pubKey crypto.PubKey, - appVersion uint64) (dbm.DB, sm.State, *mockBlockStore) { + appVersion uint64, +) (dbm.DB, sm.State, *mockBlockStore) { stateDB := dbm.NewMemDB() stateStore := sm.NewStore(stateDB) - state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile()) + state, err := sm.MakeGenesisStateFromFile(config.GenesisFile()) + require.NoError(t, err) state.Version.Consensus.App = appVersion - store := newMockBlockStore(config, state.ConsensusParams) - if err := stateStore.Save(state); err != nil { - panic(err) - } + store := newMockBlockStore(t, config, state.ConsensusParams) + require.NoError(t, stateStore.Save(state)) + return stateDB, state, store } @@ -1167,11 +1135,16 @@ type mockBlockStore struct { chain []*types.Block commits []*types.Commit base int64 + t *testing.T } // TODO: NewBlockStore(db.NewMemDB) ... -func newMockBlockStore(config *cfg.Config, params tmproto.ConsensusParams) *mockBlockStore { - return &mockBlockStore{config, params, nil, nil, 0} +func newMockBlockStore(t *testing.T, config *cfg.Config, params tmproto.ConsensusParams) *mockBlockStore { + return &mockBlockStore{ + config: config, + params: params, + t: t, + } } func (bs *mockBlockStore) Height() int64 { return int64(len(bs.chain)) } @@ -1184,8 +1157,10 @@ func (bs *mockBlockStore) LoadBlockByHash(hash []byte) *types.Block { } func (bs *mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { block := bs.chain[height-1] + bps, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(bs.t, err) return &types.BlockMeta{ - BlockID: types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(types.BlockPartSizeBytes).Header()}, + BlockID: types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}, Header: block.Header, } } @@ -1224,7 +1199,7 @@ func TestHandshakeUpdatesValidators(t *testing.T) { privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()) pubKey, err := privVal.GetPubKey() require.NoError(t, err) - stateDB, state, store := stateAndStore(config, pubKey, 0x0) + stateDB, state, store := stateAndStore(t, config, pubKey, 0x0) stateStore := sm.NewStore(stateDB) oldValAddr := state.Validators.Validators[0].Address diff --git a/consensus/state.go b/consensus/state.go index d2f3d2b42..8e662ea45 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -1131,8 +1131,17 @@ func (cs *State) defaultDecideProposal(height int64, round int32) { block, blockParts = cs.ValidBlock, cs.ValidBlockParts } else { // Create a new proposal block from state/txs from the mempool. - block, blockParts = cs.createProposalBlock() - if block == nil { + var err error + block, err = cs.createProposalBlock() + if err != nil { + cs.Logger.Error("unable to create proposal block", "error", err) + return + } else if block == nil { + panic("Method createProposalBlock should not provide a nil block without errors") + } + blockParts, err = block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + cs.Logger.Error("unable to create proposal block part set", "error", err) return } } @@ -1187,13 +1196,12 @@ func (cs *State) isProposalComplete() bool { // // NOTE: keep it side-effect free for clarity. // CONTRACT: cs.privValidator is not nil. -func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.PartSet) { +func (cs *State) createProposalBlock() (*types.Block, error) { if cs.privValidator == nil { - panic("entered createProposalBlock with privValidator being nil") + return nil, errors.New("entered createProposalBlock with privValidator being nil") } var commit *types.Commit - var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1203,23 +1211,20 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() - votes = cs.LastCommit.GetVotes() default: // This shouldn't happen. - cs.Logger.Error("propose step; cannot propose anything without commit for the previous block") - return + return nil, errors.New("propose step; cannot propose anything without commit for the previous block") } if cs.privValidatorPubKey == nil { // If this node is a validator & proposer in the current round, it will // miss the opportunity to create a block. - cs.Logger.Error("propose step; empty priv validator public key", "err", errPubKeyIsNotSet) - return + return nil, fmt.Errorf("propose step; empty priv validator public key, error: %w", errPubKeyIsNotSet) } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, votes) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: `timeoutPropose` after entering Propose. diff --git a/consensus/state_test.go b/consensus/state_test.go index 1e3887fd9..a551cfd6d 100644 --- a/consensus/state_test.go +++ b/consensus/state_test.go @@ -191,7 +191,8 @@ func TestStateBadProposal(t *testing.T) { proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) - propBlock, _ := cs1.createProposalBlock() // changeProposer(t, cs1, vs2) + propBlock, err := cs1.createProposalBlock() // changeProposer(t, cs1, vs2) + require.NoError(t, err) // make the second validator the proposer by incrementing round round++ @@ -204,7 +205,8 @@ func TestStateBadProposal(t *testing.T) { } stateHash[0] = (stateHash[0] + 1) % 255 propBlock.AppHash = stateHash - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(vs2.Height, round, -1, blockID) p := proposal.ToProto() @@ -230,13 +232,19 @@ func TestStateBadProposal(t *testing.T) { validatePrevote(t, cs1, round, vss[0], nil) // add bad prevote from vs2 and wait for it - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2) ensurePrevote(voteCh, height, round) // wait for precommit ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, -1, vss[0], nil, nil) - signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps2, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), bps2.Header(), vs2) } func TestStateOversizedBlock(t *testing.T) { @@ -250,7 +258,8 @@ func TestStateOversizedBlock(t *testing.T) { timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose) voteCh := subscribe(cs1.eventBus, types.EventQueryVote) - propBlock, _ := cs1.createProposalBlock() + propBlock, err := cs1.createProposalBlock() + require.NoError(t, err) propBlock.Data.Txs = []types.Tx{tmrand.Bytes(2001)} propBlock.Header.DataHash = propBlock.Data.Hash() @@ -258,7 +267,8 @@ func TestStateOversizedBlock(t *testing.T) { round++ incrementRound(vss[1:]...) - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) blockID := types.BlockID{Hash: propBlock.Hash(), PartSetHeader: propBlockParts.Header()} proposal := types.NewProposal(height, round, -1, blockID) p := proposal.ToProto() @@ -290,11 +300,18 @@ func TestStateOversizedBlock(t *testing.T) { // precommit on it ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], nil) - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2) ensurePrevote(voteCh, height, round) ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, -1, vss[0], nil, nil) - signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + + bps2, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, propBlock.Hash(), bps2.Header(), vs2) } //---------------------------------------------------------------------------------------------------- @@ -466,9 +483,7 @@ func TestStateLockNoPOL(t *testing.T) { rs := cs1.GetRoundState() - if rs.ProposalBlock != nil { - panic("Expected proposal block to be nil") - } + require.Nil(t, rs.ProposalBlock, "Expected proposal block to be nil") // wait to finish prevote ensurePrevote(voteCh, height, round) @@ -476,7 +491,10 @@ func TestStateLockNoPOL(t *testing.T) { validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash()) // add a conflicting prevote from the other validator - signAddVotes(cs1, tmproto.PrevoteType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2) + bps, err := rs.LockedBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, hash, bps.Header(), vs2) ensurePrevote(voteCh, height, round) // now we're going to enter prevote again, but with invalid args @@ -489,7 +507,9 @@ func TestStateLockNoPOL(t *testing.T) { validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // add conflicting precommit from vs2 - signAddVotes(cs1, tmproto.PrecommitType, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2) + bps2, err := rs.LockedBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrecommitType, hash, bps2.Header(), vs2) ensurePrecommit(voteCh, height, round) // (note we're entering precommit for a second time this round, but with invalid args @@ -519,7 +539,9 @@ func TestStateLockNoPOL(t *testing.T) { ensurePrevote(voteCh, height, round) // prevote validatePrevote(t, cs1, round, vss[0], rs.LockedBlock.Hash()) - signAddVotes(cs1, tmproto.PrevoteType, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2) + bps0, err := rs.ProposalBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrevoteType, hash, bps0.Header(), vs2) ensurePrevote(voteCh, height, round) ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds()) @@ -527,11 +549,13 @@ func TestStateLockNoPOL(t *testing.T) { validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but be locked on proposal + bps1, err := rs.ProposalBlock.MakePartSet(partSize) + require.NoError(t, err) signAddVotes( cs1, tmproto.PrecommitType, hash, - rs.ProposalBlock.MakePartSet(partSize).Header(), + bps1.Header(), vs2) // NOTE: conflicting precommits at same height ensurePrecommit(voteCh, height, round) @@ -539,7 +563,7 @@ func TestStateLockNoPOL(t *testing.T) { cs2, _ := randState(2) // needed so generated block is different than locked block // before we time out into new round, set next proposal block - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } @@ -555,7 +579,9 @@ func TestStateLockNoPOL(t *testing.T) { // now we're on a new round and not the proposer // so set the proposal block - if err := cs1.SetProposalAndBlock(prop, propBlock, propBlock.MakePartSet(partSize), ""); err != nil { + bps3, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + if err := cs1.SetProposalAndBlock(prop, propBlock, bps3, ""); err != nil { t.Fatal(err) } @@ -565,18 +591,23 @@ func TestStateLockNoPOL(t *testing.T) { validatePrevote(t, cs1, 3, vss[0], cs1.LockedBlock.Hash()) // prevote for proposed block - signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2) + bps4, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + signAddVotes(cs1, tmproto.PrevoteType, propBlock.Hash(), bps4.Header(), vs2) ensurePrevote(voteCh, height, round) ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Prevote(round).Nanoseconds()) ensurePrecommit(voteCh, height, round) validatePrecommit(t, cs1, round, 0, vss[0], nil, theBlockHash) // precommit nil but locked on proposal + bps5, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) signAddVotes( cs1, tmproto.PrecommitType, propBlock.Hash(), - propBlock.MakePartSet(partSize).Header(), + bps5.Header(), vs2) // NOTE: conflicting precommits at same height ensurePrecommit(voteCh, height, round) } @@ -631,11 +662,13 @@ func TestStateLockPOLRelock(t *testing.T) { // before we timeout to the new round set the new proposal cs2 := newState(cs1.state, vs2, counter.NewApplication(true)) - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + propBlockHash := propBlock.Hash() require.NotEqual(t, propBlockHash, theBlockHash) @@ -728,8 +761,9 @@ func TestStateLockPOLUnlock(t *testing.T) { signAddVotes(cs1, tmproto.PrecommitType, theBlockHash, theBlockParts, vs3) // before we time out into new round, set next proposal block - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) - propBlockParts := propBlock.MakePartSet(partSize) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // timeout to new round ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.Precommit(round).Nanoseconds()) @@ -816,11 +850,13 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) { // before we timeout to the new round set the new proposal cs2 := newState(cs1.state, vs2, counter.NewApplication(true)) - prop, propBlock := decideProposal(cs2, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs2, vs2, vs2.Height, vs2.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - secondBlockParts := propBlock.MakePartSet(partSize) + secondBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + secondBlockHash := propBlock.Hash() require.NotEqual(t, secondBlockHash, firstBlockHash) @@ -860,11 +896,12 @@ func TestStateLockPOLUnlockOnUnknownBlock(t *testing.T) { // before we timeout to the new round set the new proposal cs3 := newState(cs1.state, vs3, counter.NewApplication(true)) - prop, propBlock = decideProposal(cs3, vs3, vs3.Height, vs3.Round+1) + prop, propBlock = decideProposal(t, cs3, vs3, vs3.Height, vs3.Round+1) if prop == nil || propBlock == nil { t.Fatal("Failed to create proposal block with vs2") } - thirdPropBlockParts := propBlock.MakePartSet(partSize) + thirdPropBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) thirdPropBlockHash := propBlock.Hash() require.NotEqual(t, secondBlockHash, thirdPropBlockHash) @@ -928,7 +965,10 @@ func TestStateLockPOLSafety1(t *testing.T) { validatePrevote(t, cs1, round, vss[0], propBlock.Hash()) // the others sign a polka but we don't see it - prevotes := signVotes(tmproto.PrevoteType, propBlock.Hash(), propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + + prevotes := signVotes(tmproto.PrevoteType, propBlock.Hash(), bps.Header(), vs2, vs3, vs4) t.Logf("old prop hash %v", fmt.Sprintf("%X", propBlock.Hash())) @@ -941,9 +981,10 @@ func TestStateLockPOLSafety1(t *testing.T) { t.Log("### ONTO ROUND 1") - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) incrementRound(vs2, vs3, vs4) @@ -1037,18 +1078,20 @@ func TestStateLockPOLSafety2(t *testing.T) { // the block for R0: gets polkad but we miss it // (even though we signed it, shhh) - _, propBlock0 := decideProposal(cs1, vss[0], height, round) + _, propBlock0 := decideProposal(t, cs1, vss[0], height, round) propBlockHash0 := propBlock0.Hash() - propBlockParts0 := propBlock0.MakePartSet(partSize) + propBlockParts0, err := propBlock0.MakePartSet(partSize) + require.NoError(t, err) propBlockID0 := types.BlockID{Hash: propBlockHash0, PartSetHeader: propBlockParts0.Header()} // the others sign a polka but we don't see it prevotes := signVotes(tmproto.PrevoteType, propBlockHash0, propBlockParts0.Header(), vs2, vs3, vs4) // the block for round 1 - prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop1, propBlock1 := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash1 := propBlock1.Hash() - propBlockParts1 := propBlock1.MakePartSet(partSize) + propBlockParts1, err := propBlock1.MakePartSet(partSize) + require.NoError(t, err) incrementRound(vs2, vs3, vs4) @@ -1146,7 +1189,9 @@ func TestProposeValidBlock(t *testing.T) { validatePrevote(t, cs1, round, vss[0], propBlockHash) // the others sign a polka - signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4) + bps, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) + signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, bps.Header(), vs2, vs3, vs4) ensurePrecommit(voteCh, height, round) // we should have precommitted @@ -1230,7 +1275,8 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) { rs := cs1.GetRoundState() propBlock := rs.ProposalBlock propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], propBlockHash) @@ -1296,9 +1342,10 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) { ensurePrevote(voteCh, height, round) validatePrevote(t, cs1, round, vss[0], nil) - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round+1) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // vs2, vs3 and vs4 send prevote for propBlock signAddVotes(cs1, tmproto.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4) @@ -1456,9 +1503,10 @@ func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) { newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound) validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) - _, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round) + _, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // start round in which PO is not proposer startTestRound(cs1, height, round) @@ -1489,9 +1537,10 @@ func TestCommitFromPreviousRound(t *testing.T) { validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock) proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal) - prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round) + prop, propBlock := decideProposal(t, cs1, vs2, vs2.Height, vs2.Round) propBlockHash := propBlock.Hash() - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) // start round in which PO is not proposer startTestRound(cs1, height, round) @@ -1634,8 +1683,9 @@ func TestResetTimeoutPrecommitUponNewHeight(t *testing.T) { ensureNewBlockHeader(newBlockHeader, height, theBlockHash) - prop, propBlock := decideProposal(cs1, vs2, height+1, 0) - propBlockParts := propBlock.MakePartSet(partSize) + prop, propBlock := decideProposal(t, cs1, vs2, height+1, 0) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil { t.Fatal(err) @@ -1756,7 +1806,8 @@ func TestStateHalt1(t *testing.T) { ensureNewProposal(proposalCh, height, round) rs := cs1.GetRoundState() propBlock := rs.ProposalBlock - propBlockParts := propBlock.MakePartSet(partSize) + propBlockParts, err := propBlock.MakePartSet(partSize) + require.NoError(t, err) ensurePrevote(voteCh, height, round) diff --git a/evidence/mocks/block_store.go b/evidence/mocks/block_store.go index 02a90f831..5a16afc2a 100644 --- a/evidence/mocks/block_store.go +++ b/evidence/mocks/block_store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - types "github.com/tendermint/tendermint/types" ) diff --git a/evidence/pool_test.go b/evidence/pool_test.go index 365a3be88..c5939d43e 100644 --- a/evidence/pool_test.go +++ b/evidence/pool_test.go @@ -18,6 +18,7 @@ import ( tmversion "github.com/tendermint/tendermint/proto/tendermint/version" sm "github.com/tendermint/tendermint/state" smmocks "github.com/tendermint/tendermint/state/mocks" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/store" "github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/version" @@ -147,7 +148,7 @@ func TestAddExpiredEvidence(t *testing.T) { func TestReportConflictingVotes(t *testing.T) { var height int64 = 10 - pool, pv := defaultTestPool(height) + pool, pv := defaultTestPool(t, height) val := types.NewValidator(pv.PrivKey.PubKey(), 10) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height+1, defaultEvidenceTime, pv, evidenceChainID) @@ -181,7 +182,7 @@ func TestReportConflictingVotes(t *testing.T) { func TestEvidencePoolUpdate(t *testing.T) { height := int64(21) - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) state := pool.State() // create new block (no need to save it to blockStore) @@ -214,7 +215,7 @@ func TestEvidencePoolUpdate(t *testing.T) { func TestVerifyPendingEvidencePasses(t *testing.T) { var height int64 = 1 - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute), val, evidenceChainID) err := pool.AddEvidence(ev) @@ -226,7 +227,7 @@ func TestVerifyPendingEvidencePasses(t *testing.T) { func TestVerifyDuplicatedEvidenceFails(t *testing.T) { var height int64 = 1 - pool, val := defaultTestPool(height) + pool, val := defaultTestPool(t, height) ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, defaultEvidenceTime.Add(1*time.Minute), val, evidenceChainID) err := pool.CheckEvidence(types.EvidenceList{ev, ev}) @@ -306,7 +307,8 @@ func TestRecoverPendingEvidence(t *testing.T) { stateStore := initializeValidatorState(val, height) state, err := stateStore.Load() require.NoError(t, err) - blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + blockStore, err := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + require.NoError(t, err) // create previous pool and populate it pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) require.NoError(t, err) @@ -398,23 +400,26 @@ func initializeValidatorState(privVal types.PrivValidator, height int64) sm.Stor // initializeBlockStore creates a block storage and populates it w/ a dummy // block at +height+. -func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore { +func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) (*store.BlockStore, error) { blockStore := store.NewBlockStore(db) for i := int64(1); i <= state.LastBlockHeight; i++ { lastCommit := makeCommit(i-1, valAddr) - block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil, - state.Validators.GetProposer().Address) + block := sf.MakeBlock(state, i, lastCommit) + block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute) block.Header.Version = tmversion.Consensus{Block: version.BlockProtocol, App: 1} const parts = 1 - partSet := block.MakePartSet(parts) + partSet, err := block.MakePartSet(parts) + if err != nil { + return nil, err + } seenCommit := makeCommit(i, valAddr) blockStore.SaveBlock(block, partSet, seenCommit) } - return blockStore + return blockStore, nil } func makeCommit(height int64, valAddr []byte) *types.Commit { @@ -427,13 +432,15 @@ func makeCommit(height int64, valAddr []byte) *types.Commit { return types.NewCommit(height, 0, types.BlockID{}, commitSigs) } -func defaultTestPool(height int64) (*evidence.Pool, types.MockPV) { +func defaultTestPool(t *testing.T, height int64) (*evidence.Pool, types.MockPV) { + t.Helper() val := types.NewMockPV() valAddress := val.PrivKey.PubKey().Address() evidenceDB := dbm.NewMemDB() stateStore := initializeValidatorState(val, height) state, _ := stateStore.Load() - blockStore := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + blockStore, err := initializeBlockStore(dbm.NewMemDB(), state, valAddress) + require.NoError(t, err) pool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) if err != nil { panic("test evidence pool could not be created") diff --git a/mempool/mempool.go b/mempool/mempool.go index 08717fd95..f776fbc9b 100644 --- a/mempool/mempool.go +++ b/mempool/mempool.go @@ -23,6 +23,8 @@ const ( MaxActiveIDs = math.MaxUint16 ) +//go:generate mockery --case underscore --name Mempool + // Mempool defines the mempool interface. // // Updates to the mempool need to be synchronized with committing a block so diff --git a/mempool/mock/mempool.go b/mempool/mock/mempool.go deleted file mode 100644 index 3f293381f..000000000 --- a/mempool/mock/mempool.go +++ /dev/null @@ -1,43 +0,0 @@ -package mock - -import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/clist" - "github.com/tendermint/tendermint/mempool" - "github.com/tendermint/tendermint/types" -) - -// Mempool is an empty implementation of a Mempool, useful for testing. -type Mempool struct{} - -var _ mempool.Mempool = Mempool{} - -func (Mempool) Lock() {} -func (Mempool) Unlock() {} -func (Mempool) Size() int { return 0 } -func (Mempool) CheckTx(_ types.Tx, _ func(*abci.Response), _ mempool.TxInfo) error { - return nil -} -func (Mempool) RemoveTxByKey(txKey types.TxKey) error { return nil } -func (Mempool) ReapMaxBytesMaxGas(_, _ int64) types.Txs { return types.Txs{} } -func (Mempool) ReapMaxTxs(n int) types.Txs { return types.Txs{} } -func (Mempool) Update( - _ int64, - _ types.Txs, - _ []*abci.ResponseDeliverTx, - _ mempool.PreCheckFunc, - _ mempool.PostCheckFunc, -) error { - return nil -} -func (Mempool) Flush() {} -func (Mempool) FlushAppConn() error { return nil } -func (Mempool) TxsAvailable() <-chan struct{} { return make(chan struct{}) } -func (Mempool) EnableTxsAvailable() {} -func (Mempool) SizeBytes() int64 { return 0 } - -func (Mempool) TxsFront() *clist.CElement { return nil } -func (Mempool) TxsWaitChan() <-chan struct{} { return nil } - -func (Mempool) InitWAL() error { return nil } -func (Mempool) CloseWAL() {} diff --git a/mempool/mocks/mempool.go b/mempool/mocks/mempool.go new file mode 100644 index 000000000..94c024ac2 --- /dev/null +++ b/mempool/mocks/mempool.go @@ -0,0 +1,184 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + abcitypes "github.com/tendermint/tendermint/abci/types" + mempool "github.com/tendermint/tendermint/mempool" + + mock "github.com/stretchr/testify/mock" + + types "github.com/tendermint/tendermint/types" +) + +// Mempool is an autogenerated mock type for the Mempool type +type Mempool struct { + mock.Mock +} + +// CheckTx provides a mock function with given fields: tx, callback, txInfo +func (_m *Mempool) CheckTx(tx types.Tx, callback func(*abcitypes.Response), txInfo mempool.TxInfo) error { + ret := _m.Called(tx, callback, txInfo) + + var r0 error + if rf, ok := ret.Get(0).(func(types.Tx, func(*abcitypes.Response), mempool.TxInfo) error); ok { + r0 = rf(tx, callback, txInfo) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EnableTxsAvailable provides a mock function with given fields: +func (_m *Mempool) EnableTxsAvailable() { + _m.Called() +} + +// Flush provides a mock function with given fields: +func (_m *Mempool) Flush() { + _m.Called() +} + +// FlushAppConn provides a mock function with given fields: +func (_m *Mempool) FlushAppConn() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Lock provides a mock function with given fields: +func (_m *Mempool) Lock() { + _m.Called() +} + +// ReapMaxBytesMaxGas provides a mock function with given fields: maxBytes, maxGas +func (_m *Mempool) ReapMaxBytesMaxGas(maxBytes int64, maxGas int64) types.Txs { + ret := _m.Called(maxBytes, maxGas) + + var r0 types.Txs + if rf, ok := ret.Get(0).(func(int64, int64) types.Txs); ok { + r0 = rf(maxBytes, maxGas) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Txs) + } + } + + return r0 +} + +// ReapMaxTxs provides a mock function with given fields: max +func (_m *Mempool) ReapMaxTxs(max int) types.Txs { + ret := _m.Called(max) + + var r0 types.Txs + if rf, ok := ret.Get(0).(func(int) types.Txs); ok { + r0 = rf(max) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Txs) + } + } + + return r0 +} + +// RemoveTxByKey provides a mock function with given fields: txKey +func (_m *Mempool) RemoveTxByKey(txKey types.TxKey) error { + ret := _m.Called(txKey) + + var r0 error + if rf, ok := ret.Get(0).(func(types.TxKey) error); ok { + r0 = rf(txKey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Size provides a mock function with given fields: +func (_m *Mempool) Size() int { + ret := _m.Called() + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// SizeBytes provides a mock function with given fields: +func (_m *Mempool) SizeBytes() int64 { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// TxsAvailable provides a mock function with given fields: +func (_m *Mempool) TxsAvailable() <-chan struct{} { + ret := _m.Called() + + var r0 <-chan struct{} + if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(<-chan struct{}) + } + } + + return r0 +} + +// Unlock provides a mock function with given fields: +func (_m *Mempool) Unlock() { + _m.Called() +} + +// Update provides a mock function with given fields: blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn +func (_m *Mempool) Update(blockHeight int64, blockTxs types.Txs, deliverTxResponses []*abcitypes.ResponseDeliverTx, newPreFn mempool.PreCheckFunc, newPostFn mempool.PostCheckFunc) error { + ret := _m.Called(blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn) + + var r0 error + if rf, ok := ret.Get(0).(func(int64, types.Txs, []*abcitypes.ResponseDeliverTx, mempool.PreCheckFunc, mempool.PostCheckFunc) error); ok { + r0 = rf(blockHeight, blockTxs, deliverTxResponses, newPreFn, newPostFn) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewMempool interface { + mock.TestingT + Cleanup(func()) +} + +// NewMempool creates a new instance of Mempool. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewMempool(t mockConstructorTestingTNewMempool) *Mempool { + mock := &Mempool{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/node/node_test.go b/node/node_test.go index 5e65ad2b4..5382c94df 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -305,15 +305,17 @@ func TestCreateProposalBlock(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _ := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( height, state, commit, proposerAddr, nil, ) + require.NoError(t, err) // check that the part set does not exceed the maximum block size - partSet := block.MakePartSet(partSize) + partSet, err := block.MakePartSet(partSize) + require.NoError(t, err) assert.Less(t, partSet.ByteSize(), int64(maxBytes)) partSetFromHeader := types.NewPartSetFromHeader(partSet.Header()) @@ -384,19 +386,21 @@ func TestMaxProposalBlockSize(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _ := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( height, state, commit, proposerAddr, nil, ) + require.NoError(t, err) pb, err := block.ToProto() require.NoError(t, err) assert.Less(t, int64(pb.Size()), maxBytes) // check that the part set does not exceed the maximum block size - partSet := block.MakePartSet(partSize) + partSet, err := block.MakePartSet(partSize) + require.NoError(t, err) assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size())) } diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index f7c5e2412..9b74a397f 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -126,15 +126,15 @@ message RequestApplySnapshotChunk { } message RequestPrepareProposal { - // block_data is an array of transactions that will be included in a block, + bytes hash = 1; + tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; + // txs is an array of transactions that will be included in a block, // sent to the app for possible modifications. - // applications can not exceed the size of the data passed to it. - repeated bytes block_data = 1; - // If an application decides to populate block_data with extra information, they can not exceed this value. - int64 block_data_size = 2; - // votes includes all votes from the previous block. This contains vote extension data that can be used in proposal - // preparation. The votes here will then form the last commit that gets sent in the proposed block. - repeated types.Vote votes = 3; + repeated bytes txs = 3; + ExtendedCommitInfo local_last_commit = 4 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 5 [(gogoproto.nullable) = false]; + // the modified transactions cannot exceed this size. + int64 max_tx_bytes = 6; } //---------------------------------------- @@ -298,7 +298,8 @@ message ResponseApplySnapshotChunk { } message ResponsePrepareProposal { - repeated bytes block_data = 1; + bool modified_tx = 1; + repeated TxRecord tx_records = 2; } //---------------------------------------- @@ -326,6 +327,11 @@ message LastCommitInfo { repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; } +message ExtendedCommitInfo { + int32 round = 1; + repeated ExtendedVoteInfo votes = 2 [(gogoproto.nullable) = false]; +} + // Event allows application developers to attach additional information to // ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. // Later, transactions may be queried using these events. @@ -354,6 +360,19 @@ message TxResult { ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; } +message TxRecord { + TxAction action = 1; + bytes tx = 2; + + // TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal + enum TxAction { + UNKNOWN = 0; // Unknown action + UNMODIFIED = 1; // The Application did not modify this transaction. + ADDED = 2; // The Application added this transaction. + REMOVED = 3; // The Application wants this transaction removed from the proposal and the mempool. + } +} + //---------------------------------------- // Blockchain Types @@ -374,6 +393,14 @@ message ValidatorUpdate { message VoteInfo { Validator validator = 1 [(gogoproto.nullable) = false]; bool signed_last_block = 2; + reserved 3; // Placeholder for tendermint_signed_extension in v0.37 + reserved 4; // Placeholder for app_signed_extension in v0.37 +} + +message ExtendedVoteInfo { + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; + bytes vote_extension = 3; // Reserved for future use } enum EvidenceType { diff --git a/proxy/mocks/app_conn_consensus.go b/proxy/mocks/app_conn_consensus.go index 0cec96536..324e4b199 100644 --- a/proxy/mocks/app_conn_consensus.go +++ b/proxy/mocks/app_conn_consensus.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - abcicli "github.com/tendermint/tendermint/abci/client" types "github.com/tendermint/tendermint/abci/types" diff --git a/proxy/mocks/app_conn_mempool.go b/proxy/mocks/app_conn_mempool.go index 3e4bd93a0..e33bc4b3a 100644 --- a/proxy/mocks/app_conn_mempool.go +++ b/proxy/mocks/app_conn_mempool.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - abcicli "github.com/tendermint/tendermint/abci/client" types "github.com/tendermint/tendermint/abci/types" diff --git a/rpc/client/helpers.go b/rpc/client/helpers.go index 0878df6a8..8014d875a 100644 --- a/rpc/client/helpers.go +++ b/rpc/client/helpers.go @@ -70,7 +70,7 @@ func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (type // make sure to unregister after the test is over defer func() { if deferErr := c.UnsubscribeAll(ctx, subscriber); deferErr != nil { - panic(err) + panic(deferErr) } }() diff --git a/rpc/core/tx.go b/rpc/core/tx.go index 1dc9df7c0..e7537e353 100644 --- a/rpc/core/tx.go +++ b/rpc/core/tx.go @@ -32,19 +32,16 @@ func Tx(ctx *rpctypes.Context, hash []byte, prove bool) (*ctypes.ResultTx, error return nil, fmt.Errorf("tx (%X) not found", hash) } - height := r.Height - index := r.Index - var proof types.TxProof if prove { - block := env.BlockStore.LoadBlock(height) - proof = block.Data.Txs.Proof(int(index)) // XXX: overflow on 32-bit machines + block := env.BlockStore.LoadBlock(r.Height) + proof = block.Data.Txs.Proof(int(r.Index)) } return &ctypes.ResultTx{ Hash: hash, - Height: height, - Index: index, + Height: r.Height, + Index: r.Index, TxResult: r.Result, Tx: r.Tx, Proof: proof, @@ -118,7 +115,7 @@ func TxSearch( var proof types.TxProof if prove { block := env.BlockStore.LoadBlock(r.Height) - proof = block.Data.Txs.Proof(int(r.Index)) // XXX: overflow on 32-bit machines + proof = block.Data.Txs.Proof(int(r.Index)) } apiResults = append(apiResults, &ctypes.ResultTx{ diff --git a/state/execution.go b/state/execution.go index 2e7b4b254..0659bbf61 100644 --- a/state/execution.go +++ b/state/execution.go @@ -9,7 +9,7 @@ import ( cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/libs/fail" "github.com/tendermint/tendermint/libs/log" - mempl "github.com/tendermint/tendermint/mempool" + "github.com/tendermint/tendermint/mempool" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" @@ -34,7 +34,7 @@ type BlockExecutor struct { // manage the mempool lock during commit // and update both with block results after commit. - mempool mempl.Mempool + mempool mempool.Mempool evpool EvidencePool logger log.Logger @@ -56,7 +56,7 @@ func NewBlockExecutor( stateStore Store, logger log.Logger, proxyApp proxy.AppConnConsensus, - mempool mempl.Mempool, + mempool mempool.Mempool, evpool EvidencePool, options ...BlockExecutorOption, ) *BlockExecutor { @@ -95,10 +95,11 @@ func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) // Contract: application will not return more bytes than are sent over the wire. func (blockExec *BlockExecutor) CreateProposalBlock( height int64, - state State, commit *types.Commit, + state State, + commit *types.Commit, proposerAddr []byte, votes []*types.Vote, -) (*types.Block, *types.PartSet) { +) (*types.Block, error) { maxBytes := state.ConsensusParams.Block.MaxBytes maxGas := state.ConsensusParams.Block.MaxGas @@ -109,12 +110,17 @@ func (blockExec *BlockExecutor) CreateProposalBlock( maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size()) txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas) + block := state.MakeBlock(height, txs, commit, evidence, proposerAddr) - preparedProposal, err := blockExec.proxyApp.PrepareProposalSync( + localLastCommit := getBeginBlockValidatorInfo(block, blockExec.store, state.InitialHeight) + rpp, err := blockExec.proxyApp.PrepareProposalSync( abci.RequestPrepareProposal{ - BlockData: txs.ToSliceOfBytes(), - BlockDataSize: maxDataBytes, - Votes: types.VotesToProto(votes), + Hash: block.Hash(), + Header: *block.Header.ToProto(), + Txs: block.Txs.ToSliceOfBytes(), + LocalLastCommit: extendedCommitInfo(localLastCommit, votes), + ByzantineValidators: block.Evidence.Evidence.ToABCI(), + MaxTxBytes: maxDataBytes, }, ) if err != nil { @@ -128,19 +134,28 @@ func (blockExec *BlockExecutor) CreateProposalBlock( // purpose for now. panic(err) } - newTxs := preparedProposal.GetBlockData() - var txSize int - for _, tx := range newTxs { - txSize += len(tx) - if maxDataBytes < int64(txSize) { - panic("block data exceeds max amount of allowed bytes") - } + if !rpp.ModifiedTx { + return block, nil + } + txrSet := types.NewTxRecordSet(rpp.TxRecords) + + if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { + return nil, err } - modifiedTxs := types.ToTxs(preparedProposal.GetBlockData()) - - return state.MakeBlock(height, modifiedTxs, commit, evidence, proposerAddr) + for _, rtx := range txrSet.RemovedTxs() { + if err := blockExec.mempool.RemoveTxByKey(rtx.Key()); err != nil { + blockExec.logger.Debug("error removing transaction from the mempool", "error", err, "tx hash", rtx.Hash()) + } + } + for _, atx := range txrSet.AddedTxs() { + if err := blockExec.mempool.CheckTx(atx, nil, mempool.TxInfo{}); err != nil { + blockExec.logger.Error("error adding tx to the mempool", "error", err, "tx hash", atx.Hash()) + } + } + itxs := txrSet.IncludedTxs() + return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil } // ValidateBlock validates the given block against the given state. @@ -407,6 +422,24 @@ func getBeginBlockValidatorInfo(block *types.Block, store Store, } } +func extendedCommitInfo(c abci.LastCommitInfo, votes []*types.Vote) abci.ExtendedCommitInfo { + vs := make([]abci.ExtendedVoteInfo, len(c.Votes)) + for i := range vs { + vs[i] = abci.ExtendedVoteInfo{ + Validator: c.Votes[i].Validator, + SignedLastBlock: c.Votes[i].SignedLastBlock, + /* + TODO: Include vote extensions information when implementing vote extensions. + VoteExtension: []byte{}, + */ + } + } + return abci.ExtendedCommitInfo{ + Round: c.Round, + Votes: vs, + } +} + func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate, params tmproto.ValidatorParams) error { for _, valUpdate := range abciUpdates { diff --git a/state/execution_test.go b/state/execution_test.go index a8aeffe93..5cfea42d5 100644 --- a/state/execution_test.go +++ b/state/execution_test.go @@ -10,17 +10,20 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" + abcimocks "github.com/tendermint/tendermint/abci/types/mocks" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" cryptoenc "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" - mmock "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/mocks" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" @@ -29,7 +32,6 @@ import ( var ( chainID = "execution_chain" testPartSize uint32 = 65536 - nTxsPerBlock = 10 ) func TestApplyBlock(t *testing.T) { @@ -42,12 +44,24 @@ func TestApplyBlock(t *testing.T) { state, stateDB, _ := makeState(1, 1) stateStore := sm.NewStore(stateDB) - + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, sm.EmptyEvidencePool{}) + mp, sm.EmptyEvidencePool{}) - block := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block) require.Nil(t, err) @@ -100,7 +114,7 @@ func TestBeginBlockValidators(t *testing.T) { lastCommit := types.NewCommit(1, 0, prevBlockID, tc.lastCommitSigs) // block for height 2 - block, _ := state.MakeBlock(2, makeTxs(2), lastCommit, nil, state.Validators.GetProposer().Address) + block := sf.MakeBlock(state, 2, lastCommit) _, err = sm.ExecCommitBlock(proxyApp.Consensus(), block, log.TestingLogger(), stateStore, 1) require.Nil(t, err, tc.desc) @@ -197,14 +211,28 @@ func TestBeginBlockByzantineValidators(t *testing.T) { evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return(ev, int64(100)) evpool.On("Update", mock.AnythingOfType("state.State"), mock.AnythingOfType("types.EvidenceList")).Return() evpool.On("CheckEvidence", mock.AnythingOfType("types.EvidenceList")).Return(nil) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, evpool) + mp, evpool) - block := makeBlock(state, 1) + block := sf.MakeBlock(state, 1, new(types.Commit)) block.Evidence = types.EvidenceData{Evidence: ev} block.Header.EvidenceHash = block.Evidence.Hash() - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block) require.Nil(t, err) @@ -355,12 +383,24 @@ func TestEndBlockValidatorUpdates(t *testing.T) { state, stateDB, _ := makeState(1, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) @@ -378,8 +418,10 @@ func TestEndBlockValidatorUpdates(t *testing.T) { ) require.NoError(t, err) - block := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} pubkey := ed25519.GenPrivKey().PubKey() pk, err := cryptoenc.PubKeyToProto(pubkey) @@ -430,12 +472,14 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { stateStore, log.TestingLogger(), proxyApp.Consensus(), - mmock.Mempool{}, + new(mpmocks.Mempool), sm.EmptyEvidencePool{}, ) - block := makeBlock(state, 1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, 1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} vp, err := cryptoenc.PubKeyToProto(state.Validators.Validators[0].PubKey) require.NoError(t, err) @@ -449,6 +493,201 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { assert.NotEmpty(t, state.NextValidators.Validators) } +func TestEmptyPrepareProposal(t *testing.T) { + const height = 2 + + app := &testApp{} + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + sm.EmptyEvidencePool{}, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + _, err = blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) +} + +// TestPrepareProposalRemoveTxs tests that any transactions marked as REMOVED +// are not included in the block produced by CreateProposalBlock. The test also +// ensures that any transactions removed are also removed from the mempool. +func TestPrepareProposalRemoveTxs(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeTenTxs(height) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + trs := txsToTxRecords(types.Txs(txs)) + trs[0].Action = abci.TxRecord_REMOVED + trs[1].Action = abci.TxRecord_REMOVED + mp.On("RemoveTxByKey", mock.Anything).Return(nil).Twice() + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + defer proxyApp.Stop() //nolint:errcheck // ignore for tests + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + require.Len(t, block.Data.Txs.ToSliceOfBytes(), len(trs)-2) + + require.Equal(t, -1, block.Data.Txs.Index(types.Tx(trs[0].Tx))) + require.Equal(t, -1, block.Data.Txs.Index(types.Tx(trs[1].Tx))) + + mp.AssertCalled(t, "RemoveTxByKey", types.Tx(trs[0].Tx).Key()) + mp.AssertCalled(t, "RemoveTxByKey", types.Tx(trs[1].Tx).Key()) + mp.AssertExpectations(t) +} + +// TestPrepareProposalAddedTxsIncluded tests that any transactions marked as ADDED +// in the prepare proposal response are included in the block. The test also +// ensures that any transactions added are also checked into the mempool. +func TestPrepareProposalAddedTxsIncluded(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeTenTxs(height) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs[2:])) + mp.On("CheckTx", mock.Anything, mock.Anything, mock.Anything).Return(nil).Twice() + + trs := txsToTxRecords(types.Txs(txs)) + trs[0].Action = abci.TxRecord_ADDED + trs[1].Action = abci.TxRecord_ADDED + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + + require.Equal(t, txs[0], block.Data.Txs[0]) + require.Equal(t, txs[1], block.Data.Txs[1]) + + mp.AssertExpectations(t) + mp.AssertCalled(t, "CheckTx", types.Tx(trs[0].Tx), mock.Anything, mock.Anything) + mp.AssertCalled(t, "CheckTx", types.Tx(trs[1].Tx), mock.Anything, mock.Anything) +} + +// TestPrepareProposalReorderTxs tests that CreateBlock produces a block with transactions +// in the order matching the order they are returned from PrepareProposal. +func TestPrepareProposalReorderTxs(t *testing.T) { + const height = 2 + + state, stateDB, privVals := makeState(1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + txs := factory.MakeTenTxs(height) + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs(txs)) + + trs := txsToTxRecords(types.Txs(txs)) + trs = trs[2:] + trs = append(trs[len(trs)/2:], trs[:len(trs)/2]...) + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + ModifiedTx: true, + TxRecords: trs, + }, nil) + + cc := proxy.NewLocalClientCreator(app) + proxyApp := proxy.NewAppConns(cc) + err := proxyApp.Start() + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + log.TestingLogger(), + proxyApp.Consensus(), + mp, + evpool, + ) + pa, _ := state.Validators.GetByIndex(0) + commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals) + require.NoError(t, err) + block, err := blockExec.CreateProposalBlock(height, state, commit, pa, nil) + require.NoError(t, err) + for i, tx := range block.Data.Txs { + require.Equal(t, types.Tx(trs[i].Tx), tx) + } + + mp.AssertExpectations(t) + +} + func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID { var ( h = make([]byte, tmhash.Size) @@ -464,3 +703,14 @@ func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.Bloc }, } } + +func txsToTxRecords(txs []types.Tx) []*abci.TxRecord { + trs := make([]*abci.TxRecord, len(txs)) + for i, tx := range txs { + trs[i] = &abci.TxRecord{ + Action: abci.TxRecord_UNMODIFIED, + Tx: tx, + } + } + return trs +} diff --git a/state/helpers_test.go b/state/helpers_test.go index 19549f160..8a7311ed9 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -3,6 +3,7 @@ package state_test import ( "bytes" "fmt" + "testing" "time" dbm "github.com/tendermint/tm-db" @@ -10,11 +11,12 @@ import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" - tmrand "github.com/tendermint/tendermint/libs/rand" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/proxy" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" ) @@ -54,13 +56,18 @@ func makeAndCommitGoodBlock( func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commit, proposerAddr []byte, blockExec *sm.BlockExecutor, evidence []types.Evidence) (sm.State, types.BlockID, error) { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + return state, types.BlockID{}, err + } + if err := blockExec.ValidateBlock(state, block); err != nil { return state, types.BlockID{}, err } blockID := types.BlockID{Hash: block.Hash(), - PartSetHeader: types.PartSetHeader{Total: 3, Hash: tmrand.Bytes(32)}} - state, _, err := blockExec.ApplyBlock(state, blockID, block) + PartSetHeader: partSet.Header()} + state, _, err = blockExec.ApplyBlock(state, blockID, block) if err != nil { return state, types.BlockID{}, err } @@ -85,14 +92,6 @@ func makeValidCommit( return types.NewCommit(height, 0, blockID, sigs), nil } -// make some bogus txs -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < nTxsPerBlock; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValidator) { vals := make([]types.GenesisValidator, nVals) privVals := make(map[string]types.PrivValidator, nVals) @@ -131,17 +130,6 @@ func makeState(nVals, height int) (sm.State, dbm.DB, map[string]types.PrivValida return s, stateDB, privVals } -func makeBlock(state sm.State, height int64) *types.Block { - block, _ := state.MakeBlock( - height, - makeTxs(state.LastBlockHeight), - new(types.Commit), - nil, - state.Validators.GetProposer().Address, - ) - return block -} - func genValSet(size int) *types.ValidatorSet { vals := make([]*types.Validator, size) for i := 0; i < size; i++ { @@ -151,11 +139,12 @@ func genValSet(size int) *types.ValidatorSet { } func makeHeaderPartsResponsesValPubKeyChange( + t *testing.T, state sm.State, pubkey crypto.PubKey, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -175,11 +164,13 @@ func makeHeaderPartsResponsesValPubKeyChange( } func makeHeaderPartsResponsesValPowerChange( + t *testing.T, state sm.State, power int64, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -199,11 +190,12 @@ func makeHeaderPartsResponsesValPowerChange( } func makeHeaderPartsResponsesParams( + t *testing.T, state sm.State, params tmproto.ConsensusParams, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block := makeBlock(state, state.LastBlockHeight+1) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, diff --git a/state/mocks/evidence_pool.go b/state/mocks/evidence_pool.go index e4f9c7370..6f41e120f 100644 --- a/state/mocks/evidence_pool.go +++ b/state/mocks/evidence_pool.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" types "github.com/tendermint/tendermint/types" diff --git a/state/mocks/store.go b/state/mocks/store.go index 722c48a6f..4308d4ead 100644 --- a/state/mocks/store.go +++ b/state/mocks/store.go @@ -4,7 +4,6 @@ package mocks import ( mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" tendermintstate "github.com/tendermint/tendermint/proto/tendermint/state" diff --git a/state/state.go b/state/state.go index a1df48d45..8082da7b8 100644 --- a/state/state.go +++ b/state/state.go @@ -238,7 +238,7 @@ func (state State) MakeBlock( commit *types.Commit, evidence []types.Evidence, proposerAddress []byte, -) (*types.Block, *types.PartSet) { +) *types.Block { // Build base block with block data. block := types.MakeBlock(height, txs, commit, evidence) @@ -260,7 +260,7 @@ func (state State) MakeBlock( proposerAddress, ) - return block, block.MakePartSet(types.BlockPartSizeBytes) + return block } // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the diff --git a/state/state_test.go b/state/state_test.go index 3f27efe42..e943c37a0 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -21,6 +21,7 @@ import ( tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sm "github.com/tendermint/tendermint/state" + sf "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/types" ) @@ -101,7 +102,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) { state.LastBlockHeight++ // Build mock responses. - block := makeBlock(state, 2) + block := sf.MakeBlock(state, 2, new(types.Commit)) abciResponses := new(tmstate.ABCIResponses) dtxs := make([]*abci.ResponseDeliverTx, 2) @@ -269,12 +270,12 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { changeIndex++ power++ } - header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, power) + header, blockID, responses := makeHeaderPartsResponsesValPowerChange(t, state, power) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) require.NoError(t, err) state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) require.NoError(t, err) - err := stateStore.Save(state) + err = stateStore.Save(state) require.NoError(t, err) } @@ -443,8 +444,10 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { // NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1 assert.EqualValues(t, 0, val1.ProposerPriority) - block := makeBlock(state, state.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, @@ -557,8 +560,10 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // we only have one validator: assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) - block := makeBlock(state, state.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} // no updates: abciResponses := &tmstate.ABCIResponses{ BeginBlock: &abci.ResponseBeginBlock{}, @@ -744,8 +749,10 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -773,8 +780,12 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, } - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -788,8 +799,12 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(lastState, lastState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit)) + + bps, err = block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedStateInner, err := sm.UpdateState(lastState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -821,8 +836,11 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, } - block := makeBlock(oldState, oldState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} state, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) } @@ -836,8 +854,14 @@ func TestLargeGenesisValidator(t *testing.T) { BeginBlock: &abci.ResponseBeginBlock{}, EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, } - block = makeBlock(oldState, oldState.LastBlockHeight+1) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + + block = sf.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + require.NoError(t, err) + + bps, err = block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) updatedState, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) @@ -857,8 +881,12 @@ func TestLargeGenesisValidator(t *testing.T) { } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block = makeBlock(curState, curState.LastBlockHeight+1) - blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block = sf.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit)) + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} curState, err = sm.UpdateState(curState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { @@ -882,8 +910,12 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) - block := makeBlock(updatedState, updatedState.LastBlockHeight+1) - blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} + block := sf.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit)) + + bps, err := block.MakePartSet(testPartSize) + require.NoError(t, err) + + blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} updatedState, err = sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) require.NoError(t, err) @@ -938,7 +970,7 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { pubkey := ed25519.GenPrivKey().PubKey() // Swap the first validator with a new one (validator set size stays the same). - header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, pubkey) + header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(t, state, pubkey) // Save state etc. var validatorUpdates []*types.Validator @@ -977,7 +1009,7 @@ func TestStateMakeBlock(t *testing.T) { proposerAddress := state.Validators.GetProposer().Address stateVersion := state.Version.Consensus - block := makeBlock(state, 2) + block := sf.MakeBlock(state, 2, new(types.Commit)) // test we set some fields assert.Equal(t, stateVersion, block.Version) @@ -1019,13 +1051,13 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { changeIndex++ cp = params[changeIndex] } - header, blockID, responses := makeHeaderPartsResponsesParams(state, cp) + header, blockID, responses := makeHeaderPartsResponsesParams(t, state, cp) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) require.NoError(t, err) state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) - require.Nil(t, err) - err := stateStore.Save(state) + require.NoError(t, err) + err = stateStore.Save(state) require.NoError(t, err) } diff --git a/state/test/factory/block.go b/state/test/factory/block.go new file mode 100644 index 000000000..35e46787c --- /dev/null +++ b/state/test/factory/block.go @@ -0,0 +1,75 @@ +package factory + +import ( + "time" + + sm "github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/test/factory" + "github.com/tendermint/tendermint/types" +) + +func MakeBlocks(n int, state *sm.State, privVal types.PrivValidator) ([]*types.Block, error) { + blocks := make([]*types.Block, n) + + var ( + prevBlock *types.Block + prevBlockMeta *types.BlockMeta + ) + + appHeight := byte(0x01) + for i := 0; i < n; i++ { + height := int64(i + 1) + + block, parts, err := makeBlockAndPartSet(*state, prevBlock, prevBlockMeta, privVal, height) + if err != nil { + return nil, err + } + + blocks[i] = block + + prevBlock = block + prevBlockMeta = types.NewBlockMeta(block, parts) + + // update state + state.AppHash = []byte{appHeight} + appHeight++ + state.LastBlockHeight = height + } + + return blocks, nil +} + +func MakeBlock(state sm.State, height int64, c *types.Commit) *types.Block { + return state.MakeBlock( + height, + factory.MakeTenTxs(state.LastBlockHeight), + c, + nil, + state.Validators.GetProposer().Address, + ) +} + +func makeBlockAndPartSet( + state sm.State, + lastBlock *types.Block, + lastBlockMeta *types.BlockMeta, + privVal types.PrivValidator, + height int64, +) (*types.Block, *types.PartSet, error) { + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil) + if height > 1 { + vote, _ := types.MakeVote( + lastBlock.Header.Height, + lastBlockMeta.BlockID, + state.Validators, + privVal, + lastBlock.Header.ChainID, + time.Now()) + lastCommit = types.NewCommit(vote.Height, vote.Round, + lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) + } + + block := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) + return block, partSet, err +} diff --git a/state/txindex/mocks/tx_indexer.go b/state/txindex/mocks/tx_indexer.go index 5a109672e..64dd50ec7 100644 --- a/state/txindex/mocks/tx_indexer.go +++ b/state/txindex/mocks/tx_indexer.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - query "github.com/tendermint/tendermint/libs/pubsub/query" txindex "github.com/tendermint/tendermint/state/txindex" diff --git a/state/validation_test.go b/state/validation_test.go index afd47a650..f4de55f80 100644 --- a/state/validation_test.go +++ b/state/validation_test.go @@ -12,10 +12,12 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" - memmock "github.com/tendermint/tendermint/mempool/mock" + mpmocks "github.com/tendermint/tendermint/mempool/mocks" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/state/mocks" + sf "github.com/tendermint/tendermint/state/test/factory" + "github.com/tendermint/tendermint/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" ) @@ -29,11 +31,23 @@ func TestValidateBlockHeader(t *testing.T) { state, stateDB, privVals := makeState(3, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -73,12 +87,11 @@ func TestValidateBlockHeader(t *testing.T) { // Build up state for multiple heights for height := int64(1); height < validationTestsStopHeight; height++ { - proposerAddr := state.Validators.GetProposer().Address /* Invalid blocks don't pass */ for _, tc := range testCases { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, proposerAddr) + block := sf.MakeBlock(state, height, lastCommit) tc.malleateBlock(block) err := blockExec.ValidateBlock(state, block) require.Error(t, err, tc.name) @@ -88,7 +101,8 @@ func TestValidateBlockHeader(t *testing.T) { A good block passes */ var err error - state, _, lastCommit, err = makeAndCommitGoodBlock(state, height, lastCommit, proposerAddr, blockExec, privVals, nil) + state, _, lastCommit, err = makeAndCommitGoodBlock( + state, height, lastCommit, state.Validators.GetProposer().Address, blockExec, privVals, nil) require.NoError(t, err, "height %d", height) } } @@ -100,11 +114,23 @@ func TestValidateBlockCommit(t *testing.T) { state, stateDB, privVals := makeState(1, 1) stateStore := sm.NewStore(stateDB) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) + blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -133,7 +159,7 @@ func TestValidateBlockCommit(t *testing.T) { state.LastBlockID, []types.CommitSig{wrongHeightVote.CommitSig()}, ) - block, _ := state.MakeBlock(height, makeTxs(height), wrongHeightCommit, nil, proposerAddr) + block := sf.MakeBlock(state, height, wrongHeightCommit) err = blockExec.ValidateBlock(state, block) _, isErrInvalidCommitHeight := err.(types.ErrInvalidCommitHeight) require.True(t, isErrInvalidCommitHeight, "expected ErrInvalidCommitHeight at height %d but got: %v", height, err) @@ -141,7 +167,7 @@ func TestValidateBlockCommit(t *testing.T) { /* #2589: test len(block.LastCommit.Signatures) == state.LastValidators.Size() */ - block, _ = state.MakeBlock(height, makeTxs(height), wrongSigsCommit, nil, proposerAddr) + block = sf.MakeBlock(state, height, wrongSigsCommit) err = blockExec.ValidateBlock(state, block) _, isErrInvalidCommitSignatures := err.(types.ErrInvalidCommitSignatures) require.True(t, isErrInvalidCommitSignatures, @@ -222,12 +248,23 @@ func TestValidateBlockEvidence(t *testing.T) { evpool.On("ABCIEvidence", mock.AnythingOfType("int64"), mock.AnythingOfType("[]types.Evidence")).Return( []abci.Evidence{}) + mp := &mpmocks.Mempool{} + mp.On("Lock").Return() + mp.On("Unlock").Return() + mp.On("FlushAppConn", mock.Anything).Return(nil) + mp.On("Update", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything).Return(nil) state.ConsensusParams.Evidence.MaxBytes = 1000 blockExec := sm.NewBlockExecutor( stateStore, log.TestingLogger(), proxyApp.Consensus(), - memmock.Mempool{}, + mp, evpool, ) lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil) @@ -248,7 +285,8 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + err := blockExec.ValidateBlock(state, block) if assert.Error(t, err) { _, ok := err.(*types.ErrEvidenceOverflow) diff --git a/statesync/mocks/state_provider.go b/statesync/mocks/state_provider.go index fdd890422..7ff78561f 100644 --- a/statesync/mocks/state_provider.go +++ b/statesync/mocks/state_provider.go @@ -6,7 +6,6 @@ import ( context "context" mock "github.com/stretchr/testify/mock" - state "github.com/tendermint/tendermint/state" types "github.com/tendermint/tendermint/types" diff --git a/store/store_test.go b/store/store_test.go index ea07c73e6..db6cea4c2 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -3,6 +3,7 @@ package store import ( "bytes" "fmt" + stdlog "log" "os" "runtime/debug" "strings" @@ -21,6 +22,7 @@ import ( tmstore "github.com/tendermint/tendermint/proto/tendermint/store" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" sm "github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/state/test/factory" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" "github.com/tendermint/tendermint/version" @@ -42,18 +44,6 @@ func makeTestCommit(height int64, timestamp time.Time) *types.Commit { types.BlockID{Hash: []byte(""), PartSetHeader: types.PartSetHeader{Hash: []byte(""), Total: 2}}, commitSigs) } -func makeTxs(height int64) (txs []types.Tx) { - for i := 0; i < 10; i++ { - txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) - } - return txs -} - -func makeBlock(height int64, state sm.State, lastCommit *types.Commit) *types.Block { - block, _ := state.MakeBlock(height, makeTxs(height), lastCommit, nil, state.Validators.GetProposer().Address) - return block -} - func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore, cleanupFunc) { config := cfg.ResetTestRoot("blockchain_reactor_test") // blockDB := dbm.NewDebugDB("blockDB", dbm.NewMemDB()) @@ -144,9 +134,14 @@ var ( func TestMain(m *testing.M) { var cleanup cleanupFunc + var err error state, _, cleanup = makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer))) - block = makeBlock(1, state, new(types.Commit)) - partSet = block.MakePartSet(2) + block = factory.MakeBlock(state, 1, new(types.Commit)) + + partSet, err = block.MakePartSet(2) + if err != nil { + stdlog.Fatal(err) + } part1 = partSet.GetPart(0) part2 = partSet.GetPart(1) seenCommit1 = makeTestCommit(10, tmtime.Now()) @@ -172,8 +167,9 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { } // save a block - block := makeBlock(bs.Height()+1, state, new(types.Commit)) - validPartSet := block.MakePartSet(2) + block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) + validPartSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(10, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) require.EqualValues(t, 1, bs.Base(), "expecting the new height to be changed") @@ -181,7 +177,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { incompletePartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 2}) uncontiguousPartSet := types.NewPartSetFromHeader(types.PartSetHeader{Total: 0}) - _, err := uncontiguousPartSet.AddPart(part2) + _, err = uncontiguousPartSet.AddPart(part2) require.Error(t, err) header1 := types.Header{ @@ -375,8 +371,9 @@ func TestLoadBaseMeta(t *testing.T) { bs := NewBlockStore(dbm.NewMemDB()) for h := int64(1); h <= 10; h++ { - block := makeBlock(h, state, new(types.Commit)) - partSet := block.MakePartSet(2) + block := factory.MakeBlock(state, h, new(types.Commit)) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -443,8 +440,9 @@ func TestPruneBlocks(t *testing.T) { // make more than 1000 blocks, to test batch deletions for h := int64(1); h <= 1500; h++ { - block := makeBlock(h, state, new(types.Commit)) - partSet := block.MakePartSet(2) + block := factory.MakeBlock(state, h, new(types.Commit)) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) } @@ -552,9 +550,10 @@ func TestBlockFetchAtHeight(t *testing.T) { state, bs, cleanup := makeStateAndBlockStore(log.NewTMLogger(new(bytes.Buffer))) defer cleanup() require.Equal(t, bs.Height(), int64(0), "initially the height should be zero") - block := makeBlock(bs.Height()+1, state, new(types.Commit)) + block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) - partSet := block.MakePartSet(2) + partSet, err := block.MakePartSet(2) + require.NoError(t, err) seenCommit := makeTestCommit(10, tmtime.Now()) bs.SaveBlock(block, partSet, seenCommit) require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed") diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 4366f437c..bf31a80b4 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -259,7 +259,8 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a func (app *Application) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + // None of the transactions are modified by this application. + return abci.ResponsePrepareProposal{ModifiedTx: false} } func (app *Application) Rollback() error { diff --git a/test/factory/tx.go b/test/factory/tx.go new file mode 100644 index 000000000..c97aeefc9 --- /dev/null +++ b/test/factory/tx.go @@ -0,0 +1,16 @@ +package factory + +import "github.com/tendermint/tendermint/types" + +// MakeTxs is a helper function to generate mock transactions by given the block height +// and the transaction numbers. +func MakeTxs(height int64, num int) (txs []types.Tx) { + for i := 0; i < num; i++ { + txs = append(txs, types.Tx([]byte{byte(height), byte(i)})) + } + return txs +} + +func MakeTenTxs(height int64) (txs []types.Tx) { + return MakeTxs(height, 10) +} diff --git a/test/maverick/consensus/state.go b/test/maverick/consensus/state.go index b9b208faa..1cb91682b 100644 --- a/test/maverick/consensus/state.go +++ b/test/maverick/consensus/state.go @@ -1202,8 +1202,17 @@ func (cs *State) defaultDecideProposal(height int64, round int32) { block, blockParts = cs.ValidBlock, cs.ValidBlockParts } else { // Create a new proposal block from state/txs from the mempool. - block, blockParts = cs.createProposalBlock() - if block == nil { + var err error + block, err = cs.createProposalBlock() + if err != nil { + cs.Logger.Error("unable to create proposal block", "error", err) + return + } else if block == nil { + return + } + blockParts, err = block.MakePartSet(types.BlockPartSizeBytes) + if err != nil { + cs.Logger.Error("unable to create proposal block part set", "error", err) return } } @@ -1259,13 +1268,12 @@ func (cs *State) isProposalComplete() bool { // // NOTE: keep it side-effect free for clarity. // CONTRACT: cs.privValidator is not nil. -func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.PartSet) { +func (cs *State) createProposalBlock() (*types.Block, error) { if cs.privValidator == nil { - panic("entered createProposalBlock with privValidator being nil") + return nil, errors.New("entered createProposalBlock with privValidator being nil") } var commit *types.Commit - var votes []*types.Vote switch { case cs.Height == cs.state.InitialHeight: // We're creating a proposal for the first block. @@ -1274,21 +1282,20 @@ func (cs *State) createProposalBlock() (block *types.Block, blockParts *types.Pa case cs.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = cs.LastCommit.MakeCommit() - votes = cs.LastCommit.GetVotes() default: // This shouldn't happen. - cs.Logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") - return + cs.Logger.Error("propose step; cannot propose anything without commit for the previous block") + return nil, nil } if cs.privValidatorPubKey == nil { // If this node is a validator & proposer in the current round, it will // miss the opportunity to create a block. - cs.Logger.Error(fmt.Sprintf("enterPropose: %v", errPubKeyIsNotSet)) - return + cs.Logger.Error("propose step; empty priv validator public key", "err", errPubKeyIsNotSet) + return nil, nil } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, votes) + return cs.blockExec.CreateProposalBlock(cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: any +2/3 prevotes at next round. diff --git a/types/block.go b/types/block.go index 2f0cc487b..f9d1879f0 100644 --- a/types/block.go +++ b/types/block.go @@ -137,22 +137,22 @@ func (b *Block) Hash() tmbytes.HexBytes { // MakePartSet returns a PartSet containing parts of a serialized block. // This is the form in which the block is gossipped to peers. // CONTRACT: partSize is greater than zero. -func (b *Block) MakePartSet(partSize uint32) *PartSet { +func (b *Block) MakePartSet(partSize uint32) (*PartSet, error) { if b == nil { - return nil + return nil, errors.New("nil block") } b.mtx.Lock() defer b.mtx.Unlock() pbb, err := b.ToProto() if err != nil { - panic(err) + return nil, err } bz, err := proto.Marshal(pbb) if err != nil { - panic(err) + return nil, err } - return NewPartSetFromData(bz, partSize) + return NewPartSetFromData(bz, partSize), nil } // HashesTo is a convenience function that checks if a block hashes to the given argument. diff --git a/types/block_test.go b/types/block_test.go index 2355cb0f1..30f3bfbdb 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -110,15 +110,20 @@ func TestBlockHash(t *testing.T) { } func TestBlockMakePartSet(t *testing.T) { - assert.Nil(t, (*Block)(nil).MakePartSet(2)) + bps, err := (*Block)(nil).MakePartSet(2) + assert.Error(t, err) + assert.Nil(t, bps) - partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) + partSet, err := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil, nil).MakePartSet(1024) + require.NoError(t, err) assert.NotNil(t, partSet) assert.EqualValues(t, 1, partSet.Total()) } func TestBlockMakePartSetWithEvidence(t *testing.T) { - assert.Nil(t, (*Block)(nil).MakePartSet(2)) + bps, err := (*Block)(nil).MakePartSet(2) + assert.Error(t, err) + assert.Nil(t, bps) lastID := makeBlockIDRandom() h := int64(3) @@ -130,7 +135,9 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) { ev := NewMockDuplicateVoteEvidenceWithValidator(h, time.Now(), vals[0], "block-test-chain") evList := []Evidence{ev} - partSet := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) + partSet, err := MakeBlock(h, []Tx{Tx("Hello World")}, commit, evList).MakePartSet(512) + require.NoError(t, err) + assert.NotNil(t, partSet) assert.EqualValues(t, 4, partSet.Total()) } diff --git a/types/evidence.go b/types/evidence.go index 35acaaed1..9e71d99c2 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -459,6 +459,16 @@ func (evl EvidenceList) Has(evidence Evidence) bool { return false } +// ToABCI converts the evidence list to a slice of the ABCI protobuf messages +// for use when communicating the evidence to an application. +func (evl EvidenceList) ToABCI() []abci.Evidence { + var el []abci.Evidence + for _, e := range evl { + el = append(el, e.ABCI()...) + } + return el +} + //------------------------------------------ PROTO -------------------------------------- // EvidenceToProto is a generalized function for encoding evidence that conforms to the diff --git a/types/evidence_test.go b/types/evidence_test.go index 946373aad..959eb5086 100644 --- a/types/evidence_test.go +++ b/types/evidence_test.go @@ -245,9 +245,8 @@ func makeVote( vpb := v.ToProto() err = val.SignVote(chainID, vpb) - if err != nil { - panic(err) - } + require.NoError(t, err) + v.Signature = vpb.Signature return v } diff --git a/types/tx.go b/types/tx.go index 5bfc4f925..64617a96f 100644 --- a/types/tx.go +++ b/types/tx.go @@ -5,7 +5,9 @@ import ( "crypto/sha256" "errors" "fmt" + "sort" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/crypto/tmhash" tmbytes "github.com/tendermint/tendermint/libs/bytes" @@ -45,13 +47,8 @@ type Txs []Tx // Hash returns the Merkle root hash of the transaction hashes. // i.e. the leaves of the tree are the hashes of the txs. func (txs Txs) Hash() []byte { - // These allocations will be removed once Txs is switched to [][]byte, - // ref #2603. This is because golang does not allow type casting slices without unsafe - txBzs := make([][]byte, len(txs)) - for i := 0; i < len(txs); i++ { - txBzs[i] = txs[i].Hash() - } - return merkle.HashFromByteSlices(txBzs) + hl := txs.hashList() + return merkle.HashFromByteSlices(hl) } // Index returns the index of this transaction in the list, or -1 if not found @@ -74,16 +71,9 @@ func (txs Txs) IndexByHash(hash []byte) int { return -1 } -// Proof returns a simple merkle proof for this node. -// Panics if i < 0 or i >= len(txs) -// TODO: optimize this! func (txs Txs) Proof(i int) TxProof { - l := len(txs) - bzs := make([][]byte, l) - for i := 0; i < l; i++ { - bzs[i] = txs[i].Hash() - } - root, proofs := merkle.ProofsFromByteSlices(bzs) + hl := txs.hashList() + root, proofs := merkle.ProofsFromByteSlices(hl) return TxProof{ RootHash: root, @@ -92,11 +82,23 @@ func (txs Txs) Proof(i int) TxProof { } } +func (txs Txs) hashList() [][]byte { + hl := make([][]byte, len(txs)) + for i := 0; i < len(txs); i++ { + hl[i] = txs[i].Hash() + } + return hl +} + +// Txs is a slice of transactions. Sorting a Txs value orders the transactions +// lexicographically. +func (txs Txs) Len() int { return len(txs) } +func (txs Txs) Swap(i, j int) { txs[i], txs[j] = txs[j], txs[i] } +func (txs Txs) Less(i, j int) bool { + return bytes.Compare(txs[i], txs[j]) == -1 +} + // ToSliceOfBytes converts a Txs to slice of byte slices. -// -// NOTE: This method should become obsolete once Txs is switched to [][]byte. -// ref: #2603 -// TODO This function is to disappear when TxRecord is introduced func (txs Txs) ToSliceOfBytes() [][]byte { txBzs := make([][]byte, len(txs)) for i := 0; i < len(txs); i++ { @@ -105,13 +107,182 @@ func (txs Txs) ToSliceOfBytes() [][]byte { return txBzs } -// ToTxs converts a raw slice of byte slices into a Txs type. -func ToTxs(txs [][]byte) Txs { - txBzs := make(Txs, len(txs)) - for i := 0; i < len(txs); i++ { - txBzs[i] = txs[i] +// TxRecordSet contains indexes into an underlying set of transactions. +// These indexes are useful for validating and working with a list of TxRecords +// from the PrepareProposal response. +// +// Only one copy of the original data is referenced by all of the indexes but a +// transaction may appear in multiple indexes. +type TxRecordSet struct { + // all holds the complete list of all transactions from the original list of + // TxRecords. + all Txs + + // included is an index of the transactions that will be included in the block + // and is constructed from the list of both added and unmodified transactions. + // included maintains the original order that the transactions were present + // in the list of TxRecords. + included Txs + + // added, unmodified, removed, and unknown are indexes for each of the actions + // that may be supplied with a transaction. + // + // Because each transaction only has one action, it can be referenced by + // at most 3 indexes in this data structure: the action-specific index, the + // included index, and the all index. + added Txs + unmodified Txs + removed Txs + unknown Txs +} + +// NewTxRecordSet constructs a new set from the given transaction records. +// The contents of the input transactions are shared by the set, and must not +// be modified during the lifetime of the set. +func NewTxRecordSet(trs []*abci.TxRecord) TxRecordSet { + txrSet := TxRecordSet{ + all: make([]Tx, len(trs)), } - return txBzs + for i, tr := range trs { + + txrSet.all[i] = Tx(tr.Tx) + + // The following set of assignments do not allocate new []byte, they create + // pointers to the already allocated slice. + switch tr.GetAction() { + case abci.TxRecord_UNKNOWN: + txrSet.unknown = append(txrSet.unknown, txrSet.all[i]) + case abci.TxRecord_UNMODIFIED: + txrSet.unmodified = append(txrSet.unmodified, txrSet.all[i]) + txrSet.included = append(txrSet.included, txrSet.all[i]) + case abci.TxRecord_ADDED: + txrSet.added = append(txrSet.added, txrSet.all[i]) + txrSet.included = append(txrSet.included, txrSet.all[i]) + case abci.TxRecord_REMOVED: + txrSet.removed = append(txrSet.removed, txrSet.all[i]) + } + } + return txrSet +} + +// IncludedTxs returns the transactions marked for inclusion in a block. This +// list maintains the order that the transactions were included in the list of +// TxRecords that were used to construct the TxRecordSet. +func (t TxRecordSet) IncludedTxs() []Tx { + return t.included +} + +// AddedTxs returns the transactions added by the application. +func (t TxRecordSet) AddedTxs() []Tx { + return t.added +} + +// RemovedTxs returns the transactions marked for removal by the application. +func (t TxRecordSet) RemovedTxs() []Tx { + return t.removed +} + +// Validate checks that the record set was correctly constructed from the original +// list of transactions. +func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { + if len(t.unknown) > 0 { + return fmt.Errorf("%d transactions marked unknown (first unknown hash: %x)", len(t.unknown), t.unknown[0].Hash()) + } + + // The following validation logic performs a set of sorts on the data in the TxRecordSet indexes. + // It sorts the original transaction list, otxs, once. + // It sorts the new transaction list twice: once when sorting 'all', the total list, + // and once by sorting the set of the added, removed, and unmodified transactions indexes, + // which, when combined, comprise the complete list of modified transactions. + // + // Each of the added, removed, and unmodified indices is then iterated and once + // and each value index is checked against the sorted original list for containment. + // Asymptotically, this yields a total runtime of O(N*log(N) + 2*M*log(M) + M*log(N)). + // in the input size of the original list, N, and the input size of the new list, M, respectively. + // Performance gains are likely possible, but this was preferred for readability and maintainability. + + // Sort a copy of the complete transaction slice so we can check for + // duplication. The copy is so we do not change the original ordering. + // Only the slices are copied, the transaction contents are shared. + allCopy := sortedCopy(t.all) + + var size int64 + for i, cur := range allCopy { + size += int64(len(cur)) + if size > maxSizeBytes { + return fmt.Errorf("transaction data size %d exceeds maximum %d", size, maxSizeBytes) + } + + // allCopy is sorted, so any duplicated data will be adjacent. + if i+1 < len(allCopy) && bytes.Equal(cur, allCopy[i+1]) { + return fmt.Errorf("found duplicate transaction with hash: %x", cur.Hash()) + } + } + + // create copies of each of the action-specific indexes so that order of the original + // indexes can be preserved. + addedCopy := sortedCopy(t.added) + removedCopy := sortedCopy(t.removed) + unmodifiedCopy := sortedCopy(t.unmodified) + + // make a defensive copy of otxs so that the order of + // the caller's data is not altered. + otxsCopy := sortedCopy(otxs) + + if ix, ok := containsAll(otxsCopy, unmodifiedCopy); !ok { + return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", unmodifiedCopy[ix].Hash()) + } + + if ix, ok := containsAll(otxsCopy, removedCopy); !ok { + return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[ix].Hash()) + } + if ix, ok := containsAny(otxsCopy, addedCopy); ok { + return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", addedCopy[ix].Hash()) + } + return nil +} + +func sortedCopy(txs Txs) Txs { + cp := make(Txs, len(txs)) + copy(cp, txs) + sort.Sort(cp) + return cp +} + +// containsAny checks that list a contains one of the transactions in list +// b. If a match is found, the index in b of the matching transaction is returned. +// Both lists must be sorted. +func containsAny(a, b []Tx) (int, bool) { + for i, cur := range b { + if _, ok := contains(a, cur); ok { + return i, true + } + } + return -1, false +} + +// containsAll checks that super contains all of the transactions in the sub +// list. If not all values in sub are present in super, the index in sub of the +// first Tx absent from super is returned. +func containsAll(super, sub Txs) (int, bool) { + for i, cur := range sub { + if _, ok := contains(super, cur); !ok { + return i, false + } + } + return -1, true +} + +// contains checks that the sorted list, set contains elem. If set does contain elem, then the +// index in set of elem is returned. +func contains(set []Tx, elem Tx) (int, bool) { + n := sort.Search(len(set), func(i int) bool { + return bytes.Compare(elem, set[i]) <= 0 + }) + if n == len(set) || !bytes.Equal(elem, set[n]) { + return -1, false + } + return n, true } // TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. diff --git a/types/tx_test.go b/types/tx_test.go index 0ee308ced..efb435b4c 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -2,11 +2,13 @@ package types import ( "bytes" + "math/rand" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" tmrand "github.com/tendermint/tendermint/libs/rand" ctest "github.com/tendermint/tendermint/libs/test" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -20,11 +22,6 @@ func makeTxs(cnt, size int) Txs { return txs } -func randInt(low, high int) int { - off := tmrand.Int() % (high - low) - return low + off -} - func TestTxIndex(t *testing.T) { for i := 0; i < 20; i++ { txs := makeTxs(15, 60) @@ -51,6 +48,160 @@ func TestTxIndexByHash(t *testing.T) { } } +func TestValidateTxRecordSet(t *testing.T) { + t.Run("should error on total transaction size exceeding max data size", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6, 7, 8, 9, 10}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(9, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on duplicate transactions with the same action", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{200}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on duplicate transactions with mixed actions", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{200}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on new transactions marked UNMODIFIED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_UNMODIFIED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on new transactions marked REMOVED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_REMOVED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("should error on existing transaction marked as ADDED", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{5, 4, 3, 2, 1}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{6}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{{0}, {1, 2, 3, 4, 5}}) + require.Error(t, err) + }) + t.Run("should error if any transaction marked as UNKNOWN", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_UNKNOWN, + Tx: Tx([]byte{1, 2, 3, 4, 5}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.Error(t, err) + }) + t.Run("TxRecordSet preserves order", func(t *testing.T) { + trs := []*abci.TxRecord{ + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{100}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{99}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{55}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{12}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{66}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{9}), + }, + { + Action: abci.TxRecord_ADDED, + Tx: Tx([]byte{17}), + }, + } + txrSet := NewTxRecordSet(trs) + err := txrSet.Validate(100, []Tx{}) + require.NoError(t, err) + for i, tx := range txrSet.IncludedTxs() { + require.Equal(t, Tx(trs[i].Tx), tx) + } + }) +} + func TestValidTxProof(t *testing.T) { cases := []struct { txs Txs @@ -149,3 +300,7 @@ func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) { } } } + +func randInt(low, high int) int { + return rand.Intn(high-low) + low +} diff --git a/types/vote_set.go b/types/vote_set.go index 2d6a64ece..829b54b53 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -227,6 +227,9 @@ func (voteSet *VoteSet) getVote(valIndex int32, blockKey string) (vote *Vote, ok } func (voteSet *VoteSet) GetVotes() []*Vote { + if voteSet == nil { + return nil + } return voteSet.votes } @@ -631,6 +634,7 @@ func (voteSet *VoteSet) MakeCommit() *Commit { if commitSig.ForBlock() && !v.BlockID.Equals(*voteSet.maj23) { commitSig = NewCommitSigAbsent() } + commitSigs[i] = commitSig }