diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index d2b2d99fe..6b98d54bb 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -284,7 +284,7 @@ func (app *Application) PrepareProposal(req types.RequestPrepareProposal) types. app.mu.Lock() defer app.mu.Unlock() - return types.ResponsePrepareProposal{BlockData: app.substPrepareTx(req.BlockData)} + return types.ResponsePrepareProposal{TxRecords: app.substPrepareTx(req.Txs)} } func (*Application) ProcessProposal(req types.RequestProcessProposal) types.ResponseProcessProposal { @@ -420,7 +420,7 @@ func (app *Application) updateValidator(v types.ValidatorUpdate) *types.ExecTxRe const PreparePrefix = "prepare" func isPrepareTx(tx []byte) bool { - return strings.HasPrefix(string(tx), PreparePrefix) + return bytes.HasPrefix(tx, []byte(PreparePrefix)) } // execPrepareTx is noop. tx data is considered as placeholder @@ -430,16 +430,30 @@ func (app *Application) execPrepareTx(tx []byte) *types.ExecTxResult { return &types.ExecTxResult{} } -// substPrepareTx subst all the preparetx in the blockdata -// to null string(could be any arbitrary string). -func (app *Application) substPrepareTx(blockData [][]byte) [][]byte { - // TODO: this mechanism will change with the current spec of PrepareProposal - // We now have a special type for marking a tx as changed +// 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 *Application) substPrepareTx(blockData [][]byte) []*types.TxRecord { + trs := make([]*types.TxRecord, len(blockData)) + var removed []*types.TxRecord for i, tx := range blockData { if isPrepareTx(tx) { - blockData[i] = make([]byte, len(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 blockData + return append(trs, removed...) } diff --git a/abci/types/result.go b/abci/types/types.go similarity index 83% rename from abci/types/result.go rename to abci/types/types.go index a7198b633..4240301b5 100644 --- a/abci/types/result.go +++ b/abci/types/types.go @@ -167,3 +167,31 @@ func RespondVerifyVoteExtension(ok bool) ResponseVerifyVoteExtension { Result: result, } } + +// deterministicExecTxResult constructs a copy of response that omits +// non-deterministic fields. The input response is not modified. +func deterministicExecTxResult(response *ExecTxResult) *ExecTxResult { + return &ExecTxResult{ + Code: response.Code, + Data: response.Data, + GasWanted: response.GasWanted, + GasUsed: response.GasUsed, + } +} + +// MarshalTxResults encodes the the TxResults as a list of byte +// slices. It strips off the non-deterministic pieces of the TxResults +// so that the resulting data can be used for hash comparisons and used +// in Merkle proofs. +func MarshalTxResults(r []*ExecTxResult) ([][]byte, error) { + s := make([][]byte, len(r)) + for i, e := range r { + d := deterministicExecTxResult(e) + b, err := d.Marshal() + if err != nil { + return nil, err + } + s[i] = b + } + return s, nil +} diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 06a25a86d..b42c1e0bf 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -191,6 +191,38 @@ func (ResponseVerifyVoteExtension_Result) EnumDescriptor() ([]byte, []int) { return fileDescriptor_252557cfdd89a31a, []int{37, 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{47, 0} +} + type Request struct { // Types that are valid to be assigned to Value: // *Request_Echo @@ -1347,15 +1379,15 @@ func (m *RequestVerifyVoteExtension) GetVote() *types1.Vote { } 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{} } @@ -1391,27 +1423,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 0 + return types1.Header{} } -func (m *RequestPrepareProposal) GetVotes() []*types1.Vote { +func (m *RequestPrepareProposal) GetTxs() [][]byte { if m != nil { - return m.Votes + 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 +} + type RequestProcessProposal struct { Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` Header types1.Header `protobuf:"bytes,2,opt,name=header,proto3" json:"header"` @@ -2920,7 +2973,12 @@ func (m *ResponseVerifyVoteExtension) GetResult() ResponseVerifyVoteExtension_Re } 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"` + AppHash []byte `protobuf:"bytes,3,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` + TxResults []*ExecTxResult `protobuf:"bytes,4,rep,name=tx_results,json=txResults,proto3" json:"tx_results,omitempty"` + ValidatorUpdates []*ValidatorUpdate `protobuf:"bytes,5,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates,omitempty"` + ConsensusParamUpdates *types1.ConsensusParams `protobuf:"bytes,6,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2956,9 +3014,44 @@ 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.ModifiedTx + } + return false +} + +func (m *ResponsePrepareProposal) GetTxRecords() []*TxRecord { + if m != nil { + return m.TxRecords + } + return nil +} + +func (m *ResponsePrepareProposal) GetAppHash() []byte { + if m != nil { + return m.AppHash + } + return nil +} + +func (m *ResponsePrepareProposal) GetTxResults() []*ExecTxResult { + if m != nil { + return m.TxResults + } + return nil +} + +func (m *ResponsePrepareProposal) GetValidatorUpdates() []*ValidatorUpdate { if m != nil { - return m.BlockData + return m.ValidatorUpdates + } + return nil +} + +func (m *ResponsePrepareProposal) GetConsensusParamUpdates() *types1.ConsensusParams { + if m != nil { + return m.ConsensusParamUpdates } return nil } @@ -3175,6 +3268,58 @@ func (m *CommitInfo) 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{42} +} +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. @@ -3187,7 +3332,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{42} + return fileDescriptor_252557cfdd89a31a, []int{43} } func (m *Event) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3241,7 +3386,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{43} + return fileDescriptor_252557cfdd89a31a, []int{44} } func (m *EventAttribute) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3309,7 +3454,7 @@ func (m *ExecTxResult) Reset() { *m = ExecTxResult{} } func (m *ExecTxResult) String() string { return proto.CompactTextString(m) } func (*ExecTxResult) ProtoMessage() {} func (*ExecTxResult) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{44} + return fileDescriptor_252557cfdd89a31a, []int{45} } func (m *ExecTxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3408,7 +3553,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{45} + return fileDescriptor_252557cfdd89a31a, []int{46} } func (m *TxResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3465,6 +3610,58 @@ func (m *TxResult) GetResult() ExecTxResult { return ExecTxResult{} } +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{47} +} +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"` @@ -3476,7 +3673,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{46} + return fileDescriptor_252557cfdd89a31a, []int{48} } func (m *Validator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3529,7 +3726,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{47} + return fileDescriptor_252557cfdd89a31a, []int{49} } func (m *ValidatorUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3582,7 +3779,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{48} + return fileDescriptor_252557cfdd89a31a, []int{50} } func (m *VoteInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3625,6 +3822,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{51} +} +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 @@ -3643,7 +3900,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{49} + return fileDescriptor_252557cfdd89a31a, []int{52} } func (m *Evidence) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3719,7 +3976,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{50} + return fileDescriptor_252557cfdd89a31a, []int{53} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3789,6 +4046,7 @@ func init() { 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.ResponseVerifyVoteExtension_Result", ResponseVerifyVoteExtension_Result_name, ResponseVerifyVoteExtension_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") @@ -3831,13 +4089,16 @@ func init() { proto.RegisterType((*ResponseProcessProposal)(nil), "tendermint.abci.ResponseProcessProposal") proto.RegisterType((*ResponseFinalizeBlock)(nil), "tendermint.abci.ResponseFinalizeBlock") proto.RegisterType((*CommitInfo)(nil), "tendermint.abci.CommitInfo") + proto.RegisterType((*ExtendedCommitInfo)(nil), "tendermint.abci.ExtendedCommitInfo") proto.RegisterType((*Event)(nil), "tendermint.abci.Event") proto.RegisterType((*EventAttribute)(nil), "tendermint.abci.EventAttribute") proto.RegisterType((*ExecTxResult)(nil), "tendermint.abci.ExecTxResult") 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") } @@ -3845,209 +4106,220 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3225 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5a, 0xcd, 0x73, 0xdb, 0xd6, - 0x11, 0xe7, 0xb7, 0xc8, 0xe5, 0xa7, 0x9e, 0x14, 0x85, 0x66, 0x6c, 0xc9, 0x81, 0x27, 0x89, 0xe3, - 0x38, 0x52, 0x23, 0x4f, 0x52, 0x67, 0x92, 0xb6, 0x23, 0xd2, 0x54, 0x28, 0x4b, 0x91, 0x14, 0x88, - 0x72, 0x26, 0x6d, 0x6a, 0x04, 0x24, 0x9e, 0x48, 0xc4, 0x24, 0x80, 0x00, 0x20, 0x23, 0xf9, 0xd4, - 0xe9, 0x4c, 0x2e, 0x99, 0x76, 0x9a, 0x63, 0x67, 0x3a, 0x99, 0x5e, 0x7a, 0xe8, 0x1f, 0xd0, 0x43, - 0x4f, 0x3d, 0xf5, 0x90, 0x43, 0x0f, 0xb9, 0xb5, 0xd3, 0x43, 0xda, 0x49, 0x6e, 0xfd, 0x07, 0x7a, - 0xea, 0xc7, 0xbc, 0x0f, 0x7c, 0x91, 0x04, 0x3f, 0x62, 0xbb, 0x97, 0xde, 0xf0, 0x16, 0xbb, 0x8b, - 0xf7, 0x16, 0xef, 0xed, 0xee, 0x6f, 0xf7, 0xc1, 0x33, 0x36, 0xd6, 0x14, 0x6c, 0xf6, 0x55, 0xcd, - 0xde, 0x92, 0x5b, 0x6d, 0x75, 0xcb, 0xbe, 0x30, 0xb0, 0xb5, 0x69, 0x98, 0xba, 0xad, 0xa3, 0xa2, - 0xf7, 0x72, 0x93, 0xbc, 0xac, 0x5c, 0xf1, 0x71, 0xb7, 0xcd, 0x0b, 0xc3, 0xd6, 0xb7, 0x0c, 0x53, - 0xd7, 0xcf, 0x18, 0x7f, 0xe5, 0xb2, 0xef, 0x35, 0xd5, 0xe3, 0xd7, 0x16, 0x78, 0xcb, 0x85, 0x1f, - 0xe0, 0x0b, 0xe7, 0xed, 0x95, 0x31, 0x59, 0x43, 0x36, 0xe5, 0xbe, 0xf3, 0x7a, 0xa3, 0xa3, 0xeb, - 0x9d, 0x1e, 0xde, 0xa2, 0xa3, 0xd6, 0xe0, 0x6c, 0xcb, 0x56, 0xfb, 0xd8, 0xb2, 0xe5, 0xbe, 0xc1, - 0x19, 0x56, 0x3b, 0x7a, 0x47, 0xa7, 0x8f, 0x5b, 0xe4, 0x89, 0x51, 0x85, 0xff, 0x00, 0x2c, 0x89, - 0xf8, 0xa3, 0x01, 0xb6, 0x6c, 0xb4, 0x0d, 0x09, 0xdc, 0xee, 0xea, 0xe5, 0xe8, 0xd5, 0xe8, 0xf5, - 0xec, 0xf6, 0xe5, 0xcd, 0x91, 0xc5, 0x6d, 0x72, 0xbe, 0x7a, 0xbb, 0xab, 0x37, 0x22, 0x22, 0xe5, - 0x45, 0xaf, 0x42, 0xf2, 0xac, 0x37, 0xb0, 0xba, 0xe5, 0x18, 0x15, 0xba, 0x12, 0x26, 0xb4, 0x4b, - 0x98, 0x1a, 0x11, 0x91, 0x71, 0x93, 0x4f, 0xa9, 0xda, 0x99, 0x5e, 0x8e, 0x4f, 0xff, 0xd4, 0x9e, - 0x76, 0x46, 0x3f, 0x45, 0x78, 0x51, 0x15, 0x40, 0xd5, 0x54, 0x5b, 0x6a, 0x77, 0x65, 0x55, 0x2b, - 0x27, 0xa8, 0xe4, 0xb3, 0xe1, 0x92, 0xaa, 0x5d, 0x23, 0x8c, 0x8d, 0x88, 0x98, 0x51, 0x9d, 0x01, - 0x99, 0xee, 0x47, 0x03, 0x6c, 0x5e, 0x94, 0x93, 0xd3, 0xa7, 0xfb, 0x0e, 0x61, 0x22, 0xd3, 0xa5, - 0xdc, 0x68, 0x0f, 0xb2, 0x2d, 0xdc, 0x51, 0x35, 0xa9, 0xd5, 0xd3, 0xdb, 0x0f, 0xca, 0x29, 0x2a, - 0x2c, 0x84, 0x09, 0x57, 0x09, 0x6b, 0x95, 0x70, 0x56, 0x63, 0xe5, 0x68, 0x23, 0x22, 0x42, 0xcb, - 0xa5, 0xa0, 0x37, 0x21, 0xdd, 0xee, 0xe2, 0xf6, 0x03, 0xc9, 0x3e, 0x2f, 0x2f, 0x51, 0x3d, 0x1b, - 0x61, 0x7a, 0x6a, 0x84, 0xaf, 0x79, 0xde, 0x88, 0x88, 0x4b, 0x6d, 0xf6, 0x88, 0x76, 0x01, 0x14, - 0xdc, 0x53, 0x87, 0xd8, 0x24, 0xf2, 0xe9, 0xe9, 0x36, 0xb8, 0xc3, 0x38, 0x9b, 0xe7, 0x7c, 0x1a, - 0x19, 0xc5, 0x21, 0xa0, 0x1a, 0x64, 0xb0, 0xa6, 0xf0, 0xe5, 0x64, 0xa8, 0x9a, 0xab, 0xa1, 0xff, - 0x5b, 0x53, 0xfc, 0x8b, 0x49, 0x63, 0x3e, 0x46, 0xb7, 0x21, 0xd5, 0xd6, 0xfb, 0x7d, 0xd5, 0x2e, - 0x03, 0xd5, 0xb0, 0x1e, 0xba, 0x10, 0xca, 0xd5, 0x88, 0x88, 0x9c, 0x1f, 0x1d, 0x42, 0xa1, 0xa7, - 0x5a, 0xb6, 0x64, 0x69, 0xb2, 0x61, 0x75, 0x75, 0xdb, 0x2a, 0x67, 0xa9, 0x86, 0xe7, 0xc2, 0x34, - 0x1c, 0xa8, 0x96, 0x7d, 0xe2, 0x30, 0x37, 0x22, 0x62, 0xbe, 0xe7, 0x27, 0x10, 0x7d, 0xfa, 0xd9, - 0x19, 0x36, 0x5d, 0x85, 0xe5, 0xdc, 0x74, 0x7d, 0x47, 0x84, 0xdb, 0x91, 0x27, 0xfa, 0x74, 0x3f, - 0x01, 0xfd, 0x08, 0x56, 0x7a, 0xba, 0xac, 0xb8, 0xea, 0xa4, 0x76, 0x77, 0xa0, 0x3d, 0x28, 0xe7, - 0xa9, 0xd2, 0x17, 0x43, 0x27, 0xa9, 0xcb, 0x8a, 0xa3, 0xa2, 0x46, 0x04, 0x1a, 0x11, 0x71, 0xb9, - 0x37, 0x4a, 0x44, 0xf7, 0x61, 0x55, 0x36, 0x8c, 0xde, 0xc5, 0xa8, 0xf6, 0x02, 0xd5, 0x7e, 0x23, - 0x4c, 0xfb, 0x0e, 0x91, 0x19, 0x55, 0x8f, 0xe4, 0x31, 0x2a, 0x6a, 0x42, 0xc9, 0x30, 0xb1, 0x21, - 0x9b, 0x58, 0x32, 0x4c, 0xdd, 0xd0, 0x2d, 0xb9, 0x57, 0x2e, 0x52, 0xdd, 0x2f, 0x84, 0xe9, 0x3e, - 0x66, 0xfc, 0xc7, 0x9c, 0xbd, 0x11, 0x11, 0x8b, 0x46, 0x90, 0xc4, 0xb4, 0xea, 0x6d, 0x6c, 0x59, - 0x9e, 0xd6, 0xd2, 0x2c, 0xad, 0x94, 0x3f, 0xa8, 0x35, 0x40, 0x42, 0x75, 0xc8, 0xe2, 0x73, 0x22, - 0x2e, 0x0d, 0x75, 0x1b, 0x97, 0x97, 0xa7, 0x1f, 0xac, 0x3a, 0x65, 0xbd, 0xa7, 0xdb, 0x98, 0x1c, - 0x2a, 0xec, 0x8e, 0x90, 0x0c, 0x4f, 0x0d, 0xb1, 0xa9, 0x9e, 0x5d, 0x50, 0x35, 0x12, 0x7d, 0x63, - 0xa9, 0xba, 0x56, 0x46, 0x54, 0xe1, 0x4b, 0x61, 0x0a, 0xef, 0x51, 0x21, 0xa2, 0xa2, 0xee, 0x88, - 0x34, 0x22, 0xe2, 0xca, 0x70, 0x9c, 0x4c, 0xb6, 0xd8, 0x99, 0xaa, 0xc9, 0x3d, 0xf5, 0x21, 0xe6, - 0xc7, 0x66, 0x65, 0xfa, 0x16, 0xdb, 0xe5, 0xdc, 0xf4, 0xac, 0x90, 0x2d, 0x76, 0xe6, 0x27, 0x54, - 0x97, 0x20, 0x39, 0x94, 0x7b, 0x03, 0x2c, 0xbc, 0x00, 0x59, 0x9f, 0x63, 0x45, 0x65, 0x58, 0xea, - 0x63, 0xcb, 0x92, 0x3b, 0x98, 0xfa, 0xe1, 0x8c, 0xe8, 0x0c, 0x85, 0x02, 0xe4, 0xfc, 0xce, 0x54, - 0xf8, 0x2c, 0xea, 0x4a, 0x12, 0x3f, 0x49, 0x24, 0x87, 0xd8, 0xa4, 0xcb, 0xe6, 0x92, 0x7c, 0x88, - 0xae, 0x41, 0x9e, 0x4e, 0x59, 0x72, 0xde, 0x13, 0x67, 0x9d, 0x10, 0x73, 0x94, 0x78, 0x8f, 0x33, - 0x6d, 0x40, 0xd6, 0xd8, 0x36, 0x5c, 0x96, 0x38, 0x65, 0x01, 0x63, 0xdb, 0x70, 0x18, 0x9e, 0x85, - 0x1c, 0x59, 0x9f, 0xcb, 0x91, 0xa0, 0x1f, 0xc9, 0x12, 0x1a, 0x67, 0x11, 0xfe, 0x14, 0x83, 0xd2, - 0xa8, 0x03, 0x46, 0xb7, 0x21, 0x41, 0x62, 0x11, 0x0f, 0x2b, 0x95, 0x4d, 0x16, 0xa8, 0x36, 0x9d, - 0x40, 0xb5, 0xd9, 0x74, 0x02, 0x55, 0x35, 0xfd, 0xc5, 0x57, 0x1b, 0x91, 0xcf, 0xfe, 0xb6, 0x11, - 0x15, 0xa9, 0x04, 0xba, 0x44, 0x7c, 0xa5, 0xac, 0x6a, 0x92, 0xaa, 0xd0, 0x29, 0x67, 0x88, 0x23, - 0x94, 0x55, 0x6d, 0x4f, 0x41, 0x07, 0x50, 0x6a, 0xeb, 0x9a, 0x85, 0x35, 0x6b, 0x60, 0x49, 0x2c, - 0x10, 0xf2, 0x60, 0x12, 0x70, 0x87, 0x2c, 0xbc, 0xd6, 0x1c, 0xce, 0x63, 0xca, 0x28, 0x16, 0xdb, - 0x41, 0x02, 0x71, 0xab, 0x43, 0xb9, 0xa7, 0x2a, 0xb2, 0xad, 0x9b, 0x56, 0x39, 0x71, 0x35, 0x3e, - 0xd1, 0x1f, 0xde, 0x73, 0x58, 0x4e, 0x0d, 0x45, 0xb6, 0x71, 0x35, 0x41, 0xa6, 0x2b, 0xfa, 0x24, - 0xd1, 0xf3, 0x50, 0x94, 0x0d, 0x43, 0xb2, 0x6c, 0xd9, 0xc6, 0x52, 0xeb, 0xc2, 0xc6, 0x16, 0x0d, - 0x34, 0x39, 0x31, 0x2f, 0x1b, 0xc6, 0x09, 0xa1, 0x56, 0x09, 0x11, 0x3d, 0x07, 0x05, 0x12, 0x93, - 0x54, 0xb9, 0x27, 0x75, 0xb1, 0xda, 0xe9, 0xda, 0x34, 0xa4, 0xc4, 0xc5, 0x3c, 0xa7, 0x36, 0x28, - 0x51, 0x50, 0xdc, 0x3f, 0x4e, 0xe3, 0x11, 0x42, 0x90, 0x50, 0x64, 0x5b, 0xa6, 0x96, 0xcc, 0x89, - 0xf4, 0x99, 0xd0, 0x0c, 0xd9, 0xee, 0x72, 0xfb, 0xd0, 0x67, 0xb4, 0x06, 0x29, 0xae, 0x36, 0x4e, - 0xd5, 0xf2, 0x11, 0x5a, 0x85, 0xa4, 0x61, 0xea, 0x43, 0x4c, 0x7f, 0x5d, 0x5a, 0x64, 0x03, 0xe1, - 0x27, 0x31, 0x58, 0x1e, 0x8b, 0x5c, 0x44, 0x6f, 0x57, 0xb6, 0xba, 0xce, 0xb7, 0xc8, 0x33, 0x7a, - 0x8d, 0xe8, 0x95, 0x15, 0x6c, 0xf2, 0x68, 0x5f, 0x1e, 0x37, 0x75, 0x83, 0xbe, 0xe7, 0xa6, 0xe1, - 0xdc, 0x68, 0x1f, 0x4a, 0x3d, 0xd9, 0xb2, 0x25, 0xe6, 0xfd, 0x25, 0x5f, 0xe4, 0x7f, 0x66, 0xcc, - 0xc8, 0x2c, 0x56, 0x90, 0x0d, 0xcd, 0x95, 0x14, 0x88, 0xa8, 0x47, 0x45, 0x22, 0xac, 0xb6, 0x2e, - 0x1e, 0xca, 0x9a, 0xad, 0x6a, 0x58, 0x1a, 0xfb, 0x6b, 0x97, 0xc6, 0x14, 0xd6, 0x87, 0xaa, 0x82, - 0xb5, 0xb6, 0xf3, 0xbb, 0x56, 0x5c, 0x61, 0xf7, 0x77, 0x5a, 0x82, 0x08, 0x85, 0x60, 0xcc, 0x45, - 0x05, 0x88, 0xd9, 0xe7, 0x7c, 0xf1, 0x31, 0xfb, 0x1c, 0x7d, 0x07, 0x12, 0x64, 0x81, 0x74, 0xe1, - 0x85, 0x09, 0x09, 0x0b, 0x97, 0x6b, 0x5e, 0x18, 0x58, 0xa4, 0x9c, 0x82, 0xe0, 0x1e, 0x05, 0x37, - 0x0e, 0x8f, 0x6a, 0x15, 0x5e, 0x84, 0xe2, 0x48, 0x90, 0xf5, 0xfd, 0xbb, 0xa8, 0xff, 0xdf, 0x09, - 0x45, 0xc8, 0x07, 0xa2, 0xa9, 0xb0, 0x06, 0xab, 0x93, 0x82, 0xa3, 0xd0, 0x75, 0xe9, 0x81, 0x20, - 0x87, 0x5e, 0x85, 0xb4, 0x1b, 0x1d, 0xd9, 0x51, 0x1c, 0xb7, 0x95, 0xc3, 0x2c, 0xba, 0xac, 0xe4, - 0x0c, 0x92, 0x2d, 0x4d, 0xf7, 0x42, 0x8c, 0x4e, 0x7c, 0x49, 0x36, 0x8c, 0x86, 0x6c, 0x75, 0x85, - 0x0f, 0xa0, 0x1c, 0x16, 0xf9, 0x46, 0x96, 0x91, 0x70, 0xb7, 0xe0, 0x1a, 0xa4, 0xce, 0x74, 0xb3, - 0x2f, 0xdb, 0x54, 0x59, 0x5e, 0xe4, 0x23, 0xb2, 0x35, 0x59, 0x14, 0x8c, 0x53, 0x32, 0x1b, 0x08, - 0x12, 0x5c, 0x0a, 0x8d, 0x7e, 0x44, 0x44, 0xd5, 0x14, 0xcc, 0xec, 0x99, 0x17, 0xd9, 0xc0, 0x53, - 0xc4, 0x26, 0xcb, 0x06, 0xe4, 0xb3, 0x16, 0x5d, 0x2b, 0xd5, 0x9f, 0x11, 0xf9, 0x48, 0xf8, 0x81, - 0xbb, 0xf5, 0xbd, 0xd8, 0x82, 0x6e, 0x40, 0x82, 0x46, 0x23, 0x66, 0xa5, 0xb5, 0xf1, 0x4d, 0x4e, - 0xb8, 0x44, 0xca, 0x23, 0x34, 0xa0, 0x12, 0x1e, 0x4b, 0x16, 0xd2, 0xf4, 0xf3, 0x28, 0xac, 0x4d, - 0x0e, 0xc7, 0xe8, 0x0a, 0x00, 0xf3, 0xdf, 0xfc, 0xf4, 0xc7, 0xaf, 0xe7, 0xc4, 0x0c, 0xa5, 0xdc, - 0x21, 0x2e, 0xe0, 0x79, 0x28, 0x7a, 0xaf, 0x25, 0x4b, 0x7d, 0xc8, 0xb6, 0x69, 0x5c, 0xcc, 0xbb, - 0x3c, 0x27, 0xea, 0x43, 0x8c, 0x6e, 0x42, 0x92, 0x7c, 0x89, 0x38, 0xca, 0xf8, 0x94, 0xe9, 0x30, - 0x26, 0xe1, 0xd7, 0x31, 0xdf, 0x7c, 0x82, 0x51, 0xfb, 0x71, 0xfa, 0x86, 0x12, 0xc4, 0xed, 0x73, - 0x36, 0xa5, 0x9c, 0x48, 0x1e, 0xd1, 0x09, 0xac, 0xb2, 0x0c, 0x03, 0x2b, 0x92, 0xcf, 0x6d, 0xf0, - 0x8c, 0x7f, 0x0e, 0x8f, 0x81, 0x1c, 0xf1, 0x03, 0xd7, 0x73, 0x84, 0x7a, 0x8d, 0xe4, 0x23, 0x78, - 0x8d, 0x5f, 0xc5, 0xdc, 0xa3, 0x16, 0x08, 0xf6, 0x4f, 0xd8, 0x3e, 0xef, 0xc0, 0x8a, 0x82, 0xdb, - 0xaa, 0xf2, 0x6d, 0xcd, 0xb3, 0xcc, 0xa5, 0x9f, 0xb0, 0x75, 0xfe, 0x9c, 0x85, 0xb4, 0x88, 0x2d, - 0x83, 0x84, 0x5a, 0x54, 0x85, 0x0c, 0x3e, 0x6f, 0x63, 0xc3, 0x76, 0xb2, 0x93, 0xc9, 0x59, 0x1e, - 0xe3, 0xae, 0x3b, 0x9c, 0x04, 0xb3, 0xb8, 0x62, 0xe8, 0x16, 0x87, 0xa7, 0xe1, 0x48, 0x93, 0x8b, - 0xfb, 0xf1, 0xe9, 0x6b, 0x0e, 0x3e, 0x8d, 0x87, 0x42, 0x14, 0x26, 0x35, 0x02, 0x50, 0x6f, 0x71, - 0x80, 0x9a, 0x98, 0xf1, 0xb1, 0x00, 0x42, 0xad, 0x05, 0x10, 0x6a, 0x72, 0xc6, 0x32, 0x43, 0x20, - 0xea, 0x6b, 0x0e, 0x44, 0x4d, 0xcd, 0x98, 0xf1, 0x08, 0x46, 0xbd, 0x1b, 0xc4, 0xa8, 0x0c, 0x5b, - 0x5e, 0x0b, 0x95, 0x9e, 0x0a, 0x52, 0xbf, 0xe7, 0x03, 0xa9, 0xe9, 0x50, 0x74, 0xc8, 0x14, 0x4d, - 0x40, 0xa9, 0x6f, 0x05, 0x50, 0x6a, 0x66, 0x86, 0x1d, 0xa6, 0xc0, 0xd4, 0x3b, 0x7e, 0x98, 0x0a, - 0xa1, 0x68, 0x97, 0xff, 0xf7, 0x30, 0x9c, 0xfa, 0xba, 0x8b, 0x53, 0xb3, 0xa1, 0x80, 0x9b, 0xaf, - 0x65, 0x14, 0xa8, 0x1e, 0x8d, 0x01, 0x55, 0x06, 0x2c, 0x9f, 0x0f, 0x55, 0x31, 0x03, 0xa9, 0x1e, - 0x8d, 0x21, 0xd5, 0xfc, 0x0c, 0x85, 0x33, 0xa0, 0xea, 0xfb, 0x93, 0xa1, 0x6a, 0x38, 0x98, 0xe4, - 0xd3, 0x9c, 0x0f, 0xab, 0x4a, 0x21, 0x58, 0xb5, 0x18, 0x8a, 0xab, 0x98, 0xfa, 0xb9, 0xc1, 0xea, - 0xe9, 0x04, 0xb0, 0xca, 0x60, 0xe5, 0xf5, 0x50, 0xe5, 0x73, 0xa0, 0xd5, 0xd3, 0x09, 0x68, 0x75, - 0x79, 0xa6, 0xda, 0x99, 0x70, 0x75, 0x37, 0x08, 0x57, 0xd1, 0x8c, 0x33, 0x16, 0x8a, 0x57, 0x5b, - 0x61, 0x78, 0x95, 0x61, 0xca, 0x9b, 0xa1, 0x1a, 0x17, 0x00, 0xac, 0x47, 0x63, 0x80, 0x75, 0x75, - 0xc6, 0x4e, 0x9b, 0x17, 0xb1, 0xbe, 0x48, 0x92, 0xa6, 0x11, 0x57, 0x4d, 0xf2, 0x2e, 0x6c, 0x9a, - 0xba, 0xc9, 0xb1, 0x27, 0x1b, 0x08, 0xd7, 0x09, 0x82, 0xf1, 0xdc, 0xf2, 0x14, 0x74, 0x4b, 0xf3, - 0x5b, 0x9f, 0x2b, 0x16, 0x7e, 0x1f, 0xf5, 0x64, 0x69, 0xe2, 0xef, 0x47, 0x3f, 0x19, 0x8e, 0x7e, - 0x7c, 0x98, 0x37, 0x16, 0xc4, 0xbc, 0x1b, 0x90, 0x25, 0x79, 0xeb, 0x08, 0x9c, 0x95, 0x0d, 0x17, - 0xce, 0xde, 0x80, 0x65, 0x1a, 0x3e, 0x59, 0xea, 0xc4, 0x93, 0xd5, 0x04, 0xcd, 0x9b, 0x8a, 0xe4, - 0x05, 0xb3, 0x02, 0xcb, 0x5a, 0x5f, 0x86, 0x15, 0x1f, 0xaf, 0x9b, 0x0f, 0x33, 0x6c, 0x57, 0x72, - 0xb9, 0x77, 0x78, 0x62, 0xfc, 0xc7, 0xa8, 0x67, 0x21, 0x0f, 0x07, 0x4f, 0x82, 0xac, 0xd1, 0xc7, - 0x04, 0x59, 0x63, 0xdf, 0x1a, 0xb2, 0xfa, 0xf3, 0xfb, 0x78, 0x30, 0xbf, 0xff, 0x67, 0xd4, 0xfb, - 0x27, 0x2e, 0x00, 0x6d, 0xeb, 0x0a, 0xe6, 0x19, 0x37, 0x7d, 0x26, 0x09, 0x4a, 0x4f, 0xef, 0xf0, - 0xbc, 0x9a, 0x3c, 0x12, 0x2e, 0x37, 0x76, 0x66, 0x78, 0x68, 0x74, 0x93, 0xf5, 0x24, 0xb5, 0x30, - 0x4f, 0xd6, 0x4b, 0x10, 0x7f, 0x80, 0x59, 0xa4, 0xcb, 0x89, 0xe4, 0x91, 0xf0, 0xd1, 0x4d, 0x46, - 0xe3, 0x57, 0x4e, 0x64, 0x03, 0x74, 0x1b, 0x32, 0xb4, 0x8c, 0x2e, 0xe9, 0x86, 0xc5, 0x03, 0x52, - 0x20, 0xd1, 0x61, 0xd5, 0xf2, 0xcd, 0x63, 0xc2, 0x73, 0x64, 0x58, 0x62, 0xda, 0xe0, 0x4f, 0x3e, - 0x1c, 0x92, 0x09, 0x40, 0xe1, 0xcb, 0x90, 0x21, 0xb3, 0xb7, 0x0c, 0xb9, 0x8d, 0x69, 0x64, 0xc9, - 0x88, 0x1e, 0x41, 0xb8, 0x0f, 0x68, 0x3c, 0x4e, 0xa2, 0x06, 0xa4, 0xf0, 0x10, 0x6b, 0xb6, 0x45, - 0x53, 0xf0, 0x91, 0x04, 0x9a, 0xe7, 0x45, 0x58, 0xb3, 0xab, 0x65, 0x62, 0xe4, 0x7f, 0x7c, 0xb5, - 0x51, 0x62, 0xdc, 0x37, 0xf5, 0xbe, 0x6a, 0xe3, 0xbe, 0x61, 0x5f, 0x88, 0x5c, 0x5e, 0xf8, 0x6b, - 0x8c, 0x00, 0xbf, 0x40, 0xfc, 0x9c, 0x68, 0x5b, 0x67, 0xcb, 0xc7, 0x7c, 0x80, 0x7f, 0x3e, 0x7b, - 0x5f, 0x01, 0xe8, 0xc8, 0x96, 0xf4, 0xb1, 0xac, 0xd9, 0x58, 0xe1, 0x46, 0xcf, 0x74, 0x64, 0xeb, - 0x5d, 0x4a, 0x20, 0x7f, 0x9d, 0xbc, 0x1e, 0x58, 0x58, 0xe1, 0xa5, 0x87, 0xa5, 0x8e, 0x6c, 0x9d, - 0x5a, 0x58, 0xf1, 0xad, 0x72, 0xe9, 0xd1, 0x56, 0x19, 0xb4, 0x71, 0x7a, 0xc4, 0xc6, 0x3e, 0x48, - 0x96, 0xf1, 0x43, 0x32, 0x54, 0x81, 0xb4, 0x61, 0xaa, 0xba, 0xa9, 0xda, 0x17, 0xf4, 0xc7, 0xc4, - 0x45, 0x77, 0x8c, 0xae, 0x41, 0xbe, 0x8f, 0xfb, 0x86, 0xae, 0xf7, 0x24, 0xe6, 0x6c, 0xb2, 0x54, - 0x34, 0xc7, 0x89, 0x75, 0xea, 0x73, 0x3e, 0x89, 0x79, 0xa7, 0xcf, 0x83, 0xde, 0x8f, 0xd7, 0xbc, - 0xeb, 0x13, 0xcc, 0xeb, 0xa3, 0x90, 0x45, 0x8c, 0xd8, 0xd7, 0x1d, 0xff, 0xaf, 0x0c, 0x2c, 0xfc, - 0x8c, 0x16, 0xe3, 0x82, 0xb9, 0x11, 0x3a, 0x81, 0x65, 0xf7, 0xf0, 0x4b, 0x03, 0xea, 0x14, 0x9c, - 0xed, 0x3c, 0xaf, 0xf7, 0x28, 0x0d, 0x83, 0x64, 0x0b, 0xbd, 0x07, 0x4f, 0x8f, 0x78, 0x36, 0x57, - 0x75, 0x6c, 0x5e, 0x07, 0xf7, 0x54, 0xd0, 0xc1, 0x39, 0xaa, 0x3d, 0x63, 0xc5, 0x1f, 0xf1, 0xcc, - 0xed, 0x41, 0x21, 0x98, 0xe6, 0x4d, 0xfc, 0xfd, 0xd7, 0x20, 0x6f, 0x62, 0x5b, 0x56, 0x35, 0x29, - 0x50, 0x41, 0xcb, 0x31, 0x22, 0xaf, 0xcb, 0x1d, 0xc3, 0x53, 0x13, 0xd3, 0x3d, 0xf4, 0x5d, 0xc8, - 0x78, 0x99, 0x62, 0x34, 0x04, 0x3c, 0xb9, 0x45, 0x16, 0x8f, 0x57, 0xf8, 0x43, 0xd4, 0x53, 0x19, - 0x2c, 0xdb, 0xd4, 0x21, 0x65, 0x62, 0x6b, 0xd0, 0x63, 0x85, 0x94, 0xc2, 0xf6, 0xcb, 0xf3, 0x25, - 0x8a, 0x84, 0x3a, 0xe8, 0xd9, 0x22, 0x17, 0x16, 0xee, 0x43, 0x8a, 0x51, 0x50, 0x16, 0x96, 0x4e, - 0x0f, 0xf7, 0x0f, 0x8f, 0xde, 0x3d, 0x2c, 0x45, 0x10, 0x40, 0x6a, 0xa7, 0x56, 0xab, 0x1f, 0x37, - 0x4b, 0x51, 0x94, 0x81, 0xe4, 0x4e, 0xf5, 0x48, 0x6c, 0x96, 0x62, 0x84, 0x2c, 0xd6, 0xef, 0xd6, - 0x6b, 0xcd, 0x52, 0x1c, 0x2d, 0x43, 0x9e, 0x3d, 0x4b, 0xbb, 0x47, 0xe2, 0xdb, 0x3b, 0xcd, 0x52, - 0xc2, 0x47, 0x3a, 0xa9, 0x1f, 0xde, 0xa9, 0x8b, 0xa5, 0xa4, 0xf0, 0x0a, 0x5c, 0x0a, 0x4d, 0x2d, - 0xbd, 0x9a, 0x4c, 0xd4, 0x57, 0x93, 0x11, 0x7e, 0x19, 0x83, 0x4a, 0x78, 0xbe, 0x88, 0xee, 0x8e, - 0x2c, 0x7c, 0x7b, 0x81, 0x64, 0x73, 0x64, 0xf5, 0xe8, 0x39, 0x28, 0x98, 0xf8, 0x0c, 0xdb, 0xed, - 0x2e, 0xcb, 0x5f, 0x59, 0xc0, 0xcc, 0x8b, 0x79, 0x4e, 0xa5, 0x42, 0x16, 0x63, 0xfb, 0x10, 0xb7, - 0x6d, 0x89, 0xf9, 0x22, 0xb6, 0xe9, 0x32, 0x84, 0x8d, 0x50, 0x4f, 0x18, 0x51, 0xf8, 0x60, 0x21, - 0x5b, 0x66, 0x20, 0x29, 0xd6, 0x9b, 0xe2, 0x7b, 0xa5, 0x38, 0x42, 0x50, 0xa0, 0x8f, 0xd2, 0xc9, - 0xe1, 0xce, 0xf1, 0x49, 0xe3, 0x88, 0xd8, 0x72, 0x05, 0x8a, 0x8e, 0x2d, 0x1d, 0x62, 0x52, 0x78, - 0xdf, 0x8b, 0x3f, 0xbe, 0xba, 0xd4, 0x2e, 0x14, 0x46, 0xd2, 0xc5, 0xe8, 0x38, 0x9e, 0xf1, 0x0a, - 0x39, 0x6e, 0x2a, 0x28, 0xe6, 0x87, 0xfe, 0xa1, 0xf0, 0x9b, 0x28, 0x3c, 0x33, 0x25, 0xa1, 0x44, - 0xfb, 0x23, 0x96, 0xbf, 0xb5, 0x48, 0x3a, 0x3a, 0xba, 0xf1, 0x6e, 0xcf, 0x65, 0xac, 0x93, 0x83, - 0x9d, 0x93, 0x46, 0x70, 0xe3, 0x09, 0xb7, 0xe1, 0xe9, 0x90, 0x8c, 0x7f, 0x46, 0x41, 0x4c, 0xf8, - 0x5d, 0xcc, 0x2f, 0x1a, 0x4c, 0xe1, 0xd7, 0x20, 0x25, 0xb7, 0x49, 0xd2, 0x4a, 0x17, 0x97, 0x16, - 0xf9, 0x68, 0x4a, 0x9d, 0x13, 0xbd, 0x09, 0x60, 0x9f, 0x4b, 0x6c, 0x3d, 0x8e, 0x1f, 0x1a, 0xaf, - 0x08, 0xd4, 0xcf, 0x71, 0xbb, 0x79, 0xce, 0x57, 0x9f, 0xb1, 0xf9, 0x93, 0x85, 0xde, 0x9e, 0xe4, - 0x71, 0xe7, 0x6c, 0x31, 0x2c, 0xe6, 0x6b, 0x93, 0x8f, 0xe6, 0x6b, 0x85, 0x5f, 0xc4, 0x3d, 0x27, - 0x14, 0x2c, 0x68, 0x3d, 0xb6, 0xcc, 0x67, 0xc4, 0x96, 0xb1, 0x05, 0x6d, 0x39, 0x31, 0x7a, 0xc5, - 0x9f, 0x5c, 0xf4, 0x4a, 0x3c, 0x62, 0xf4, 0xf2, 0x6f, 0xaa, 0x64, 0x70, 0x53, 0x8d, 0x05, 0x9a, - 0xd4, 0x84, 0x40, 0xf3, 0x1e, 0x80, 0xaf, 0xf3, 0xb1, 0x0a, 0x49, 0x53, 0x1f, 0x68, 0x0a, 0xdd, - 0xb9, 0x49, 0x91, 0x0d, 0xd0, 0xab, 0x4e, 0x55, 0x37, 0x16, 0x12, 0x6f, 0xc8, 0xf1, 0xf4, 0x95, - 0xff, 0x78, 0x79, 0xf7, 0x21, 0x24, 0xe9, 0x3f, 0x23, 0x51, 0x90, 0x76, 0x36, 0x38, 0xac, 0x22, - 0xcf, 0xe8, 0xc7, 0x00, 0xb2, 0x6d, 0x9b, 0x6a, 0x6b, 0xe0, 0x29, 0xde, 0x98, 0xfc, 0xcf, 0x77, - 0x1c, 0xbe, 0xea, 0x65, 0xfe, 0xf3, 0x57, 0x3d, 0x51, 0xdf, 0x06, 0xf0, 0x29, 0x14, 0x0e, 0xa1, - 0x10, 0x94, 0x75, 0x80, 0x00, 0x9b, 0x43, 0x10, 0x08, 0x30, 0x5c, 0xc7, 0x81, 0x80, 0x0b, 0x23, - 0xe2, 0xac, 0x83, 0x45, 0x07, 0xc2, 0xbf, 0xa3, 0x90, 0xf3, 0x6f, 0x99, 0xff, 0xb7, 0x5c, 0x5a, - 0xf8, 0x24, 0x0a, 0x69, 0x77, 0xf1, 0x21, 0x1d, 0x24, 0xcf, 0x76, 0x31, 0x7f, 0xbf, 0x84, 0xb5, - 0xa4, 0xe2, 0x6e, 0xa3, 0xeb, 0x0d, 0xd7, 0xf9, 0x87, 0x95, 0x3e, 0xfd, 0x96, 0x76, 0x8a, 0xd5, - 0xdc, 0xd9, 0xbf, 0x01, 0x19, 0xf7, 0xd4, 0x11, 0x6c, 0x2e, 0x2b, 0x8a, 0x89, 0x2d, 0x8b, 0xc7, - 0x7d, 0x67, 0x48, 0xfb, 0x90, 0xfa, 0xc7, 0xbc, 0x19, 0x13, 0x17, 0xd9, 0x40, 0x50, 0xa0, 0x38, - 0x72, 0x64, 0xd1, 0x1b, 0xb0, 0x64, 0x0c, 0x5a, 0x92, 0xb3, 0x35, 0x46, 0x6e, 0x0a, 0x39, 0xa8, - 0x6f, 0xd0, 0xea, 0xa9, 0xed, 0x7d, 0x7c, 0xe1, 0x4c, 0xc6, 0x18, 0xb4, 0xf6, 0xd9, 0x0e, 0x62, - 0x5f, 0x89, 0xf9, 0xbf, 0xf2, 0xd3, 0x28, 0xa4, 0x9d, 0x13, 0x81, 0xbe, 0x0f, 0x19, 0xd7, 0x1d, - 0xb8, 0xfd, 0xe9, 0x50, 0x3f, 0xc2, 0xf5, 0x7b, 0x22, 0xe8, 0x06, 0x2c, 0x5b, 0x6a, 0x47, 0x73, - 0x2a, 0xf1, 0xac, 0xcc, 0x12, 0xa3, 0x5b, 0xb3, 0xc8, 0x5e, 0x1c, 0x38, 0xb5, 0x81, 0xbb, 0x89, - 0x74, 0xbc, 0x94, 0xb8, 0x9b, 0x48, 0x27, 0x4a, 0x49, 0xe1, 0x5f, 0x51, 0x48, 0x3b, 0x35, 0x74, - 0xf4, 0x8a, 0xef, 0x00, 0x16, 0x26, 0xd9, 0x9b, 0x33, 0x7a, 0xbd, 0xc5, 0xe0, 0xbc, 0x63, 0x8b, - 0xcf, 0x3b, 0xac, 0x41, 0xec, 0xb4, 0xea, 0x13, 0x0b, 0xb7, 0xea, 0x6f, 0x02, 0xb2, 0x75, 0x5b, - 0xee, 0x49, 0x43, 0xdd, 0x56, 0xb5, 0x8e, 0xc4, 0x2c, 0xcf, 0xce, 0x4a, 0x89, 0xbe, 0xb9, 0x47, - 0x5f, 0x1c, 0xbb, 0x3f, 0xc1, 0xcd, 0x70, 0x17, 0x6d, 0x15, 0xae, 0x41, 0x8a, 0x27, 0x71, 0xac, - 0x57, 0xc8, 0x47, 0x6e, 0xd7, 0x25, 0xe1, 0xeb, 0xba, 0x54, 0x20, 0xdd, 0xc7, 0xb6, 0x4c, 0x0f, - 0x3e, 0x73, 0xc0, 0xee, 0xf8, 0xc6, 0xeb, 0x90, 0xf5, 0x75, 0x6d, 0x89, 0x2f, 0x38, 0xac, 0xbf, - 0x5b, 0x8a, 0x54, 0x96, 0x3e, 0xfd, 0xfc, 0x6a, 0xfc, 0x10, 0x7f, 0x4c, 0x36, 0xb0, 0x58, 0xaf, - 0x35, 0xea, 0xb5, 0xfd, 0x52, 0xb4, 0x92, 0xfd, 0xf4, 0xf3, 0xab, 0x4b, 0x22, 0xa6, 0x25, 0xee, - 0x1b, 0x0d, 0xc8, 0xf9, 0xff, 0x4a, 0x30, 0xb5, 0x41, 0x50, 0xb8, 0x73, 0x7a, 0x7c, 0xb0, 0x57, - 0xdb, 0x69, 0xd6, 0xa5, 0x7b, 0x47, 0xcd, 0x7a, 0x29, 0x8a, 0x9e, 0x86, 0x95, 0x83, 0xbd, 0xb7, - 0x1a, 0x4d, 0xa9, 0x76, 0xb0, 0x57, 0x3f, 0x6c, 0x4a, 0x3b, 0xcd, 0xe6, 0x4e, 0x6d, 0xbf, 0x14, - 0xdb, 0xfe, 0x6d, 0x16, 0x8a, 0x3b, 0xd5, 0xda, 0x1e, 0xc9, 0x61, 0xd5, 0xb6, 0x4c, 0x4b, 0x69, - 0x35, 0x48, 0xd0, 0x62, 0xd9, 0xd4, 0x1b, 0x78, 0x95, 0xe9, 0x0d, 0x10, 0xb4, 0x0b, 0x49, 0x5a, - 0x47, 0x43, 0xd3, 0xaf, 0xe4, 0x55, 0x66, 0x74, 0x44, 0xc8, 0x64, 0xe8, 0x51, 0x99, 0x7a, 0x47, - 0xaf, 0x32, 0xbd, 0x41, 0x82, 0x0e, 0x60, 0xc9, 0x29, 0x73, 0xcc, 0xba, 0xed, 0x56, 0x99, 0xd9, - 0x69, 0x20, 0x4b, 0x63, 0xe5, 0xa8, 0xe9, 0xd7, 0xf7, 0x2a, 0x33, 0x5a, 0x27, 0x68, 0x0f, 0x52, - 0x1c, 0x09, 0xce, 0xb8, 0xb9, 0x56, 0x99, 0xd5, 0x31, 0x40, 0x22, 0x64, 0xbc, 0x42, 0xdf, 0xec, - 0x4b, 0x89, 0x95, 0x39, 0xba, 0x42, 0xe8, 0x3e, 0xe4, 0x83, 0xe8, 0x72, 0xbe, 0xdb, 0x71, 0x95, - 0x39, 0x7b, 0x13, 0x44, 0x7f, 0x10, 0x6a, 0xce, 0x77, 0x5b, 0xae, 0x32, 0x67, 0xab, 0x02, 0x7d, - 0x08, 0xcb, 0xe3, 0x50, 0x70, 0xfe, 0xcb, 0x73, 0x95, 0x05, 0x9a, 0x17, 0xa8, 0x0f, 0x68, 0x02, - 0x84, 0x5c, 0xe0, 0x2e, 0x5d, 0x65, 0x91, 0x5e, 0x06, 0x52, 0xa0, 0x38, 0x0a, 0x49, 0xe6, 0xbd, - 0x5b, 0x57, 0x99, 0xbb, 0xaf, 0xc1, 0xbe, 0x12, 0x44, 0x2f, 0xf3, 0xde, 0xb5, 0xab, 0xcc, 0xdd, - 0xe6, 0x40, 0xa7, 0x00, 0x3e, 0x8c, 0x39, 0xc7, 0xdd, 0xbb, 0xca, 0x3c, 0x0d, 0x0f, 0x64, 0xc0, - 0xca, 0x24, 0x6c, 0xb9, 0xc8, 0x55, 0xbc, 0xca, 0x42, 0x7d, 0x10, 0xb2, 0x9f, 0x83, 0xa8, 0x65, - 0xbe, 0xab, 0x79, 0x95, 0x39, 0x1b, 0x22, 0xd5, 0xfa, 0x17, 0x5f, 0xaf, 0x47, 0xbf, 0xfc, 0x7a, - 0x3d, 0xfa, 0xf7, 0xaf, 0xd7, 0xa3, 0x9f, 0x7d, 0xb3, 0x1e, 0xf9, 0xf2, 0x9b, 0xf5, 0xc8, 0x5f, - 0xbe, 0x59, 0x8f, 0xfc, 0xf0, 0xa5, 0x8e, 0x6a, 0x77, 0x07, 0xad, 0xcd, 0xb6, 0xde, 0xdf, 0xf2, - 0xdf, 0xd2, 0x9e, 0x74, 0x73, 0xbc, 0x95, 0xa2, 0xd1, 0xf4, 0xd6, 0x7f, 0x03, 0x00, 0x00, 0xff, - 0xff, 0x8d, 0xc9, 0xd7, 0xa0, 0x59, 0x2e, 0x00, 0x00, + // 3395 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x5b, 0x4b, 0x73, 0xdb, 0xd6, + 0xf5, 0xe7, 0xfb, 0x71, 0x28, 0x3e, 0x74, 0xa5, 0x38, 0x34, 0x63, 0x4b, 0x0e, 0x3c, 0x49, 0x1c, + 0x27, 0x91, 0xff, 0xb1, 0x27, 0xf9, 0x3b, 0x4d, 0xd2, 0x8c, 0x44, 0x51, 0xa1, 0x6c, 0x59, 0x52, + 0x20, 0xca, 0x99, 0xb4, 0xa9, 0x11, 0x10, 0xb8, 0x22, 0x11, 0x93, 0x00, 0x02, 0x80, 0x0a, 0x95, + 0x55, 0xa7, 0x33, 0xd9, 0x64, 0x3a, 0xd3, 0xec, 0xda, 0x99, 0x4e, 0xa6, 0x9b, 0x76, 0xa6, 0x1f, + 0xa0, 0x8b, 0xae, 0xba, 0x69, 0x17, 0x59, 0x74, 0x91, 0x5d, 0x3b, 0x5d, 0xa4, 0x9d, 0x64, 0xd7, + 0x2f, 0x90, 0x55, 0x1f, 0x73, 0x1f, 0x00, 0x01, 0x90, 0xe0, 0x23, 0xb6, 0xb3, 0xe9, 0x0e, 0xf7, + 0xf0, 0x9c, 0x83, 0x7b, 0x0f, 0xee, 0x3d, 0xe7, 0xfc, 0xce, 0xb9, 0x84, 0x27, 0x1c, 0xac, 0xab, + 0xd8, 0xea, 0x6b, 0xba, 0x73, 0x4d, 0x6e, 0x2b, 0xda, 0x35, 0xe7, 0xcc, 0xc4, 0xf6, 0x86, 0x69, + 0x19, 0x8e, 0x81, 0xca, 0xa3, 0x1f, 0x37, 0xc8, 0x8f, 0xb5, 0x8b, 0x3e, 0x6e, 0xc5, 0x3a, 0x33, + 0x1d, 0xe3, 0x9a, 0x69, 0x19, 0xc6, 0x09, 0xe3, 0xaf, 0x5d, 0xf0, 0xfd, 0x4c, 0xf5, 0xf8, 0xb5, + 0x05, 0x7e, 0xe5, 0xc2, 0xf7, 0xf1, 0x99, 0xfb, 0xeb, 0xc5, 0x31, 0x59, 0x53, 0xb6, 0xe4, 0xbe, + 0xfb, 0xf3, 0x7a, 0xc7, 0x30, 0x3a, 0x3d, 0x7c, 0x8d, 0x8e, 0xda, 0x83, 0x93, 0x6b, 0x8e, 0xd6, + 0xc7, 0xb6, 0x23, 0xf7, 0x4d, 0xce, 0xb0, 0xda, 0x31, 0x3a, 0x06, 0x7d, 0xbc, 0x46, 0x9e, 0x18, + 0x55, 0xf8, 0x0f, 0x40, 0x56, 0xc4, 0x1f, 0x0c, 0xb0, 0xed, 0xa0, 0xeb, 0x90, 0xc2, 0x4a, 0xd7, + 0xa8, 0xc6, 0x2f, 0xc5, 0xaf, 0x14, 0xae, 0x5f, 0xd8, 0x08, 0x2d, 0x6e, 0x83, 0xf3, 0x35, 0x94, + 0xae, 0xd1, 0x8c, 0x89, 0x94, 0x17, 0xbd, 0x04, 0xe9, 0x93, 0xde, 0xc0, 0xee, 0x56, 0x13, 0x54, + 0xe8, 0x62, 0x94, 0xd0, 0x0e, 0x61, 0x6a, 0xc6, 0x44, 0xc6, 0x4d, 0x5e, 0xa5, 0xe9, 0x27, 0x46, + 0x35, 0x39, 0xfd, 0x55, 0xbb, 0xfa, 0x09, 0x7d, 0x15, 0xe1, 0x45, 0x5b, 0x00, 0x9a, 0xae, 0x39, + 0x92, 0xd2, 0x95, 0x35, 0xbd, 0x9a, 0xa2, 0x92, 0x4f, 0x46, 0x4b, 0x6a, 0x4e, 0x9d, 0x30, 0x36, + 0x63, 0x62, 0x5e, 0x73, 0x07, 0x64, 0xba, 0x1f, 0x0c, 0xb0, 0x75, 0x56, 0x4d, 0x4f, 0x9f, 0xee, + 0x5b, 0x84, 0x89, 0x4c, 0x97, 0x72, 0xa3, 0x5d, 0x28, 0xb4, 0x71, 0x47, 0xd3, 0xa5, 0x76, 0xcf, + 0x50, 0xee, 0x57, 0x33, 0x54, 0x58, 0x88, 0x12, 0xde, 0x22, 0xac, 0x5b, 0x84, 0x73, 0x2b, 0x51, + 0x8d, 0x37, 0x63, 0x22, 0xb4, 0x3d, 0x0a, 0x7a, 0x0d, 0x72, 0x4a, 0x17, 0x2b, 0xf7, 0x25, 0x67, + 0x58, 0xcd, 0x52, 0x3d, 0xeb, 0x51, 0x7a, 0xea, 0x84, 0xaf, 0x35, 0x6c, 0xc6, 0xc4, 0xac, 0xc2, + 0x1e, 0xd1, 0x0e, 0x80, 0x8a, 0x7b, 0xda, 0x29, 0xb6, 0x88, 0x7c, 0x6e, 0xba, 0x0d, 0xb6, 0x19, + 0x67, 0x6b, 0xc8, 0xa7, 0x91, 0x57, 0x5d, 0x02, 0xaa, 0x43, 0x1e, 0xeb, 0x2a, 0x5f, 0x4e, 0x9e, + 0xaa, 0xb9, 0x14, 0xf9, 0xbd, 0x75, 0xd5, 0xbf, 0x98, 0x1c, 0xe6, 0x63, 0x74, 0x13, 0x32, 0x8a, + 0xd1, 0xef, 0x6b, 0x4e, 0x15, 0xa8, 0x86, 0xb5, 0xc8, 0x85, 0x50, 0xae, 0x66, 0x4c, 0xe4, 0xfc, + 0x68, 0x1f, 0x4a, 0x3d, 0xcd, 0x76, 0x24, 0x5b, 0x97, 0x4d, 0xbb, 0x6b, 0x38, 0x76, 0xb5, 0x40, + 0x35, 0x3c, 0x15, 0xa5, 0x61, 0x4f, 0xb3, 0x9d, 0x23, 0x97, 0xb9, 0x19, 0x13, 0x8b, 0x3d, 0x3f, + 0x81, 0xe8, 0x33, 0x4e, 0x4e, 0xb0, 0xe5, 0x29, 0xac, 0x2e, 0x4d, 0xd7, 0x77, 0x40, 0xb8, 0x5d, + 0x79, 0xa2, 0xcf, 0xf0, 0x13, 0xd0, 0x0f, 0x61, 0xa5, 0x67, 0xc8, 0xaa, 0xa7, 0x4e, 0x52, 0xba, + 0x03, 0xfd, 0x7e, 0xb5, 0x48, 0x95, 0x3e, 0x1b, 0x39, 0x49, 0x43, 0x56, 0x5d, 0x15, 0x75, 0x22, + 0xd0, 0x8c, 0x89, 0xcb, 0xbd, 0x30, 0x11, 0xdd, 0x83, 0x55, 0xd9, 0x34, 0x7b, 0x67, 0x61, 0xed, + 0x25, 0xaa, 0xfd, 0x6a, 0x94, 0xf6, 0x4d, 0x22, 0x13, 0x56, 0x8f, 0xe4, 0x31, 0x2a, 0x6a, 0x41, + 0xc5, 0xb4, 0xb0, 0x29, 0x5b, 0x58, 0x32, 0x2d, 0xc3, 0x34, 0x6c, 0xb9, 0x57, 0x2d, 0x53, 0xdd, + 0xcf, 0x44, 0xe9, 0x3e, 0x64, 0xfc, 0x87, 0x9c, 0xbd, 0x19, 0x13, 0xcb, 0x66, 0x90, 0xc4, 0xb4, + 0x1a, 0x0a, 0xb6, 0xed, 0x91, 0xd6, 0xca, 0x2c, 0xad, 0x94, 0x3f, 0xa8, 0x35, 0x40, 0x42, 0x0d, + 0x28, 0xe0, 0x21, 0x11, 0x97, 0x4e, 0x0d, 0x07, 0x57, 0x97, 0xa7, 0x1f, 0xac, 0x06, 0x65, 0xbd, + 0x6b, 0x38, 0x98, 0x1c, 0x2a, 0xec, 0x8d, 0x90, 0x0c, 0x8f, 0x9d, 0x62, 0x4b, 0x3b, 0x39, 0xa3, + 0x6a, 0x24, 0xfa, 0x8b, 0xad, 0x19, 0x7a, 0x15, 0x51, 0x85, 0xcf, 0x45, 0x29, 0xbc, 0x4b, 0x85, + 0x88, 0x8a, 0x86, 0x2b, 0xd2, 0x8c, 0x89, 0x2b, 0xa7, 0xe3, 0x64, 0xb2, 0xc5, 0x4e, 0x34, 0x5d, + 0xee, 0x69, 0x1f, 0x61, 0x7e, 0x6c, 0x56, 0xa6, 0x6f, 0xb1, 0x1d, 0xce, 0x4d, 0xcf, 0x0a, 0xd9, + 0x62, 0x27, 0x7e, 0xc2, 0x56, 0x16, 0xd2, 0xa7, 0x72, 0x6f, 0x80, 0x85, 0x67, 0xa0, 0xe0, 0x73, + 0xac, 0xa8, 0x0a, 0xd9, 0x3e, 0xb6, 0x6d, 0xb9, 0x83, 0xa9, 0x1f, 0xce, 0x8b, 0xee, 0x50, 0x28, + 0xc1, 0x92, 0xdf, 0x99, 0x0a, 0x9f, 0xc6, 0x3d, 0x49, 0xe2, 0x27, 0x89, 0xe4, 0x29, 0xb6, 0xe8, + 0xb2, 0xb9, 0x24, 0x1f, 0xa2, 0xcb, 0x50, 0xa4, 0x53, 0x96, 0xdc, 0xdf, 0x89, 0xb3, 0x4e, 0x89, + 0x4b, 0x94, 0x78, 0x97, 0x33, 0xad, 0x43, 0xc1, 0xbc, 0x6e, 0x7a, 0x2c, 0x49, 0xca, 0x02, 0xe6, + 0x75, 0xd3, 0x65, 0x78, 0x12, 0x96, 0xc8, 0xfa, 0x3c, 0x8e, 0x14, 0x7d, 0x49, 0x81, 0xd0, 0x38, + 0x8b, 0xf0, 0xe7, 0x04, 0x54, 0xc2, 0x0e, 0x18, 0xdd, 0x84, 0x14, 0x89, 0x45, 0x3c, 0xac, 0xd4, + 0x36, 0x58, 0xa0, 0xda, 0x70, 0x03, 0xd5, 0x46, 0xcb, 0x0d, 0x54, 0x5b, 0xb9, 0xcf, 0xbf, 0x5c, + 0x8f, 0x7d, 0xfa, 0xf7, 0xf5, 0xb8, 0x48, 0x25, 0xd0, 0x79, 0xe2, 0x2b, 0x65, 0x4d, 0x97, 0x34, + 0x95, 0x4e, 0x39, 0x4f, 0x1c, 0xa1, 0xac, 0xe9, 0xbb, 0x2a, 0xda, 0x83, 0x8a, 0x62, 0xe8, 0x36, + 0xd6, 0xed, 0x81, 0x2d, 0xb1, 0x40, 0xc8, 0x83, 0x49, 0xc0, 0x1d, 0xb2, 0xf0, 0x5a, 0x77, 0x39, + 0x0f, 0x29, 0xa3, 0x58, 0x56, 0x82, 0x04, 0xe2, 0x56, 0x4f, 0xe5, 0x9e, 0xa6, 0xca, 0x8e, 0x61, + 0xd9, 0xd5, 0xd4, 0xa5, 0xe4, 0x44, 0x7f, 0x78, 0xd7, 0x65, 0x39, 0x36, 0x55, 0xd9, 0xc1, 0x5b, + 0x29, 0x32, 0x5d, 0xd1, 0x27, 0x89, 0x9e, 0x86, 0xb2, 0x6c, 0x9a, 0x92, 0xed, 0xc8, 0x0e, 0x96, + 0xda, 0x67, 0x0e, 0xb6, 0x69, 0xa0, 0x59, 0x12, 0x8b, 0xb2, 0x69, 0x1e, 0x11, 0xea, 0x16, 0x21, + 0xa2, 0xa7, 0xa0, 0x44, 0x62, 0x92, 0x26, 0xf7, 0xa4, 0x2e, 0xd6, 0x3a, 0x5d, 0x87, 0x86, 0x94, + 0xa4, 0x58, 0xe4, 0xd4, 0x26, 0x25, 0x0a, 0xaa, 0xf7, 0xc5, 0x69, 0x3c, 0x42, 0x08, 0x52, 0xaa, + 0xec, 0xc8, 0xd4, 0x92, 0x4b, 0x22, 0x7d, 0x26, 0x34, 0x53, 0x76, 0xba, 0xdc, 0x3e, 0xf4, 0x19, + 0x9d, 0x83, 0x0c, 0x57, 0x9b, 0xa4, 0x6a, 0xf9, 0x08, 0xad, 0x42, 0xda, 0xb4, 0x8c, 0x53, 0x4c, + 0x3f, 0x5d, 0x4e, 0x64, 0x03, 0xe1, 0xc7, 0x09, 0x58, 0x1e, 0x8b, 0x5c, 0x44, 0x6f, 0x57, 0xb6, + 0xbb, 0xee, 0xbb, 0xc8, 0x33, 0x7a, 0x99, 0xe8, 0x95, 0x55, 0x6c, 0xf1, 0x68, 0x5f, 0x1d, 0x37, + 0x75, 0x93, 0xfe, 0xce, 0x4d, 0xc3, 0xb9, 0xd1, 0x6d, 0xa8, 0xf4, 0x64, 0xdb, 0x91, 0x98, 0xf7, + 0x97, 0x7c, 0x91, 0xff, 0x89, 0x31, 0x23, 0xb3, 0x58, 0x41, 0x36, 0x34, 0x57, 0x52, 0x22, 0xa2, + 0x23, 0x2a, 0x12, 0x61, 0xb5, 0x7d, 0xf6, 0x91, 0xac, 0x3b, 0x9a, 0x8e, 0xa5, 0xb1, 0xaf, 0x76, + 0x7e, 0x4c, 0x61, 0xe3, 0x54, 0x53, 0xb1, 0xae, 0xb8, 0x9f, 0x6b, 0xc5, 0x13, 0xf6, 0x3e, 0xa7, + 0x2d, 0x88, 0x50, 0x0a, 0xc6, 0x5c, 0x54, 0x82, 0x84, 0x33, 0xe4, 0x8b, 0x4f, 0x38, 0x43, 0xf4, + 0x7f, 0x90, 0x22, 0x0b, 0xa4, 0x0b, 0x2f, 0x4d, 0x48, 0x58, 0xb8, 0x5c, 0xeb, 0xcc, 0xc4, 0x22, + 0xe5, 0x14, 0x04, 0xef, 0x28, 0x78, 0x71, 0x38, 0xac, 0x55, 0x78, 0x16, 0xca, 0xa1, 0x20, 0xeb, + 0xfb, 0x76, 0x71, 0xff, 0xb7, 0x13, 0xca, 0x50, 0x0c, 0x44, 0x53, 0xe1, 0x1c, 0xac, 0x4e, 0x0a, + 0x8e, 0x42, 0xd7, 0xa3, 0x07, 0x82, 0x1c, 0x7a, 0x09, 0x72, 0x5e, 0x74, 0x64, 0x47, 0x71, 0xdc, + 0x56, 0x2e, 0xb3, 0xe8, 0xb1, 0x92, 0x33, 0x48, 0xb6, 0x34, 0xdd, 0x0b, 0x09, 0x3a, 0xf1, 0xac, + 0x6c, 0x9a, 0x4d, 0xd9, 0xee, 0x0a, 0xef, 0x41, 0x35, 0x2a, 0xf2, 0x85, 0x96, 0x91, 0xf2, 0xb6, + 0xe0, 0x39, 0xc8, 0x9c, 0x18, 0x56, 0x5f, 0x76, 0xa8, 0xb2, 0xa2, 0xc8, 0x47, 0x64, 0x6b, 0xb2, + 0x28, 0x98, 0xa4, 0x64, 0x36, 0x10, 0x24, 0x38, 0x1f, 0x19, 0xfd, 0x88, 0x88, 0xa6, 0xab, 0x98, + 0xd9, 0xb3, 0x28, 0xb2, 0xc1, 0x48, 0x11, 0x9b, 0x2c, 0x1b, 0x90, 0xd7, 0xda, 0x74, 0xad, 0x54, + 0x7f, 0x5e, 0xe4, 0x23, 0xe1, 0x0d, 0x6f, 0xeb, 0x8f, 0x62, 0x0b, 0xba, 0x0a, 0x29, 0x1a, 0x8d, + 0x98, 0x95, 0xce, 0x8d, 0x6f, 0x72, 0xc2, 0x25, 0x52, 0x1e, 0xa1, 0x09, 0xb5, 0xe8, 0x58, 0xb2, + 0x90, 0xa6, 0x3f, 0x26, 0xe0, 0xdc, 0xe4, 0x70, 0xfc, 0x50, 0xcf, 0x62, 0x05, 0x92, 0xce, 0x90, + 0xf8, 0xca, 0xe4, 0x95, 0x25, 0x91, 0x3c, 0xa2, 0x63, 0x58, 0xee, 0x19, 0x8a, 0xdc, 0x93, 0x7c, + 0x67, 0x94, 0xa7, 0xd7, 0x97, 0xc7, 0x4f, 0x13, 0x35, 0x13, 0x56, 0xc7, 0x8e, 0x69, 0x99, 0xea, + 0xd8, 0xf3, 0xce, 0x6a, 0xe4, 0x39, 0x4d, 0x7f, 0xfb, 0x73, 0x8a, 0x2e, 0xc1, 0x52, 0x5f, 0x1e, + 0x4a, 0xce, 0x90, 0x3b, 0x57, 0xe6, 0x35, 0xa1, 0x2f, 0x0f, 0x5b, 0x43, 0xea, 0x59, 0x85, 0x5f, + 0xf9, 0xad, 0x18, 0xcc, 0x35, 0x1e, 0xad, 0x15, 0x8f, 0x60, 0x95, 0xe5, 0x45, 0x58, 0x9d, 0x60, + 0xc8, 0x39, 0xfc, 0x1c, 0x72, 0xc5, 0x1f, 0xad, 0x0d, 0x85, 0x5f, 0x26, 0x3c, 0x07, 0x11, 0x48, + 0x51, 0x1e, 0xb1, 0x7d, 0xde, 0x82, 0x15, 0x15, 0x2b, 0x9a, 0xfa, 0x6d, 0xcd, 0xb3, 0xcc, 0xa5, + 0x1f, 0xb1, 0x75, 0xfe, 0x52, 0x80, 0x9c, 0x88, 0x6d, 0x93, 0x24, 0x08, 0x68, 0x0b, 0xf2, 0x78, + 0xa8, 0x60, 0xd3, 0x71, 0x73, 0xaa, 0xc9, 0xb9, 0x29, 0xe3, 0x6e, 0xb8, 0x9c, 0x04, 0x69, 0x79, + 0x62, 0xe8, 0x06, 0x07, 0xd5, 0xd1, 0xf8, 0x98, 0x8b, 0xfb, 0x51, 0xf5, 0xcb, 0x2e, 0xaa, 0x4e, + 0x46, 0x02, 0x2b, 0x26, 0x15, 0x82, 0xd5, 0x37, 0x38, 0xac, 0x4e, 0xcd, 0x78, 0x59, 0x00, 0x57, + 0xd7, 0x03, 0xb8, 0x3a, 0x3d, 0x63, 0x99, 0x11, 0xc0, 0xfa, 0x65, 0x17, 0x58, 0x67, 0x66, 0xcc, + 0x38, 0x84, 0xac, 0x6f, 0x05, 0x91, 0x75, 0x36, 0xc2, 0xed, 0xb8, 0xd2, 0x53, 0xa1, 0xf5, 0xeb, + 0x3e, 0x68, 0x9d, 0x8b, 0xc4, 0xb4, 0x4c, 0xd1, 0x04, 0x6c, 0xfd, 0x66, 0x00, 0x5b, 0xe7, 0x67, + 0xd8, 0x61, 0x0a, 0xb8, 0xde, 0xf6, 0x83, 0x6b, 0x88, 0xc4, 0xe8, 0xfc, 0xbb, 0x47, 0xa1, 0xeb, + 0x57, 0x3c, 0x74, 0x5d, 0x88, 0x2c, 0x13, 0xf0, 0xb5, 0x84, 0xe1, 0xf5, 0xc1, 0x18, 0xbc, 0x66, + 0x70, 0xf8, 0xe9, 0x48, 0x15, 0x33, 0xf0, 0xf5, 0xc1, 0x18, 0xbe, 0x2e, 0xce, 0x50, 0x38, 0x03, + 0x60, 0xbf, 0x3b, 0x19, 0x60, 0x47, 0x43, 0x60, 0x3e, 0xcd, 0xf9, 0x10, 0xb6, 0x14, 0x81, 0xb0, + 0xcb, 0x91, 0x68, 0x90, 0xa9, 0x9f, 0x1b, 0x62, 0x1f, 0x4f, 0x80, 0xd8, 0x0c, 0x0c, 0x5f, 0x89, + 0x54, 0x3e, 0x07, 0xc6, 0x3e, 0x9e, 0x80, 0xb1, 0x97, 0x67, 0xaa, 0x9d, 0x09, 0xb2, 0x77, 0x82, + 0x20, 0x1b, 0xcd, 0x38, 0x63, 0x91, 0x28, 0xbb, 0x1d, 0x85, 0xb2, 0x19, 0x12, 0x7e, 0x3e, 0x52, + 0xe3, 0x02, 0x30, 0xfb, 0x60, 0x0c, 0x66, 0xaf, 0xce, 0xd8, 0x69, 0xf3, 0xe2, 0xec, 0x67, 0x49, + 0xaa, 0x17, 0x72, 0xd5, 0x24, 0x5b, 0xc4, 0x96, 0x65, 0x58, 0x1c, 0x31, 0xb3, 0x81, 0x70, 0x85, + 0xe0, 0xae, 0x91, 0x5b, 0x9e, 0x82, 0xc9, 0x69, 0x56, 0xee, 0x73, 0xc5, 0xc2, 0xef, 0xe3, 0x23, + 0x59, 0x0a, 0x57, 0xfc, 0x98, 0x2d, 0xcf, 0x31, 0x9b, 0x0f, 0xa9, 0x27, 0x82, 0x48, 0x7d, 0x1d, + 0x0a, 0x24, 0xdb, 0x0e, 0x81, 0x70, 0xd9, 0xf4, 0x40, 0xf8, 0x55, 0x58, 0xa6, 0xe1, 0x93, 0xe1, + 0x79, 0x9e, 0x62, 0xa7, 0x68, 0x1a, 0x54, 0x26, 0x3f, 0x30, 0x2b, 0xb0, 0x5c, 0xfb, 0x05, 0x58, + 0xf1, 0xf1, 0x7a, 0x59, 0x3c, 0x43, 0xa4, 0x15, 0x8f, 0x7b, 0x93, 0xa7, 0xf3, 0x7f, 0x8a, 0x8f, + 0x2c, 0x34, 0x42, 0xef, 0x93, 0x80, 0x76, 0xfc, 0x21, 0x01, 0xed, 0xc4, 0xb7, 0x06, 0xda, 0x7e, + 0x54, 0x92, 0x0c, 0xa2, 0x92, 0x6f, 0xe2, 0xa3, 0x6f, 0xe2, 0xc1, 0x66, 0xc5, 0x50, 0x31, 0xc7, + 0x09, 0xf4, 0x99, 0x24, 0x28, 0x3d, 0xa3, 0xc3, 0xd1, 0x00, 0x79, 0x24, 0x5c, 0x5e, 0xec, 0xcc, + 0xf3, 0xd0, 0xe8, 0x41, 0x8c, 0x34, 0xb5, 0x30, 0x87, 0x18, 0x15, 0x48, 0xde, 0xc7, 0x2c, 0xd2, + 0x2d, 0x89, 0xe4, 0x91, 0xf0, 0xd1, 0x4d, 0x46, 0xe3, 0xd7, 0x92, 0xc8, 0x06, 0xe8, 0x26, 0xe4, + 0x69, 0xf1, 0x5f, 0x32, 0x4c, 0x9b, 0x07, 0xa4, 0x40, 0xa2, 0xc3, 0x6a, 0xfc, 0x1b, 0x87, 0x84, + 0xe7, 0xc0, 0xb4, 0xc5, 0x9c, 0xc9, 0x9f, 0x7c, 0xe8, 0x29, 0x1f, 0x00, 0xf0, 0x17, 0x20, 0x4f, + 0x66, 0x6f, 0x9b, 0xb2, 0x82, 0x69, 0x64, 0xc9, 0x8b, 0x23, 0x82, 0x70, 0x0f, 0xd0, 0x78, 0x9c, + 0x44, 0x4d, 0xc8, 0xe0, 0x53, 0xac, 0x3b, 0xe4, 0xb3, 0x25, 0xc3, 0x28, 0x84, 0xe7, 0x45, 0x58, + 0x77, 0xb6, 0xaa, 0xc4, 0xc8, 0xff, 0xfc, 0x72, 0xbd, 0xc2, 0xb8, 0x9f, 0x37, 0xfa, 0x9a, 0x83, + 0xfb, 0xa6, 0x73, 0x26, 0x72, 0x79, 0xe1, 0x6f, 0x09, 0x02, 0x57, 0x03, 0xf1, 0x73, 0xa2, 0x6d, + 0xdd, 0x2d, 0x9f, 0xf0, 0x95, 0x29, 0xe6, 0xb3, 0xf7, 0x45, 0x80, 0x8e, 0x6c, 0x4b, 0x1f, 0xca, + 0xba, 0x83, 0x55, 0x6e, 0xf4, 0x7c, 0x47, 0xb6, 0xdf, 0xa6, 0x04, 0xf2, 0xd5, 0xc9, 0xcf, 0x03, + 0x1b, 0xab, 0x3c, 0xf5, 0xcf, 0x76, 0x64, 0xfb, 0xd8, 0xc6, 0xaa, 0x6f, 0x95, 0xd9, 0x07, 0x5b, + 0x65, 0xd0, 0xc6, 0xb9, 0x90, 0x8d, 0x7d, 0x40, 0x32, 0xef, 0x07, 0x92, 0xa8, 0x06, 0x39, 0xd3, + 0xd2, 0x0c, 0x4b, 0x73, 0xce, 0xe8, 0x87, 0x49, 0x8a, 0xde, 0x18, 0x5d, 0x86, 0x62, 0x1f, 0xf7, + 0x4d, 0xc3, 0xe8, 0x49, 0xcc, 0xd9, 0x14, 0xa8, 0xe8, 0x12, 0x27, 0x36, 0xa8, 0xcf, 0xf9, 0x38, + 0x31, 0x3a, 0x7d, 0xa3, 0x82, 0xc1, 0xc3, 0x35, 0xef, 0xda, 0x04, 0xf3, 0xfa, 0x28, 0x64, 0x11, + 0x21, 0xfb, 0x7a, 0xe3, 0xef, 0xca, 0xc0, 0xc2, 0x4f, 0x69, 0x09, 0x31, 0x98, 0x1b, 0xa1, 0x23, + 0x58, 0xf6, 0x0e, 0xbf, 0x34, 0xa0, 0x4e, 0xc1, 0xdd, 0xce, 0xf3, 0x7a, 0x8f, 0xca, 0x69, 0x90, + 0x6c, 0xa3, 0x77, 0xe0, 0xf1, 0x90, 0x67, 0xf3, 0x54, 0x27, 0xe6, 0x75, 0x70, 0x8f, 0x05, 0x1d, + 0x9c, 0xab, 0x7a, 0x64, 0xac, 0xe4, 0x03, 0x9e, 0xb9, 0x5d, 0x28, 0x05, 0xd3, 0xbc, 0x89, 0x9f, + 0xff, 0x32, 0x14, 0x2d, 0xec, 0xc8, 0x9a, 0x2e, 0x05, 0xea, 0x7e, 0x4b, 0x8c, 0xc8, 0xab, 0x89, + 0x87, 0xf0, 0xd8, 0xc4, 0x74, 0x0f, 0xfd, 0x3f, 0xe4, 0x47, 0x99, 0x62, 0x3c, 0x02, 0x3c, 0x79, + 0xa5, 0xa1, 0x11, 0xaf, 0xf0, 0x87, 0xf8, 0x48, 0x65, 0xb0, 0xd8, 0xd4, 0x80, 0x8c, 0x85, 0xed, + 0x41, 0x8f, 0x95, 0x7f, 0x4a, 0xd7, 0x5f, 0x98, 0x2f, 0x51, 0x24, 0xd4, 0x41, 0xcf, 0x11, 0xb9, + 0xb0, 0x70, 0x0f, 0x32, 0x8c, 0x82, 0x0a, 0x90, 0x3d, 0xde, 0xbf, 0xbd, 0x7f, 0xf0, 0xf6, 0x7e, + 0x25, 0x86, 0x00, 0x32, 0x9b, 0xf5, 0x7a, 0xe3, 0xb0, 0x55, 0x89, 0xa3, 0x3c, 0xa4, 0x37, 0xb7, + 0x0e, 0xc4, 0x56, 0x25, 0x41, 0xc8, 0x62, 0xe3, 0x56, 0xa3, 0xde, 0xaa, 0x24, 0xd1, 0x32, 0x14, + 0xd9, 0xb3, 0xb4, 0x73, 0x20, 0xde, 0xd9, 0x6c, 0x55, 0x52, 0x3e, 0xd2, 0x51, 0x63, 0x7f, 0xbb, + 0x21, 0x56, 0xd2, 0xc2, 0x8b, 0x70, 0x3e, 0x32, 0xb5, 0x1c, 0x55, 0x92, 0xe2, 0xbe, 0x4a, 0x92, + 0xf0, 0x8b, 0x04, 0xd4, 0xa2, 0xf3, 0x45, 0x74, 0x2b, 0xb4, 0xf0, 0xeb, 0x0b, 0x24, 0x9b, 0xa1, + 0xd5, 0xa3, 0xa7, 0xa0, 0x64, 0xe1, 0x13, 0xec, 0x28, 0x5d, 0x96, 0xbf, 0xb2, 0x80, 0x59, 0x14, + 0x8b, 0x9c, 0x4a, 0x85, 0x6c, 0xc6, 0xf6, 0x3e, 0x56, 0x1c, 0x89, 0xf9, 0x22, 0xb6, 0xe9, 0xf2, + 0x84, 0x8d, 0x50, 0x8f, 0x18, 0x51, 0x78, 0x6f, 0x21, 0x5b, 0xe6, 0x21, 0x2d, 0x36, 0x5a, 0xe2, + 0x3b, 0x95, 0x24, 0x42, 0x50, 0xa2, 0x8f, 0xd2, 0xd1, 0xfe, 0xe6, 0xe1, 0x51, 0xf3, 0x80, 0xd8, + 0x72, 0x05, 0xca, 0xae, 0x2d, 0x5d, 0x62, 0x5a, 0x78, 0x77, 0x14, 0x7f, 0x7c, 0xd5, 0xb4, 0x1d, + 0x28, 0x85, 0xd2, 0xc5, 0xf8, 0x38, 0x9e, 0x19, 0x55, 0xc3, 0xbc, 0x54, 0x50, 0x2c, 0x9e, 0xfa, + 0x87, 0xc2, 0xaf, 0xe3, 0xf0, 0xc4, 0x94, 0x84, 0x12, 0xdd, 0x0e, 0x59, 0xfe, 0xc6, 0x22, 0xe9, + 0x68, 0x78, 0xe3, 0xdd, 0x9c, 0xcb, 0x58, 0x47, 0x7b, 0x9b, 0x47, 0xcd, 0xe0, 0xc6, 0x13, 0xbe, + 0x49, 0xc0, 0xe3, 0x11, 0x29, 0x3f, 0xc9, 0xee, 0xfa, 0x86, 0xaa, 0x9d, 0x68, 0x58, 0x95, 0x78, + 0x1d, 0x38, 0x27, 0x82, 0x4b, 0x6a, 0x0d, 0xd1, 0x4d, 0x00, 0x67, 0x28, 0x59, 0x58, 0x31, 0x2c, + 0xd5, 0x4d, 0x8f, 0xc6, 0x8f, 0x62, 0x6b, 0x28, 0x52, 0x0e, 0x31, 0xef, 0xf0, 0xa7, 0x69, 0x09, + 0x11, 0x7a, 0x8d, 0x2b, 0x25, 0xcb, 0x71, 0xcb, 0xe4, 0x17, 0x27, 0x14, 0xf6, 0xb0, 0x42, 0x14, + 0x53, 0x33, 0x50, 0xc5, 0x94, 0x1f, 0xdd, 0x99, 0xe4, 0x7a, 0xd3, 0xf3, 0xb9, 0xde, 0xc5, 0x9c, + 0x6e, 0xe6, 0xc1, 0x9c, 0xae, 0xf0, 0xbb, 0x80, 0xe5, 0x83, 0x10, 0xe8, 0x1c, 0x64, 0x64, 0x85, + 0x24, 0xfd, 0xdc, 0xe8, 0x7c, 0x34, 0xa5, 0xba, 0x1d, 0x32, 0x5b, 0xf2, 0x61, 0x98, 0x2d, 0xf5, + 0x28, 0xcc, 0x96, 0x7e, 0x40, 0xb3, 0xfd, 0x2c, 0x39, 0x72, 0xe2, 0xc1, 0x82, 0xe0, 0x43, 0xcb, + 0x1c, 0x43, 0xb6, 0x4c, 0x2c, 0x68, 0xcb, 0x89, 0xd1, 0x3f, 0xf9, 0xe8, 0xa2, 0x7f, 0xea, 0x01, + 0xa3, 0xbf, 0x7f, 0x53, 0xa5, 0x83, 0x9b, 0x6a, 0x2c, 0x50, 0x67, 0x26, 0x04, 0xea, 0x77, 0x00, + 0x7c, 0xfd, 0xae, 0x55, 0x48, 0x5b, 0xc6, 0x40, 0x57, 0xe9, 0xce, 0x4d, 0x8b, 0x6c, 0x80, 0x5e, + 0x82, 0x34, 0x71, 0x8f, 0xd1, 0x4e, 0x82, 0xb8, 0x37, 0x5f, 0xf9, 0x94, 0x71, 0x0b, 0x1a, 0xa0, + 0xf1, 0x0a, 0x7e, 0xc4, 0x2b, 0x5e, 0x0f, 0xbe, 0xe2, 0xc9, 0xc8, 0x5e, 0xc0, 0xe4, 0x57, 0x7d, + 0x04, 0x69, 0xba, 0x3d, 0x48, 0xc2, 0x42, 0x5b, 0x67, 0x1c, 0x01, 0x93, 0x67, 0xf4, 0x23, 0x00, + 0xd9, 0x71, 0x2c, 0xad, 0x3d, 0x18, 0xbd, 0x60, 0x7d, 0xf2, 0xf6, 0xda, 0x74, 0xf9, 0xb6, 0x2e, + 0xf0, 0x7d, 0xb6, 0x3a, 0x12, 0xf5, 0xed, 0x35, 0x9f, 0x42, 0x61, 0x1f, 0x4a, 0x41, 0x59, 0x17, + 0xb3, 0xb1, 0x39, 0x04, 0x31, 0x1b, 0x83, 0xe0, 0x1c, 0xb3, 0x79, 0x88, 0x2f, 0xc9, 0x5a, 0xa4, + 0x74, 0x20, 0xfc, 0x3b, 0x0e, 0x4b, 0xfe, 0xdd, 0xf9, 0xbf, 0x06, 0x7b, 0x84, 0x8f, 0xe3, 0x90, + 0xf3, 0x16, 0x1f, 0xd1, 0xa2, 0x1c, 0xd9, 0x2e, 0xe1, 0x6f, 0xc8, 0xb1, 0x9e, 0x67, 0xd2, 0xeb, + 0xa4, 0xbe, 0xea, 0xc5, 0xe9, 0xa8, 0x2a, 0xb5, 0xdf, 0xd2, 0x6e, 0x5f, 0x81, 0xc7, 0xe5, 0x9f, + 0xf3, 0x79, 0x90, 0xa0, 0x87, 0xbe, 0x47, 0x9c, 0xba, 0x57, 0x9b, 0x2f, 0x4d, 0x28, 0xd6, 0xba, + 0xac, 0x1b, 0xad, 0xe1, 0x26, 0xe5, 0x14, 0xb9, 0x04, 0x9f, 0x55, 0xc2, 0xeb, 0xc4, 0xbe, 0x41, + 0xf4, 0x32, 0x9e, 0x60, 0xc8, 0x2f, 0x01, 0x1c, 0xef, 0xdf, 0x39, 0xd8, 0xde, 0xdd, 0xd9, 0x6d, + 0x6c, 0xf3, 0x1c, 0x69, 0x7b, 0xbb, 0xb1, 0x5d, 0x49, 0x10, 0x3e, 0xb1, 0x71, 0xe7, 0xe0, 0x6e, + 0x63, 0xbb, 0x92, 0x14, 0x5e, 0x85, 0xbc, 0xe7, 0x7a, 0x50, 0x15, 0xb2, 0xb2, 0xaa, 0x5a, 0xd8, + 0xb6, 0x79, 0xf2, 0xe8, 0x0e, 0x69, 0x0b, 0xde, 0xf8, 0x90, 0xf7, 0x21, 0x93, 0x22, 0x1b, 0x08, + 0x2a, 0x94, 0x43, 0x7e, 0x0b, 0xbd, 0x0a, 0x59, 0x73, 0xd0, 0x96, 0xdc, 0x4d, 0x1b, 0xba, 0x24, + 0xe7, 0x96, 0x0e, 0x06, 0xed, 0x9e, 0xa6, 0xdc, 0xc6, 0x67, 0xae, 0x99, 0xcc, 0x41, 0xfb, 0x36, + 0xdb, 0xdb, 0xec, 0x2d, 0x09, 0xff, 0x5b, 0x7e, 0x12, 0x87, 0x9c, 0x7b, 0x56, 0xd1, 0xf7, 0x21, + 0xef, 0xf9, 0x44, 0xef, 0x6a, 0x46, 0xa4, 0x33, 0xe5, 0xfa, 0x47, 0x22, 0xe8, 0x2a, 0x2c, 0xdb, + 0x5a, 0x47, 0x77, 0xdb, 0x39, 0xac, 0x56, 0x97, 0xa0, 0x87, 0xa6, 0xcc, 0x7e, 0xd8, 0x73, 0x0b, + 0x4c, 0xb7, 0x52, 0xb9, 0x64, 0x25, 0x75, 0x2b, 0x95, 0x4b, 0x55, 0xd2, 0xc2, 0x6f, 0xe2, 0x50, + 0x09, 0x3b, 0x8e, 0xef, 0x72, 0x32, 0x24, 0x5d, 0x0e, 0xe5, 0xa3, 0x6c, 0x6f, 0x86, 0xd2, 0xcd, + 0x7f, 0xc5, 0x21, 0xe7, 0x36, 0x8c, 0xd0, 0x8b, 0x3e, 0x17, 0x56, 0x9a, 0xb4, 0x63, 0x39, 0xe3, + 0xa8, 0xfd, 0x1f, 0x5c, 0x52, 0x62, 0xf1, 0x25, 0x45, 0xdd, 0xe1, 0x70, 0x6f, 0xd3, 0xa4, 0x16, + 0xbe, 0x4d, 0xf3, 0x3c, 0x20, 0xc7, 0x70, 0xe4, 0x9e, 0x74, 0x6a, 0x38, 0x9a, 0xde, 0x91, 0xd8, + 0x0e, 0x61, 0xde, 0xa6, 0x42, 0x7f, 0xb9, 0x4b, 0x7f, 0x38, 0xf4, 0x36, 0x8b, 0x07, 0xe7, 0x16, + 0xed, 0xe6, 0x9f, 0x83, 0x0c, 0x47, 0x2c, 0xac, 0x9d, 0xcf, 0x47, 0x5e, 0x8b, 0x31, 0xe5, 0x6b, + 0x31, 0xd6, 0x20, 0xd7, 0xc7, 0x8e, 0x4c, 0x5d, 0x27, 0x8b, 0x96, 0xde, 0xf8, 0xea, 0x2b, 0x50, + 0xf0, 0x5d, 0xac, 0x20, 0xde, 0x74, 0xbf, 0xf1, 0x76, 0x25, 0x56, 0xcb, 0x7e, 0xf2, 0xd9, 0xa5, + 0xe4, 0x3e, 0xfe, 0x90, 0x1c, 0x34, 0xb1, 0x51, 0x6f, 0x36, 0xea, 0xb7, 0x2b, 0xf1, 0x5a, 0xe1, + 0x93, 0xcf, 0x2e, 0x65, 0x45, 0x4c, 0xfb, 0x39, 0x57, 0x9b, 0xb0, 0xe4, 0xff, 0x2a, 0xc1, 0x43, + 0x8d, 0xa0, 0xb4, 0x7d, 0x7c, 0xb8, 0xb7, 0x5b, 0xdf, 0x6c, 0x35, 0xa4, 0xbb, 0x07, 0xad, 0x46, + 0x25, 0x8e, 0x1e, 0x87, 0x95, 0xbd, 0xdd, 0x37, 0x9b, 0x2d, 0xa9, 0xbe, 0xb7, 0xdb, 0xd8, 0x6f, + 0x49, 0x9b, 0xad, 0xd6, 0x66, 0xfd, 0x76, 0x25, 0x71, 0xfd, 0xb7, 0x05, 0x28, 0x6f, 0x6e, 0xd5, + 0x77, 0x09, 0x60, 0xd3, 0x14, 0x99, 0xba, 0x88, 0x3a, 0xa4, 0x68, 0x65, 0x78, 0xea, 0x25, 0xd9, + 0xda, 0xf4, 0x6e, 0x1f, 0xda, 0x81, 0x34, 0x2d, 0x1a, 0xa3, 0xe9, 0xb7, 0x66, 0x6b, 0x33, 0xda, + 0x7f, 0x64, 0x32, 0xf4, 0x14, 0x4d, 0xbd, 0x46, 0x5b, 0x9b, 0xde, 0x0d, 0x44, 0x7b, 0x90, 0x75, + 0x6b, 0x7a, 0xb3, 0x2e, 0xa4, 0xd6, 0x66, 0xb6, 0xd5, 0xc8, 0xd2, 0x58, 0xed, 0x75, 0xfa, 0x0d, + 0xdb, 0xda, 0x8c, 0x3e, 0x21, 0xda, 0x85, 0x0c, 0x2f, 0x7b, 0xcc, 0xb8, 0x5c, 0x5a, 0x9b, 0xd5, + 0x1e, 0x43, 0x22, 0xe4, 0x47, 0x55, 0xed, 0xd9, 0xf7, 0x86, 0x6b, 0x73, 0xb4, 0x40, 0xd1, 0x3d, + 0x28, 0x06, 0x4b, 0x29, 0xf3, 0x5d, 0x60, 0xad, 0xcd, 0xd9, 0x88, 0x23, 0xfa, 0x83, 0x75, 0x95, + 0xf9, 0x2e, 0xb4, 0xd6, 0xe6, 0xec, 0xcb, 0xa1, 0xf7, 0x61, 0x79, 0xbc, 0xee, 0x31, 0xff, 0xfd, + 0xd6, 0xda, 0x02, 0x9d, 0x3a, 0xd4, 0x07, 0x34, 0xa1, 0x5e, 0xb2, 0xc0, 0x75, 0xd7, 0xda, 0x22, + 0x8d, 0x3b, 0xa4, 0x42, 0x39, 0x0c, 0xbf, 0xe7, 0xbd, 0xfe, 0x5a, 0x9b, 0xbb, 0x89, 0xc7, 0xde, + 0x12, 0x84, 0x9a, 0xf3, 0x5e, 0x87, 0xad, 0xcd, 0xdd, 0xd3, 0x43, 0xc7, 0x00, 0xbe, 0x82, 0xca, + 0x1c, 0xd7, 0x63, 0x6b, 0xf3, 0x74, 0xf7, 0x90, 0x09, 0x2b, 0x93, 0x0a, 0x29, 0x8b, 0xdc, 0x96, + 0xad, 0x2d, 0xd4, 0xf4, 0x23, 0xfb, 0x39, 0x08, 0x31, 0xe7, 0xbb, 0x3d, 0x5b, 0x9b, 0xb3, 0xfb, + 0xb7, 0xd5, 0xf8, 0xfc, 0xab, 0xb5, 0xf8, 0x17, 0x5f, 0xad, 0xc5, 0xff, 0xf1, 0xd5, 0x5a, 0xfc, + 0xd3, 0xaf, 0xd7, 0x62, 0x5f, 0x7c, 0xbd, 0x16, 0xfb, 0xeb, 0xd7, 0x6b, 0xb1, 0x1f, 0x3c, 0xd7, + 0xd1, 0x9c, 0xee, 0xa0, 0xbd, 0xa1, 0x18, 0xfd, 0x6b, 0xfe, 0x3f, 0x52, 0x4c, 0xfa, 0x73, 0x47, + 0x3b, 0x43, 0xa3, 0xe9, 0x8d, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf9, 0x85, 0x76, 0xba, 0xfc, + 0x31, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5752,10 +6024,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 } @@ -5763,22 +6040,44 @@ func (m *RequestPrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTypes(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x2a } } - if m.BlockDataSize != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.BlockDataSize)) - i-- - dAtA[i] = 0x10 + { + size, err := m.LocalLastCommit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) } - 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] = 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] = 0xa + dAtA[i] = 0x1a + } + } + { + 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 } @@ -7108,20 +7407,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA55 := make([]byte, len(m.RefetchChunks)*10) - var j54 int + dAtA57 := make([]byte, len(m.RefetchChunks)*10) + var j56 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA55[j54] = uint8(uint64(num)&0x7f | 0x80) + dAtA57[j56] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j54++ + j56++ } - dAtA55[j54] = uint8(num) - j54++ + dAtA57[j56] = uint8(num) + j56++ } - i -= j54 - copy(dAtA[i:], dAtA55[:j54]) - i = encodeVarintTypes(dAtA, i, uint64(j54)) + i -= j56 + copy(dAtA[i:], dAtA57[:j56]) + i = encodeVarintTypes(dAtA, i, uint64(j56)) i-- dAtA[i] = 0x12 } @@ -7216,16 +7515,78 @@ 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 m.ConsensusParamUpdates != nil { + { + size, err := m.ConsensusParamUpdates.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.ValidatorUpdates) > 0 { + for iNdEx := len(m.ValidatorUpdates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ValidatorUpdates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } i-- - dAtA[i] = 0xa + dAtA[i] = 0x2a } } - return len(dAtA) - i, nil + if len(m.TxResults) > 0 { + for iNdEx := len(m.TxResults) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxResults[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.AppHash) > 0 { + i -= len(m.AppHash) + copy(dAtA[i:], m.AppHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.AppHash))) + i-- + dAtA[i] = 0x1a + } + 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] = 0x12 + } + } + if m.ModifiedTx { + i-- + if m.ModifiedTx { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil } func (m *ResponseProcessProposal) Marshal() (dAtA []byte, err error) { @@ -7439,6 +7800,48 @@ func (m *CommitInfo) 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) @@ -7660,6 +8063,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) @@ -7776,6 +8214,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) @@ -7801,12 +8289,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n62, err62 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err62 != nil { - return 0, err62 + n66, err66 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err66 != nil { + return 0, err66 } - i -= n62 - i = encodeVarintTypes(dAtA, i, uint64(n62)) + i -= n66 + i = encodeVarintTypes(dAtA, i, uint64(n66)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -8404,21 +8892,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 } @@ -9102,12 +9598,35 @@ 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)) + } + } + l = len(m.AppHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.TxResults) > 0 { + for _, e := range m.TxResults { + l = e.Size() + n += 1 + l + sovTypes(uint64(l)) + } + } + if len(m.ValidatorUpdates) > 0 { + for _, e := range m.ValidatorUpdates { + l = e.Size() n += 1 + l + sovTypes(uint64(l)) } } + if m.ConsensusParamUpdates != nil { + l = m.ConsensusParamUpdates.Size() + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -9199,6 +9718,24 @@ func (m *CommitInfo) 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 @@ -9299,6 +9836,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 @@ -9343,6 +9896,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 @@ -11894,7 +12465,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 { @@ -11921,14 +12492,16 @@ 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) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Header", wireType) } - m.BlockDataSize = 0 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -11938,18 +12511,64 @@ func (m *RequestPrepareProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.BlockDataSize |= int64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Votes", wireType) + if msglen < 0 { + return ErrInvalidLengthTypes } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + 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 { @@ -11972,11 +12591,63 @@ 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.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:]) @@ -15606,10 +16277,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 @@ -15619,79 +16290,17 @@ 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 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + byteLen - 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]) - 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 *ResponseProcessProposal) 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: ResponseProcessProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ResponseProcessProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Accept", wireType) + m.ModifiedTx = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxRecords", wireType) } - var v int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -15701,13 +16310,27 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.Accept = bool(v != 0) - case 2: + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxRecords = append(m.TxRecords, &TxRecord{}) + if err := m.TxRecords[len(m.TxRecords)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) } @@ -15741,7 +16364,7 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { m.AppHash = []byte{} } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxResults", wireType) } @@ -15775,7 +16398,7 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ValidatorUpdates", wireType) } @@ -15809,7 +16432,7 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: + case 6: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ConsensusParamUpdates", wireType) } @@ -15866,7 +16489,7 @@ func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { } return nil } -func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { +func (m *ResponseProcessProposal) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -15889,17 +16512,37 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ResponseFinalizeBlock: wiretype end group for non-group") + return fmt.Errorf("proto: ResponseProcessProposal: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ResponseFinalizeBlock: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ResponseProcessProposal: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Accept", 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.Accept = bool(v != 0) + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -15909,27 +16552,27 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthTypes } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthTypes } if postIndex > l { return io.ErrUnexpectedEOF } - m.Events = append(m.Events, Event{}) - if err := m.Events[len(m.Events)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) + if m.AppHash == nil { + m.AppHash = []byte{} } iNdEx = postIndex - case 2: + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxResults", wireType) } @@ -15963,7 +16606,7 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ValidatorUpdates", wireType) } @@ -15992,12 +16635,12 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ValidatorUpdates = append(m.ValidatorUpdates, ValidatorUpdate{}) + m.ValidatorUpdates = append(m.ValidatorUpdates, &ValidatorUpdate{}) if err := m.ValidatorUpdates[len(m.ValidatorUpdates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 4: + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field ConsensusParamUpdates", wireType) } @@ -16033,9 +16676,197 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) + 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 *ResponseFinalizeBlock) 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: ResponseFinalizeBlock: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResponseFinalizeBlock: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Events", 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.Events = append(m.Events, Event{}) + if err := m.Events[len(m.Events)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxResults", 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.TxResults = append(m.TxResults, &ExecTxResult{}) + if err := m.TxResults[len(m.TxResults)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorUpdates", 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.ValidatorUpdates = append(m.ValidatorUpdates, ValidatorUpdate{}) + if err := m.ValidatorUpdates[len(m.ValidatorUpdates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsensusParamUpdates", 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 m.ConsensusParamUpdates == nil { + m.ConsensusParamUpdates = &types1.ConsensusParams{} + } + if err := m.ConsensusParamUpdates.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -16071,7 +16902,95 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field RetainHeight", wireType) } - m.RetainHeight = 0 + m.RetainHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RetainHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *CommitInfo) 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: CommitInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CommitInfo: 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 @@ -16081,11 +17000,26 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.RetainHeight |= int64(b&0x7F) << shift + 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, VoteInfo{}) + 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:]) @@ -16107,7 +17041,7 @@ func (m *ResponseFinalizeBlock) Unmarshal(dAtA []byte) error { } return nil } -func (m *CommitInfo) Unmarshal(dAtA []byte) error { +func (m *ExtendedCommitInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -16130,10 +17064,10 @@ func (m *CommitInfo) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CommitInfo: wiretype end group for non-group") + return fmt.Errorf("proto: ExtendedCommitInfo: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ExtendedCommitInfo: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -16184,7 +17118,7 @@ func (m *CommitInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Votes = append(m.Votes, VoteInfo{}) + m.Votes = append(m.Votes, ExtendedVoteInfo{}) if err := m.Votes[len(m.Votes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -16886,6 +17820,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 @@ -17194,6 +18231,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/abci/types/types_test.go b/abci/types/types_test.go new file mode 100644 index 000000000..f79a24454 --- /dev/null +++ b/abci/types/types_test.go @@ -0,0 +1,74 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" +) + +func TestHashAndProveResults(t *testing.T) { + trs := []*abci.ExecTxResult{ + // Note, these tests rely on the first two entries being in this order. + {Code: 0, Data: nil}, + {Code: 0, Data: []byte{}}, + + {Code: 0, Data: []byte("one")}, + {Code: 14, Data: nil}, + {Code: 14, Data: []byte("foo")}, + {Code: 14, Data: []byte("bar")}, + } + + // Nil and []byte{} should produce the same bytes + bz0, err := trs[0].Marshal() + require.NoError(t, err) + bz1, err := trs[1].Marshal() + require.NoError(t, err) + require.Equal(t, bz0, bz1) + + // Make sure that we can get a root hash from results and verify proofs. + rs, err := abci.MarshalTxResults(trs) + require.NoError(t, err) + root := merkle.HashFromByteSlices(rs) + assert.NotEmpty(t, root) + + _, proofs := merkle.ProofsFromByteSlices(rs) + for i, tr := range trs { + bz, err := tr.Marshal() + require.NoError(t, err) + + valid := proofs[i].Verify(root, bz) + assert.NoError(t, valid, "%d", i) + } +} + +func TestHashDeterministicFieldsOnly(t *testing.T) { + tr1 := abci.ExecTxResult{ + Code: 1, + Data: []byte("transaction"), + Log: "nondeterministic data: abc", + Info: "nondeterministic data: abc", + GasWanted: 1000, + GasUsed: 1000, + Events: []abci.Event{}, + Codespace: "nondeterministic.data.abc", + } + tr2 := abci.ExecTxResult{ + Code: 1, + Data: []byte("transaction"), + Log: "nondeterministic data: def", + Info: "nondeterministic data: def", + GasWanted: 1000, + GasUsed: 1000, + Events: []abci.Event{}, + Codespace: "nondeterministic.data.def", + } + r1, err := abci.MarshalTxResults([]*abci.ExecTxResult{&tr1}) + require.NoError(t, err) + r2, err := abci.MarshalTxResults([]*abci.ExecTxResult{&tr2}) + require.NoError(t, err) + require.Equal(t, merkle.HashFromByteSlices(r1), merkle.HashFromByteSlices(r2)) +} diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 86b54fc51..00faaa8b8 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -85,6 +85,7 @@ Note the context/background should be written in the present tense. - [ADR-067: Mempool Refactor](./adr-067-mempool-refactor.md) - [ADR-075: RPC Event Subscription Interface](./adr-075-rpc-subscription.md) - [ADR-076: Combine Spec and Tendermint Repositories](./adr-076-combine-spec-repo.md) +- [ADR-081: Protocol Buffers Management](./adr-081-protobuf-mgmt.md) ### Deprecated diff --git a/docs/architecture/adr-081-protobuf-mgmt.md b/docs/architecture/adr-081-protobuf-mgmt.md new file mode 100644 index 000000000..1199cff1b --- /dev/null +++ b/docs/architecture/adr-081-protobuf-mgmt.md @@ -0,0 +1,201 @@ +# ADR 081: Protocol Buffers Management + +## Changelog + +- 2022-02-28: First draft + +## Status + +Accepted + +[Tracking issue](https://github.com/tendermint/tendermint/issues/8121) + +## Context + +At present, we manage the [Protocol Buffers] schema files ("protos") that define +our wire-level data formats within the Tendermint repository itself (see the +[`proto`](../../proto/) directory). Recently, we have been making use of [Buf], +both locally and in CI, in order to generate Go stubs, and lint and check +`.proto` files for breaking changes. + +The version of Buf used at the time of this decision was `v1beta1`, and it was +discussed in [\#7975] and in weekly calls as to whether we should upgrade to +`v1` and harmonize our approach with that used by the Cosmos SDK. The team +managing the Cosmos SDK was primarily interested in having our protos versioned +and easily accessible from the [Buf] registry. + +The three main sets of stakeholders for the `.proto` files and their needs, as +currently understood, are as follows. + +1. Tendermint needs Go code generated from `.proto` files. +2. Consumers of Tendermint's `.proto` files, specifically projects that want to + interoperate with Tendermint and need to generate code for their own + programming language, want to be able to access these files in a reliable and + efficient way. +3. The Tendermint Core team wants to provide stable interfaces that are as easy + as possible to maintain, on which consumers can depend, and to be able to + notify those consumers promptly when those interfaces change. To this end, we + want to: + 1. Prevent any breaking changes from being introduced in minor/patch releases + of Tendermint. Only major version updates should be able to contain + breaking interface changes. + 2. Prevent generated code from diverging from the Protobuf schema files. + +There was also discussion surrounding the notion of automated documentation +generation and hosting, but it is not clear at this time whether this would be +that valuable to any of our stakeholders. What will, of course, be valuable at +minimum would be better documentation (in comments) of the `.proto` files +themselves. + +## Alternative Approaches + +### Meeting stakeholders' needs + +1. Go stub generation from protos. We could use: + 1. [Buf]. This approach has been rather cumbersome up to this point, and it + is not clear what Buf really provides beyond that which `protoc` provides + to justify the additional complexity in configuring Buf for stub + generation. + 2. [protoc] - the Protocol Buffers compiler. +2. Notification of breaking changes: + 1. Buf in CI for all pull requests to *release* branches only (and not on + `master`). + 2. Buf in CI on every pull request to every branch (this was the case at the + time of this decision, and the team decided that the signal-to-noise ratio + for this approach was too low to be of value). +3. `.proto` linting: + 1. Buf in CI on every pull request +4. `.proto` formatting: + 1. [clang-format] locally and a [clang-format GitHub Action] in CI to check + that files are formatted properly on every pull request. +5. Sharing of `.proto` files in a versioned, reliable manner: + 1. Consumers could simply clone the Tendermint repository, check out a + specific commit, tag or branch and manually copy out all of the `.proto` + files they need. This requires no effort from the Tendermint Core team and + will continue to be an option for consumers. The drawback of this approach + is that it requires manual coding/scripting to implement and is brittle in + the face of bigger changes. + 2. Uploading our `.proto` files to Buf's registry on every release. This is + by far the most seamless for consumers of our `.proto` files, but requires + the dependency on Buf. This has the additional benefit that the Buf + registry will automatically [generate and host + documentation][buf-docs-gen] for these protos. + 3. We could create a process that, upon release, creates a `.zip` file + containing our `.proto` files. + +### Popular alternatives to Buf + +[Prototool] was not considered as it appears deprecated, and the ecosystem seems +to be converging on Buf at this time. + +### Tooling complexity + +The more tools we have in our build/CI processes, the more complex and fragile +repository/CI management becomes, and the longer it takes to onboard new team +members. Maintainability is a core concern here. + +### Buf sustainability and costs + +One of the primary considerations regarding the usage of Buf is whether, for +example, access to its registry will eventually become a +paid-for/subscription-based service and whether this is valuable enough for us +and the ecosystem to pay for such a service. At this time, it appears as though +Buf will never charge for hosting open source projects' protos. + +Another consideration was Buf's sustainability as a project - what happens when +their resources run out? Will there be a strong and broad enough open source +community to continue maintaining it? + +### Local Buf usage options + +Local usage of Buf (i.e. not in CI) can be accomplished in two ways: + +1. Installing the relevant tools individually. +2. By way of its [Docker image][buf-docker]. + +Local installation of Buf requires developers to manually keep their toolchains +up-to-date. The Docker option comes with a number of complexities, including +how the file system permissions of code generated by a Docker container differ +between platforms (e.g. on Linux, Buf-generated code ends up being owned by +`root`). + +The trouble with the Docker-based approach is that we make use of the +[gogoprotobuf] plugin for `protoc`. Continuing to use the Docker-based approach +to using Buf will mean that we will have to continue building our own custom +Docker image with embedded gogoprotobuf. + +Along these lines, we could eventually consider coming up with a [Nix]- or +[redo]-based approach to developer tooling to ensure tooling consistency across +the team and for anyone who wants to be able to contribute to Tendermint. + +## Decision + +1. We will adopt Buf for now for proto generation, linting, breakage checking + and its registry (mainly in CI, with optional usage locally). +2. Failing CI when checking for breaking changes in `.proto` files will only + happen when performing minor/patch releases. +3. Local tooling will be favored over Docker-based tooling. + +## Detailed Design + +We currently aim to: + +1. Update to Buf `v1` to facilitate linting, breakage checking and uploading to + the Buf registry. +2. Configure CI appropriately for proto management: + 1. Uploading protos to the Buf registry on every release (e.g. the + [approach][cosmos-sdk-buf-registry-ci] used by the Cosmos SDK). + 2. Linting on every pull request (e.g. the + [approach][cosmos-sdk-buf-linting-ci] used by the Cosmos SDK). The linter + passing should be considered a requirement for accepting PRs. + 3. Checking for breaking changes in minor/patch version releases and failing + CI accordingly - see [\#8003]. + 4. Add [clang-format GitHub Action] to check `.proto` file formatting. Format + checking should be considered a requirement for accepting PRs. +3. Update the Tendermint [`Makefile`](../../Makefile) to primarily facilitate + local Protobuf stub generation, linting, formatting and breaking change + checking. More specifically: + 1. This includes removing the dependency on Docker and introducing the + dependency on local toolchain installation. CI-based equivalents, where + relevant, will rely on specific GitHub Actions instead of the Makefile. + 2. Go code generation will rely on `protoc` directly. + +## Consequences + +### Positive + +- We will still offer Go stub generation, proto linting and breakage checking. +- Breakage checking will only happen on minor/patch releases to increase the + signal-to-noise ratio in CI. +- Versioned protos will be made available via Buf's registry upon every release. + +### Negative + +- Developers/contributors will need to install the relevant Protocol + Buffers-related tooling (Buf, gogoprotobuf, clang-format) locally in order to + build, lint, format and check `.proto` files for breaking changes. + +### Neutral + +## References + +- [Protocol Buffers] +- [Buf] +- [\#7975] +- [protoc] - The Protocol Buffers compiler + +[Protocol Buffers]: https://developers.google.com/protocol-buffers +[Buf]: https://buf.build/ +[\#7975]: https://github.com/tendermint/tendermint/pull/7975 +[protoc]: https://github.com/protocolbuffers/protobuf +[clang-format]: https://clang.llvm.org/docs/ClangFormat.html +[clang-format GitHub Action]: https://github.com/marketplace/actions/clang-format-github-action +[buf-docker]: https://hub.docker.com/r/bufbuild/buf +[cosmos-sdk-buf-registry-ci]: https://github.com/cosmos/cosmos-sdk/blob/e6571906043b6751951a42b6546431b1c38b05bd/.github/workflows/proto-registry.yml +[cosmos-sdk-buf-linting-ci]: https://github.com/cosmos/cosmos-sdk/blob/e6571906043b6751951a42b6546431b1c38b05bd/.github/workflows/proto.yml#L15 +[\#8003]: https://github.com/tendermint/tendermint/issues/8003 +[Nix]: https://nixos.org/ +[gogoprotobuf]: https://github.com/gogo/protobuf +[Prototool]: https://github.com/uber/prototool +[buf-docs-gen]: https://docs.buf.build/bsr/documentation +[redo]: https://redo.readthedocs.io/en/latest/ diff --git a/internal/blocksync/reactor_test.go b/internal/blocksync/reactor_test.go index 8d3399d52..14264e040 100644 --- a/internal/blocksync/reactor_test.go +++ b/internal/blocksync/reactor_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/fortytw2/leaktest" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -15,7 +16,7 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/consensus" "github.com/tendermint/tendermint/internal/eventbus" - "github.com/tendermint/tendermint/internal/mempool/mock" + mpmocks "github.com/tendermint/tendermint/internal/mempool/mocks" "github.com/tendermint/tendermint/internal/p2p" "github.com/tendermint/tendermint/internal/p2p/p2ptest" "github.com/tendermint/tendermint/internal/proxy" @@ -121,6 +122,17 @@ func (rts *reactorTestSuite) addNode( state, err := sm.MakeGenesisState(genDoc) require.NoError(t, err) require.NoError(t, stateStore.Save(state)) + 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) eventbus := eventbus.NewDefault(logger) require.NoError(t, eventbus.Start(ctx)) @@ -129,7 +141,7 @@ func (rts *reactorTestSuite) addNode( stateStore, log.TestingLogger(), rts.app[nodeID], - mock.Mempool{}, + mp, sm.EmptyEvidencePool{}, blockStore, eventbus, @@ -159,8 +171,7 @@ func (rts *reactorTestSuite) addNode( ) } - thisBlock, err := sf.MakeBlock(state, blockHeight, lastCommit) - require.NoError(t, err) + thisBlock := sf.MakeBlock(state, blockHeight, lastCommit) thisParts, err := thisBlock.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) blockID := types.BlockID{Hash: thisBlock.Hash(), PartSetHeader: thisParts.Header()} diff --git a/internal/consensus/byzantine_test.go b/internal/consensus/byzantine_test.go index 0573bd19d..221baf3e1 100644 --- a/internal/consensus/byzantine_test.go +++ b/internal/consensus/byzantine_test.go @@ -176,7 +176,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { require.NotNil(t, lazyNodeState.privValidator) var commit *types.Commit - var votes []*types.Vote switch { case lazyNodeState.Height == lazyNodeState.state.InitialHeight: // We're creating a proposal for the first block. @@ -185,7 +184,6 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { case lazyNodeState.LastCommit.HasTwoThirdsMajority(): // Make the commit from LastCommit commit = lazyNodeState.LastCommit.MakeCommit() - votes = lazyNodeState.LastCommit.GetVotes() default: // This shouldn't happen. lazyNodeState.logger.Error("enterPropose: Cannot propose anything: No commit for the previous block") return @@ -202,9 +200,10 @@ func TestByzantinePrevoteEquivocation(t *testing.T) { } proposerAddr := lazyNodeState.privValidatorPubKey.Address() - block, blockParts, err := lazyNodeState.blockExec.CreateProposalBlock( - ctx, lazyNodeState.Height, lazyNodeState.state, commit, proposerAddr, votes, - ) + block, err := lazyNodeState.blockExec.CreateProposalBlock( + ctx, lazyNodeState.Height, lazyNodeState.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, diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index c9c207b55..b0f22e54f 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -242,7 +242,9 @@ func decideProposal( t.Helper() cs1.mtx.Lock() - block, blockParts, err := cs1.createProposalBlock(ctx) + block, err := cs1.createProposalBlock(ctx) + require.NoError(t, err) + blockParts, err := block.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) validRound := cs1.ValidRound chainID := cs1.state.ChainID diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index 41e981003..e527e8598 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -310,7 +310,7 @@ func (app *CounterApplication) Commit() abci.ResponseCommit { func (app *CounterApplication) PrepareProposal( req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - return abci.ResponsePrepareProposal{BlockData: req.BlockData} + return abci.ResponsePrepareProposal{} } func (app *CounterApplication) ProcessProposal( diff --git a/internal/consensus/pbts_test.go b/internal/consensus/pbts_test.go index f99ec7e39..1cb6892c4 100644 --- a/internal/consensus/pbts_test.go +++ b/internal/consensus/pbts_test.go @@ -203,7 +203,7 @@ func (p *pbtsTestHarness) nextHeight(ctx context.Context, t *testing.T, proposer ensureNewRound(t, p.roundCh, p.currentHeight, p.currentRound) - b, _, err := p.observedState.createProposalBlock(ctx) + b, err := p.observedState.createProposalBlock(ctx) require.NoError(t, err) b.Height = p.currentHeight b.Header.Height = p.currentHeight diff --git a/internal/consensus/replay_test.go b/internal/consensus/replay_test.go index 2f6a531da..c735e9977 100644 --- a/internal/consensus/replay_test.go +++ b/internal/consensus/replay_test.go @@ -380,7 +380,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite { newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower) err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, newValidatorTx1, nil, mempool.TxInfo{}) assert.NoError(t, err) - propBlock, _, err := css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) + propBlock, err := css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) require.NoError(t, err) propBlockParts, err := propBlock.MakePartSet(partSize) require.NoError(t, err) @@ -414,7 +414,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite { updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25) err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, updateValidatorTx1, nil, mempool.TxInfo{}) assert.NoError(t, err) - propBlock, _, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) + propBlock, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) require.NoError(t, err) propBlockParts, err = propBlock.MakePartSet(partSize) require.NoError(t, err) @@ -455,7 +455,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite { newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower) err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, newValidatorTx3, nil, mempool.TxInfo{}) assert.NoError(t, err) - propBlock, _, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) + propBlock, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) require.NoError(t, err) propBlockParts, err = propBlock.MakePartSet(partSize) require.NoError(t, err) @@ -543,7 +543,7 @@ func setupSimulator(ctx context.Context, t *testing.T) *simulatorTestSuite { removeValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, 0) err = assertMempool(t, css[0].txNotifier).CheckTx(ctx, removeValidatorTx3, nil, mempool.TxInfo{}) assert.NoError(t, err) - propBlock, _, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) + propBlock, err = css[0].createProposalBlock(ctx) // changeProposer(t, cs1, vs2) require.NoError(t, err) propBlockParts, err = propBlock.MakePartSet(partSize) require.NoError(t, err) diff --git a/internal/consensus/state.go b/internal/consensus/state.go index bbb28f1d4..92b5b84d6 100644 --- a/internal/consensus/state.go +++ b/internal/consensus/state.go @@ -1300,8 +1300,16 @@ func (cs *State) defaultDecideProposal(ctx context.Context, height int64, round } else { // Create a new proposal block from state/txs from the mempool. var err error - block, blockParts, err = cs.createProposalBlock(ctx) - if block == nil || err != nil { + block, err = cs.createProposalBlock(ctx) + 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 } } @@ -1360,13 +1368,12 @@ func (cs *State) isProposalComplete() bool { // // NOTE: keep it side-effect free for clarity. // CONTRACT: cs.privValidator is not nil. -func (cs *State) createProposalBlock(ctx context.Context) (block *types.Block, blockParts *types.PartSet, err error) { +func (cs *State) createProposalBlock(ctx context.Context) (*types.Block, error) { if cs.privValidator == nil { - return nil, nil, errors.New("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. @@ -1376,23 +1383,22 @@ func (cs *State) createProposalBlock(ctx context.Context) (block *types.Block, b 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, 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("propose step; empty priv validator public key", "err", errPubKeyIsNotSet) - return + return nil, nil } proposerAddr := cs.privValidatorPubKey.Address() - return cs.blockExec.CreateProposalBlock(ctx, cs.Height, cs.state, commit, proposerAddr, votes) + return cs.blockExec.CreateProposalBlock(ctx, cs.Height, cs.state, commit, proposerAddr, cs.LastCommit.GetVotes()) } // Enter: `timeoutPropose` after entering Propose. diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 9e67adf31..f008e75d3 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -220,7 +220,7 @@ func TestStateBadProposal(t *testing.T) { proposalCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryCompleteProposal) voteCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryVote) - propBlock, _, err := cs1.createProposalBlock(ctx) // changeProposer(t, cs1, vs2) + propBlock, err := cs1.createProposalBlock(ctx) // changeProposer(t, cs1, vs2) require.NoError(t, err) // make the second validator the proposer by incrementing round @@ -282,7 +282,7 @@ func TestStateOversizedBlock(t *testing.T) { timeoutProposeCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryTimeoutPropose) voteCh := subscribe(ctx, t, cs1.eventBus, types.EventQueryVote) - propBlock, _, err := cs1.createProposalBlock(ctx) + propBlock, err := cs1.createProposalBlock(ctx) require.NoError(t, err) propBlock.Data.Txs = []types.Tx{tmrand.Bytes(2001)} propBlock.Header.DataHash = propBlock.Data.Hash() @@ -2632,7 +2632,7 @@ func TestStateTimestamp_ProposalNotMatch(t *testing.T) { addr := pv1.Address() voteCh := subscribeToVoter(ctx, t, cs1, addr) - propBlock, _, err := cs1.createProposalBlock(ctx) + propBlock, err := cs1.createProposalBlock(ctx) require.NoError(t, err) round++ incrementRound(vss[1:]...) @@ -2680,7 +2680,7 @@ func TestStateTimestamp_ProposalMatch(t *testing.T) { addr := pv1.Address() voteCh := subscribeToVoter(ctx, t, cs1, addr) - propBlock, _, err := cs1.createProposalBlock(ctx) + propBlock, err := cs1.createProposalBlock(ctx) require.NoError(t, err) round++ incrementRound(vss[1:]...) diff --git a/internal/evidence/pool_test.go b/internal/evidence/pool_test.go index b3f5df9f1..dcf44a5df 100644 --- a/internal/evidence/pool_test.go +++ b/internal/evidence/pool_test.go @@ -569,10 +569,7 @@ func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) (*store.Blo for i := int64(1); i <= state.LastBlockHeight; i++ { lastCommit := makeCommit(i-1, valAddr) - block, err := sf.MakeBlock(state, i, lastCommit) - if err != nil { - return nil, err - } + block := sf.MakeBlock(state, i, lastCommit) block.Header.Time = defaultEvidenceTime.Add(time.Duration(i) * time.Minute) block.Header.Version = version.Consensus{Block: version.BlockProtocol, App: 1} diff --git a/internal/mempool/mock/mempool.go b/internal/mempool/mock/mempool.go deleted file mode 100644 index 1a0cd75ae..000000000 --- a/internal/mempool/mock/mempool.go +++ /dev/null @@ -1,46 +0,0 @@ -package mock - -import ( - "context" - - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/internal/libs/clist" - "github.com/tendermint/tendermint/internal/mempool" - "github.com/tendermint/tendermint/types" -) - -// Mempool is an empty implementation of a Mempool, useful for testing. -type Mempool struct{} - -var _ Mempool = Mempool{} - -func (Mempool) Lock() {} -func (Mempool) Unlock() {} -func (Mempool) Size() int { return 0 } -func (Mempool) CheckTx(context.Context, types.Tx, func(*abci.ResponseCheckTx), 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( - _ context.Context, - _ int64, - _ types.Txs, - _ []*abci.ExecTxResult, - _ mempool.PreCheckFunc, - _ mempool.PostCheckFunc, -) error { - return nil -} -func (Mempool) Flush() {} -func (Mempool) FlushAppConn(ctx context.Context) 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/internal/mempool/mocks/mempool.go b/internal/mempool/mocks/mempool.go new file mode 100644 index 000000000..d4cdfabd7 --- /dev/null +++ b/internal/mempool/mocks/mempool.go @@ -0,0 +1,172 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + context "context" + + abcitypes "github.com/tendermint/tendermint/abci/types" + + mempool "github.com/tendermint/tendermint/internal/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: ctx, tx, callback, txInfo +func (_m *Mempool) CheckTx(ctx context.Context, tx types.Tx, callback func(*abcitypes.ResponseCheckTx), txInfo mempool.TxInfo) error { + ret := _m.Called(ctx, tx, callback, txInfo) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.Tx, func(*abcitypes.ResponseCheckTx), mempool.TxInfo) error); ok { + r0 = rf(ctx, 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: _a0 +func (_m *Mempool) FlushAppConn(_a0 context.Context) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } 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: ctx, blockHeight, blockTxs, txResults, newPreFn, newPostFn +func (_m *Mempool) Update(ctx context.Context, blockHeight int64, blockTxs types.Txs, txResults []*abcitypes.ExecTxResult, newPreFn mempool.PreCheckFunc, newPostFn mempool.PostCheckFunc) error { + ret := _m.Called(ctx, blockHeight, blockTxs, txResults, newPreFn, newPostFn) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, types.Txs, []*abcitypes.ExecTxResult, mempool.PreCheckFunc, mempool.PostCheckFunc) error); ok { + r0 = rf(ctx, blockHeight, blockTxs, txResults, newPreFn, newPostFn) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/internal/mempool/types.go b/internal/mempool/types.go index c2124d538..a51d286e2 100644 --- a/internal/mempool/types.go +++ b/internal/mempool/types.go @@ -23,6 +23,8 @@ const ( MaxActiveIDs = math.MaxUint16 ) +//go:generate ../../scripts/mockery_generate.sh Mempool + // Mempool defines the mempool interface. // // Updates to the mempool need to be synchronized with committing a block so diff --git a/internal/rpc/core/tx.go b/internal/rpc/core/tx.go index 126875d0d..73fa6d2c8 100644 --- a/internal/rpc/core/tx.go +++ b/internal/rpc/core/tx.go @@ -36,19 +36,16 @@ func (env *Environment) Tx(ctx context.Context, hash bytes.HexBytes, prove bool) return nil, fmt.Errorf("tx (%X) not found, err: %w", hash, err) } - 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 &coretypes.ResultTx{ Hash: hash, - Height: height, - Index: index, + Height: r.Height, + Index: r.Index, TxResult: r.Result, Tx: r.Tx, Proof: proof, @@ -127,7 +124,7 @@ func (env *Environment) 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, &coretypes.ResultTx{ diff --git a/internal/state/execution.go b/internal/state/execution.go index 158d0d137..3423b00f6 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -8,6 +8,7 @@ import ( abciclient "github.com/tendermint/tendermint/abci/client" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/encoding" + "github.com/tendermint/tendermint/crypto/merkle" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/mempool" "github.com/tendermint/tendermint/libs/log" @@ -99,10 +100,11 @@ func (blockExec *BlockExecutor) Store() Store { func (blockExec *BlockExecutor) CreateProposalBlock( ctx context.Context, height int64, - state State, commit *types.Commit, + state State, + commit *types.Commit, proposerAddr []byte, votes []*types.Vote, -) (*types.Block, *types.PartSet, error) { +) (*types.Block, error) { maxBytes := state.ConsensusParams.Block.MaxBytes maxGas := state.ConsensusParams.Block.MaxGas @@ -113,13 +115,18 @@ 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.appClient.PrepareProposal( + localLastCommit := buildLastCommitInfo(block, blockExec.store, state.InitialHeight) + rpp, err := blockExec.appClient.PrepareProposal( ctx, 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.ToABCI(), + MaxTxBytes: maxDataBytes, }, ) if err != nil { @@ -133,19 +140,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) - modifiedTxs := types.ToTxs(preparedProposal.GetBlockData()) + if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { + return nil, err + } - 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(ctx, 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 } func (blockExec *BlockExecutor) ProcessProposal( @@ -249,7 +265,12 @@ func (blockExec *BlockExecutor) ApplyBlock( } // Update the state with the block and responses. - state, err = state.Update(blockID, &block.Header, ABCIResponsesResultsHash(abciResponses), finalizeBlockResponse.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(finalizeBlockResponse.TxResults) + if err != nil { + return state, fmt.Errorf("marshaling TxResults: %w", err) + } + h := merkle.HashFromByteSlices(rs) + state, err = state.Update(blockID, &block.Header, h, finalizeBlockResponse.ConsensusParamUpdates, validatorUpdates) if err != nil { return state, fmt.Errorf("commit failed for application: %w", err) } @@ -410,6 +431,24 @@ func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) a } } +func extendedCommitInfo(c abci.CommitInfo, 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 types.ValidatorParams) error { for _, valUpdate := range abciUpdates { diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index 451a9e2bb..e62735a4a 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -18,7 +18,7 @@ import ( "github.com/tendermint/tendermint/crypto/encoding" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/internal/eventbus" - mmock "github.com/tendermint/tendermint/internal/mempool/mock" + mpmocks "github.com/tendermint/tendermint/internal/mempool/mocks" "github.com/tendermint/tendermint/internal/proxy" "github.com/tendermint/tendermint/internal/pubsub" sm "github.com/tendermint/tendermint/internal/state" @@ -53,10 +53,20 @@ func TestApplyBlock(t *testing.T) { state, stateDB, _ := makeState(t, 1, 1) stateStore := sm.NewStore(stateDB) blockStore := store.NewBlockStore(dbm.NewMemDB()) - blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mmock.Mempool{}, sm.EmptyEvidencePool{}, blockStore, eventBus) - - block, err := sf.MakeBlock(state, 1, new(types.Commit)) - require.NoError(t, 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) + blockExec := sm.NewBlockExecutor(stateStore, logger, proxyApp, mp, sm.EmptyEvidencePool{}, blockStore, eventBus) + + 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()} @@ -103,11 +113,22 @@ func TestFinalizeBlockDecidedLastCommit(t *testing.T) { evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, 0) evpool.On("Update", ctx, mock.Anything, mock.Anything).Return() evpool.On("CheckEvidence", ctx, mock.Anything).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) eventBus := eventbus.NewDefault(logger) require.NoError(t, eventBus.Start(ctx)) - blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), appClient, mmock.Mempool{}, evpool, blockStore, eventBus) + blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), appClient, mp, evpool, blockStore, eventBus) state, _, lastCommit := makeAndCommitGoodBlock(ctx, t, state, 1, new(types.Commit), state.NextValidators.Validators[0].Address, blockExec, privVals, nil) for idx, isAbsent := range tc.absentCommitSigs { @@ -117,8 +138,7 @@ func TestFinalizeBlockDecidedLastCommit(t *testing.T) { } // block for height 2 - block, err := sf.MakeBlock(state, 2, lastCommit) - require.NoError(t, err) + block := sf.MakeBlock(state, 2, lastCommit) bps, err := block.MakePartSet(testPartSize) require.NoError(t, err) blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()} @@ -215,6 +235,17 @@ func TestFinalizeBlockByzantineValidators(t *testing.T) { evpool.On("PendingEvidence", mock.AnythingOfType("int64")).Return(ev, int64(100)) evpool.On("Update", ctx, mock.AnythingOfType("state.State"), mock.AnythingOfType("types.EvidenceList")).Return() evpool.On("CheckEvidence", ctx, 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) eventBus := eventbus.NewDefault(logger) require.NoError(t, eventBus.Start(ctx)) @@ -222,10 +253,9 @@ func TestFinalizeBlockByzantineValidators(t *testing.T) { blockStore := store.NewBlockStore(dbm.NewMemDB()) blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp, - mmock.Mempool{}, evpool, blockStore, eventBus) + mp, evpool, blockStore, eventBus) - block, err := sf.MakeBlock(state, 1, new(types.Commit)) - require.NoError(t, err) + block := sf.MakeBlock(state, 1, new(types.Commit)) block.Evidence = ev block.Header.EvidenceHash = block.Evidence.Hash() bps, err := block.MakePartSet(testPartSize) @@ -264,14 +294,13 @@ func TestProcessProposal(t *testing.T) { stateStore, logger, proxyApp, - mmock.Mempool{}, + new(mpmocks.Mempool), sm.EmptyEvidencePool{}, blockStore, eventBus, ) - block0, err := sf.MakeBlock(state, height-1, new(types.Commit)) - require.NoError(t, err) + block0 := sf.MakeBlock(state, height-1, new(types.Commit)) lastCommitSig := []types.CommitSig{} partSet, err := block0.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) @@ -295,8 +324,7 @@ func TestProcessProposal(t *testing.T) { } lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, lastCommitSig) - block1, err := sf.MakeBlock(state, height, lastCommit) - require.NoError(t, err) + block1 := sf.MakeBlock(state, height, lastCommit) block1.Txs = txs expectedRpp := abci.RequestProcessProposal{ @@ -463,6 +491,18 @@ func TestFinalizeBlockValidatorUpdates(t *testing.T) { state, stateDB, _ := makeState(t, 1, 1) stateStore := sm.NewStore(stateDB) blockStore := store.NewBlockStore(dbm.NewMemDB()) + 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{}) eventBus := eventbus.NewDefault(logger) require.NoError(t, eventBus.Start(ctx)) @@ -471,7 +511,7 @@ func TestFinalizeBlockValidatorUpdates(t *testing.T) { stateStore, logger, proxyApp, - mmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, blockStore, eventBus, @@ -483,8 +523,7 @@ func TestFinalizeBlockValidatorUpdates(t *testing.T) { }) require.NoError(t, err) - block, err := sf.MakeBlock(state, 1, new(types.Commit)) - require.NoError(t, err) + 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()} @@ -542,14 +581,13 @@ func TestFinalizeBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { stateStore, log.TestingLogger(), proxyApp, - mmock.Mempool{}, + new(mpmocks.Mempool), sm.EmptyEvidencePool{}, blockStore, eventBus, ) - block, err := sf.MakeBlock(state, 1, new(types.Commit)) - require.NoError(t, err) + 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()} @@ -566,6 +604,292 @@ func TestFinalizeBlockValidatorUpdatesResultingInEmptySet(t *testing.T) { assert.NotEmpty(t, state.NextValidators.Validators) } +func TestEmptyPrepareProposal(t *testing.T) { + const height = 2 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + app := abcimocks.NewBaseMock() + cc := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + state, stateDB, privVals := makeState(t, 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, + logger, + proxyApp, + mp, + sm.EmptyEvidencePool{}, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + _, err = blockExec.CreateProposalBlock(ctx, 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 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 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 := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, 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 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 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, 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 := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, 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", mock.Anything, types.Tx(trs[0].Tx), mock.Anything, mock.Anything) + mp.AssertCalled(t, "CheckTx", mock.Anything, 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 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 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 := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, 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) + +} + +// TestPrepareProposalModifiedTxFalse tests that CreateBlock correctly ignores +// the ResponsePrepareProposal TxRecords if ResponsePrepareProposal does not +// set ModifiedTx to true. +func TestPrepareProposalModifiedTxFalse(t *testing.T) { + const height = 2 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 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 = append(trs[len(trs)/2:], trs[:len(trs)/2]...) + trs = trs[1:] + trs[0].Action = abci.TxRecord_REMOVED + trs[1] = &abci.TxRecord{ + Tx: []byte("new"), + Action: abci.TxRecord_ADDED, + } + + app := abcimocks.NewBaseMock() + app.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{ + ModifiedTx: false, + TxRecords: trs, + }, nil) + + cc := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + block, err := blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) + require.NoError(t, err) + for i, tx := range block.Data.Txs { + require.Equal(t, txs[i], tx) + } + + mp.AssertExpectations(t) +} + func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID { var ( h = make([]byte, tmhash.Size) @@ -581,3 +905,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/internal/state/helpers_test.go b/internal/state/helpers_test.go index 6df958908..dffb6f256 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -18,7 +18,6 @@ import ( sm "github.com/tendermint/tendermint/internal/state" sf "github.com/tendermint/tendermint/internal/state/test/factory" "github.com/tendermint/tendermint/internal/test/factory" - tmrand "github.com/tendermint/tendermint/libs/rand" tmtime "github.com/tendermint/tendermint/libs/time" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -63,12 +62,13 @@ func makeAndApplyGoodBlock( evidence []types.Evidence, ) (sm.State, types.BlockID) { t.Helper() - block, _, err := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + block := state.MakeBlock(height, factory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) require.NoError(t, blockExec.ValidateBlock(ctx, state, block)) blockID := types.BlockID{Hash: block.Hash(), - PartSetHeader: types.PartSetHeader{Total: 3, Hash: tmrand.Bytes(32)}} + PartSetHeader: partSet.Header()} state, err = blockExec.ApplyBlock(ctx, state, blockID, block) require.NoError(t, err) @@ -144,8 +144,7 @@ func makeHeaderPartsResponsesValPubKeyChange( pubkey crypto.PubKey, ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { - block, err := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{} // If the pubkey is new, remove the old and add the new. _, val := state.NextValidators.GetByIndex(0) @@ -173,8 +172,7 @@ func makeHeaderPartsResponsesValPowerChange( ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { t.Helper() - block, err := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) abciResponses := &tmstate.ABCIResponses{} @@ -202,8 +200,7 @@ func makeHeaderPartsResponsesParams( ) (types.Header, types.BlockID, *tmstate.ABCIResponses) { t.Helper() - block, err := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := sf.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) pbParams := params.ToProto() abciResponses := &tmstate.ABCIResponses{ FinalizeBlock: &abci.ResponseFinalizeBlock{ConsensusParamUpdates: &pbParams}, diff --git a/internal/state/state.go b/internal/state/state.go index f036ab7df..a31d8baad 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -267,7 +267,7 @@ func (state State) MakeBlock( commit *types.Commit, evidence []types.Evidence, proposerAddress []byte, -) (*types.Block, *types.PartSet, error) { +) *types.Block { // Build base block with block data. block := types.MakeBlock(height, txs, commit, evidence) @@ -281,12 +281,7 @@ func (state State) MakeBlock( proposerAddress, ) - bps, err := block.MakePartSet(types.BlockPartSizeBytes) - if err != nil { - return nil, nil, err - } - - return block, bps, nil + return block } //------------------------------------------------------------------------ diff --git a/internal/state/state_test.go b/internal/state/state_test.go index d64f6891c..f38d37ea4 100644 --- a/internal/state/state_test.go +++ b/internal/state/state_test.go @@ -18,6 +18,7 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/encoding" + "github.com/tendermint/tendermint/crypto/merkle" sm "github.com/tendermint/tendermint/internal/state" statefactory "github.com/tendermint/tendermint/internal/state/test/factory" tmstate "github.com/tendermint/tendermint/proto/tendermint/state" @@ -110,8 +111,7 @@ func TestABCIResponsesSaveLoad1(t *testing.T) { state.LastBlockHeight++ // Build mock responses. - block, err := statefactory.MakeBlock(state, 2, new(types.Commit)) - require.NoError(t, err) + block := statefactory.MakeBlock(state, 2, new(types.Commit)) abciResponses := new(tmstate.ABCIResponses) dtxs := make([]*abci.ExecTxResult, 2) @@ -212,14 +212,13 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { res, err := stateStore.LoadABCIResponses(h) if assert.NoError(t, err, "%d", i) { t.Log(res) - responses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - TxResults: tc.expected, - }, - } - sm.ABCIResponsesResultsHash(res) - sm.ABCIResponsesResultsHash(responses) - assert.Equal(t, sm.ABCIResponsesResultsHash(responses), sm.ABCIResponsesResultsHash(res), "%d", i) + e, err := abci.MarshalTxResults(tc.expected) + require.NoError(t, err) + he := merkle.HashFromByteSlices(e) + rs, err := abci.MarshalTxResults(res.FinalizeBlock.TxResults) + hrs := merkle.HashFromByteSlices(rs) + require.NoError(t, err) + assert.Equal(t, he, hrs, "%d", i) } } } @@ -285,9 +284,12 @@ func TestOneValidatorChangesSaveLoad(t *testing.T) { header, blockID, responses := makeHeaderPartsResponsesValPowerChange(t, state, power) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(responses.FinalizeBlock.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + state, err = state.Update(blockID, &header, h, responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) - err := stateStore.Save(state) + err = stateStore.Save(state) require.NoError(t, err) } @@ -458,19 +460,19 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { // NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1 assert.EqualValues(t, 0, val1.ProposerPriority) - block, err := statefactory.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) + require.NoError(t, err) + rs, err := abci.MarshalTxResults(fb.TxResults) require.NoError(t, err) - updatedState, err := state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + h := merkle.HashFromByteSlices(rs) + updatedState, err := state.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) curTotal := val1VotingPower // one increment step and one validator: 0 + power - total_power == 0 @@ -485,7 +487,10 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { updateAddVal := abci.ValidatorUpdate{PubKey: fvp, Power: val2VotingPower} validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) assert.NoError(t, err) - updatedState2, err := updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + updatedState2, err := updatedState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState2.NextValidators.Validators), 2) @@ -524,7 +529,10 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { // this will cause the diff of priorities (77) // to be larger than threshold == 2*totalVotingPower (22): - updatedState3, err := updatedState2.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + updatedState3, err := updatedState2.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState3.NextValidators.Validators), 2) @@ -576,21 +584,21 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // we only have one validator: assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) - block, err := statefactory.MakeBlock(state, state.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err := state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedState, err := state.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) // 0 + 10 (initial prio) - 10 (avg) - 10 (mostest - total) = -10 @@ -607,7 +615,10 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) assert.NoError(t, err) - updatedState2, err := updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + updatedState2, err := updatedState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) require.Equal(t, len(updatedState2.NextValidators.Validators), 2) @@ -647,10 +658,13 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { updatedVal2, ) - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState3, err := updatedState2.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + updatedState3, err := updatedState2.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) assert.Equal(t, updatedState3.Validators.Proposer.Address, updatedState3.NextValidators.Proposer.Address) @@ -686,15 +700,16 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // no changes in voting power and both validators have same voting power // -> proposers should alternate: oldState := updatedState3 - abciResponses = &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - oldState, err = oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + oldState, err = oldState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) expectedVal1Prio2 = 1 expectedVal2Prio2 = -1 @@ -703,15 +718,16 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { for i := 0; i < 1000; i++ { // no validator updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedState, err := oldState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) assert.NoError(t, err) // alternate (and cyclic priorities): assert.NotEqual( @@ -762,21 +778,21 @@ func TestLargeGenesisValidator(t *testing.T) { oldState := state for i := 0; i < 10; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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 := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedState, err := oldState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) // no changes in voting power (ProposerPrio += VotingPower == Voting in 1st round; than shiftByAvg == 0, // than -Total == -Voting) @@ -798,41 +814,41 @@ func TestLargeGenesisValidator(t *testing.T) { firstAddedVal := abci.ValidatorUpdate{PubKey: fvp, Power: firstAddedValVotingPower} validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) assert.NoError(t, err) - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}, } - block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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 := oldState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedState, err := oldState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) lastState := updatedState for i := 0; i < 200; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - block, err := statefactory.MakeBlock(lastState, lastState.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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 := lastState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedStateInner, err := lastState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) lastState = updatedStateInner } @@ -858,18 +874,18 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{addedVal}) assert.NoError(t, err) - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{addedVal}, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{addedVal}, } - block, err := statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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 = state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + state, err = state.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) } require.Equal(t, 10+2, len(state.NextValidators.Validators)) @@ -878,22 +894,23 @@ func TestLargeGenesisValidator(t *testing.T) { gp, err := encoding.PubKeyToProto(genesisPubKey) require.NoError(t, err) removeGenesisVal := abci.ValidatorUpdate{PubKey: gp, Power: 0} - abciResponses = &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}, } - block, err = statefactory.MakeBlock(oldState, oldState.LastBlockHeight+1, new(types.Commit)) + block = statefactory.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.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - updatedState, err = state.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err = abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h = merkle.HashFromByteSlices(rs) + updatedState, err = state.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) // only the first added val (not the genesis val) should be left assert.Equal(t, 11, len(updatedState.NextValidators.Validators)) @@ -904,21 +921,21 @@ func TestLargeGenesisValidator(t *testing.T) { count := 0 isProposerUnchanged := true for isProposerUnchanged { - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb = &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) - require.NoError(t, err) - block, err = statefactory.MakeBlock(curState, curState.LastBlockHeight+1, new(types.Commit)) + validatorUpdates, err = types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) + block = statefactory.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 = curState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + curState, err = curState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { isProposerUnchanged = false @@ -934,23 +951,23 @@ func TestLargeGenesisValidator(t *testing.T) { proposers := make([]*types.Validator, numVals) for i := 0; i < 100; i++ { // no updates: - abciResponses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - ValidatorUpdates: nil, - }, + fb := &abci.ResponseFinalizeBlock{ + ValidatorUpdates: nil, } - validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.FinalizeBlock.ValidatorUpdates) + validatorUpdates, err := types.PB2TM.ValidatorUpdates(fb.ValidatorUpdates) require.NoError(t, err) - block, err := statefactory.MakeBlock(updatedState, updatedState.LastBlockHeight+1, new(types.Commit)) - require.NoError(t, err) + block := statefactory.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 = updatedState.Update(blockID, &block.Header, sm.ABCIResponsesResultsHash(abciResponses), abciResponses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(fb.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + updatedState, err = updatedState.Update(blockID, &block.Header, h, fb.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) if i > numVals { // expect proposers to cycle through after the first iteration (of numVals blocks): if proposers[i%numVals] == nil { @@ -1009,7 +1026,10 @@ func TestManyValidatorChangesSaveLoad(t *testing.T) { var validatorUpdates []*types.Validator validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(responses.FinalizeBlock.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + state, err = state.Update(blockID, &header, h, responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) nextHeight := state.LastBlockHeight + 1 err = stateStore.Save(state) @@ -1042,8 +1062,7 @@ func TestStateMakeBlock(t *testing.T) { proposerAddress := state.Validators.GetProposer().Address stateVersion := state.Version.Consensus - block, err := statefactory.MakeBlock(state, 2, new(types.Commit)) - require.NoError(t, err) + block := statefactory.MakeBlock(state, 2, new(types.Commit)) // test we set some fields assert.Equal(t, stateVersion, block.Version) @@ -1087,10 +1106,13 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) { header, blockID, responses := makeHeaderPartsResponsesParams(t, state, &cp) validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.FinalizeBlock.ValidatorUpdates) require.NoError(t, err) - state, err = state.Update(blockID, &header, sm.ABCIResponsesResultsHash(responses), responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) + rs, err := abci.MarshalTxResults(responses.FinalizeBlock.TxResults) + require.NoError(t, err) + h := merkle.HashFromByteSlices(rs) + state, err = state.Update(blockID, &header, h, responses.FinalizeBlock.ConsensusParamUpdates, validatorUpdates) require.NoError(t, err) - err := stateStore.Save(state) + err = stateStore.Save(state) require.NoError(t, err) } diff --git a/internal/state/store.go b/internal/state/store.go index 53848dba8..93bd3eb2b 100644 --- a/internal/state/store.go +++ b/internal/state/store.go @@ -406,14 +406,6 @@ func (store dbStore) reverseBatchDelete(batch dbm.Batch, start, end []byte) ([]b //------------------------------------------------------------------------ -// ABCIResponsesResultsHash returns the root hash of a Merkle tree of -// ResponseDeliverTx responses (see ABCIResults.Hash) -// -// See merkle.SimpleHashFromByteSlices -func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte { - return types.NewResults(ar.FinalizeBlock.TxResults).Hash() -} - // LoadABCIResponses loads the ABCIResponses for the given height from the // database. If not found, ErrNoABCIResponsesForHeight is returned. // diff --git a/internal/state/store_test.go b/internal/state/store_test.go index 0134d5987..59084fd10 100644 --- a/internal/state/store_test.go +++ b/internal/state/store_test.go @@ -7,7 +7,6 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" @@ -299,25 +298,3 @@ func TestPruneStates(t *testing.T) { }) } } - -func TestABCIResponsesResultsHash(t *testing.T) { - responses := &tmstate.ABCIResponses{ - FinalizeBlock: &abci.ResponseFinalizeBlock{ - TxResults: []*abci.ExecTxResult{ - {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, - }, - }, - } - - root := sm.ABCIResponsesResultsHash(responses) - - // root should be Merkle tree root of FinalizeBlock tx responses - results := types.NewResults(responses.FinalizeBlock.TxResults) - assert.Equal(t, root, results.Hash()) - - // test we can prove first tx in FinalizeBlock - proof := results.ProveResult(0) - bz, err := results[0].Marshal() - require.NoError(t, err) - assert.NoError(t, proof.Verify(root, bz)) -} diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index 5154d170a..14f49e2d5 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -42,19 +42,14 @@ func MakeBlocks(ctx context.Context, t *testing.T, n int, state *sm.State, privV return blocks } -func MakeBlock(state sm.State, height int64, c *types.Commit) (*types.Block, error) { - block, _, err := state.MakeBlock( +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, ) - if err != nil { - return nil, err - } - - return block, nil } func makeBlockAndPartSet( @@ -82,7 +77,8 @@ func makeBlockAndPartSet( lastBlockMeta.BlockID, []types.CommitSig{vote.CommitSig()}) } - block, partSet, err := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + block := state.MakeBlock(height, []types.Tx{}, lastCommit, nil, state.Validators.GetProposer().Address) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) require.NoError(t, err) return block, partSet diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index 74a41fdf9..62d2051cb 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -15,7 +15,7 @@ import ( "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/internal/eventbus" - memmock "github.com/tendermint/tendermint/internal/mempool/mock" + mpmocks "github.com/tendermint/tendermint/internal/mempool/mocks" "github.com/tendermint/tendermint/internal/proxy" sm "github.com/tendermint/tendermint/internal/state" "github.com/tendermint/tendermint/internal/state/mocks" @@ -42,12 +42,24 @@ func TestValidateBlockHeader(t *testing.T) { state, stateDB, privVals := makeState(t, 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) + blockStore := store.NewBlockStore(dbm.NewMemDB()) blockExec := sm.NewBlockExecutor( stateStore, logger, proxyApp, - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, blockStore, eventBus, @@ -98,10 +110,9 @@ func TestValidateBlockHeader(t *testing.T) { Invalid blocks don't pass */ for _, tc := range testCases { - block, err := statefactory.MakeBlock(state, height, lastCommit) - require.NoError(t, err) + block := statefactory.MakeBlock(state, height, lastCommit) tc.malleateBlock(block) - err = blockExec.ValidateBlock(ctx, state, block) + err := blockExec.ValidateBlock(ctx, state, block) t.Logf("%s: %v", tc.name, err) require.Error(t, err, tc.name) } @@ -114,10 +125,9 @@ func TestValidateBlockHeader(t *testing.T) { } nextHeight := validationTestsStopHeight - block, err := statefactory.MakeBlock(state, nextHeight, lastCommit) - require.NoError(t, err) + block := statefactory.MakeBlock(state, nextHeight, lastCommit) state.InitialHeight = nextHeight + 1 - err = blockExec.ValidateBlock(ctx, state, block) + err := blockExec.ValidateBlock(ctx, state, block) require.Error(t, err, "expected an error when state is ahead of block") assert.Contains(t, err.Error(), "lower than initial height") } @@ -135,12 +145,24 @@ func TestValidateBlockCommit(t *testing.T) { state, stateDB, privVals := makeState(t, 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) + blockStore := store.NewBlockStore(dbm.NewMemDB()) blockExec := sm.NewBlockExecutor( stateStore, logger, proxyApp, - memmock.Mempool{}, + mp, sm.EmptyEvidencePool{}, blockStore, eventBus, @@ -174,8 +196,7 @@ func TestValidateBlockCommit(t *testing.T) { state.LastBlockID, []types.CommitSig{wrongHeightVote.CommitSig()}, ) - block, err := statefactory.MakeBlock(state, height, wrongHeightCommit) - require.NoError(t, err) + block := statefactory.MakeBlock(state, height, wrongHeightCommit) err = blockExec.ValidateBlock(ctx, state, block) _, isErrInvalidCommitHeight := err.(types.ErrInvalidCommitHeight) require.True(t, isErrInvalidCommitHeight, "expected ErrInvalidCommitHeight at height %d but got: %v", height, err) @@ -183,8 +204,7 @@ func TestValidateBlockCommit(t *testing.T) { /* #2589: test len(block.LastCommit.Signatures) == state.LastValidators.Size() */ - block, err = statefactory.MakeBlock(state, height, wrongSigsCommit) - require.NoError(t, err) + block = statefactory.MakeBlock(state, height, wrongSigsCommit) err = blockExec.ValidateBlock(ctx, state, block) _, isErrInvalidCommitSignatures := err.(types.ErrInvalidCommitSignatures) require.True(t, isErrInvalidCommitSignatures, @@ -274,13 +294,24 @@ func TestValidateBlockEvidence(t *testing.T) { eventBus := eventbus.NewDefault(logger) require.NoError(t, eventBus.Start(ctx)) + 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, - memmock.Mempool{}, + mp, evpool, blockStore, eventBus, @@ -304,10 +335,9 @@ func TestValidateBlockEvidence(t *testing.T) { evidence = append(evidence, newEv) currentBytes += int64(len(newEv.Bytes())) } - block, _, err := state.MakeBlock(height, testfactory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) - require.NoError(t, err) + block := state.MakeBlock(height, testfactory.MakeTenTxs(height), lastCommit, evidence, proposerAddr) - err = blockExec.ValidateBlock(ctx, state, block) + err := blockExec.ValidateBlock(ctx, state, block) if assert.Error(t, err) { _, ok := err.(*types.ErrEvidenceOverflow) require.True(t, ok, "expected error to be of type ErrEvidenceOverflow at height %d but got %v", height, err) diff --git a/internal/store/store_test.go b/internal/store/store_test.go index 8e1ee2db3..82949b103 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -86,11 +86,8 @@ func TestMain(m *testing.M) { stdlog.Fatal(err) } - block, err = factory.MakeBlock(state, 1, new(types.Commit)) + block = factory.MakeBlock(state, 1, new(types.Commit)) - if err != nil { - stdlog.Fatal(err) - } partSet, err = block.MakePartSet(2) if err != nil { stdlog.Fatal(err) @@ -121,8 +118,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) { } // save a block - block, err := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) - require.NoError(t, err) + block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) validPartSet, err := block.MakePartSet(2) require.NoError(t, err) seenCommit := makeTestCommit(10, tmtime.Now()) @@ -326,8 +322,7 @@ func TestLoadBaseMeta(t *testing.T) { bs := NewBlockStore(dbm.NewMemDB()) for h := int64(1); h <= 10; h++ { - block, err := factory.MakeBlock(state, h, new(types.Commit)) - require.NoError(t, err) + block := factory.MakeBlock(state, h, new(types.Commit)) partSet, err := block.MakePartSet(2) require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) @@ -394,8 +389,7 @@ func TestPruneBlocks(t *testing.T) { // make more than 1000 blocks, to test batch deletions for h := int64(1); h <= 1500; h++ { - block, err := factory.MakeBlock(state, h, new(types.Commit)) - require.NoError(t, err) + block := factory.MakeBlock(state, h, new(types.Commit)) partSet, err := block.MakePartSet(2) require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) @@ -502,8 +496,7 @@ func TestBlockFetchAtHeight(t *testing.T) { defer cleanup() require.NoError(t, err) require.Equal(t, bs.Height(), int64(0), "initially the height should be zero") - block, err := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) - require.NoError(t, err) + block := factory.MakeBlock(state, bs.Height()+1, new(types.Commit)) partSet, err := block.MakePartSet(2) require.NoError(t, err) @@ -545,8 +538,7 @@ func TestSeenAndCanonicalCommit(t *testing.T) { // are persisted. for h := int64(3); h <= 5; h++ { blockCommit := makeTestCommit(h-1, tmtime.Now()) - block, err := factory.MakeBlock(state, h, blockCommit) - require.NoError(t, err) + block := factory.MakeBlock(state, h, blockCommit) partSet, err := block.MakePartSet(2) require.NoError(t, err) seenCommit := makeTestCommit(h, tmtime.Now()) diff --git a/light/rpc/client.go b/light/rpc/client.go index 54b0a6258..f1c21c994 100644 --- a/light/rpc/client.go +++ b/light/rpc/client.go @@ -458,16 +458,17 @@ func (c *Client) BlockResults(ctx context.Context, height *int64) (*coretypes.Re return nil, err } - // Build a Merkle tree of proto-encoded FinalizeBlock tx results and get a hash. - results := types.NewResults(res.TxsResults) - // Build a Merkle tree out of the slice. - rH := merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash()}) + rs, err := abci.MarshalTxResults(res.TxsResults) + if err != nil { + return nil, err + } + mh := merkle.HashFromByteSlices(append([][]byte{bbeBytes}, rs...)) // Verify block results. - if !bytes.Equal(rH, trustedBlock.LastResultsHash) { + if !bytes.Equal(mh, trustedBlock.LastResultsHash) { return nil, fmt.Errorf("last results %X does not match with trusted last results %X", - rH, trustedBlock.LastResultsHash) + mh, trustedBlock.LastResultsHash) } return res, nil diff --git a/node/node_test.go b/node/node_test.go index f5b978418..fcd633d71 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -336,7 +336,7 @@ func TestCreateProposalBlock(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _, err := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( ctx, height, state, commit, @@ -415,7 +415,7 @@ func TestMaxTxsProposalBlockSize(t *testing.T) { ) commit := types.NewCommit(height-1, 0, types.BlockID{}, nil) - block, _, err := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( ctx, height, state, commit, @@ -497,10 +497,16 @@ func TestMaxProposalBlockSize(t *testing.T) { }, } + // save the updated validator set for use by the block executor. + state.LastBlockHeight = math.MaxInt64 - 3 + state.LastHeightValidatorsChanged = math.MaxInt64 - 1 + state.NextValidators = state.Validators.Copy() + require.NoError(t, stateStore.Save(state)) + timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) // change state in order to produce the largest accepted header state.LastBlockID = blockID - state.LastBlockHeight = math.MaxInt64 - 1 + state.LastBlockHeight = math.MaxInt64 - 2 state.LastBlockTime = timestamp state.LastResultsHash = tmhash.Sum([]byte("last_results_hash")) state.AppHash = tmhash.Sum([]byte("app_hash")) @@ -530,7 +536,7 @@ func TestMaxProposalBlockSize(t *testing.T) { commit.Signatures = append(commit.Signatures, cs) } - block, partSet, err := blockExec.CreateProposalBlock( + block, err := blockExec.CreateProposalBlock( ctx, math.MaxInt64, state, commit, @@ -538,6 +544,8 @@ func TestMaxProposalBlockSize(t *testing.T) { nil, ) require.NoError(t, err) + partSet, err := block.MakePartSet(types.BlockPartSizeBytes) + require.NoError(t, err) // this ensures that the header is at max size block.Header.Time = timestamp diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 26f264958..c65e13f3e 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -322,7 +322,6 @@ message ResponsePrepareProposal { repeated ExecTxResult tx_results = 4; repeated ValidatorUpdate validator_updates = 5; tendermint.types.ConsensusParams consensus_param_updates = 6; - repeated bytes app_signed_updates = 7; } message ResponseProcessProposal { diff --git a/proto/tendermint/abci/types.proto.intermediate b/proto/tendermint/abci/types.proto.intermediate index b84f4c910..d710ed06f 100644 --- a/proto/tendermint/abci/types.proto.intermediate +++ b/proto/tendermint/abci/types.proto.intermediate @@ -8,9 +8,8 @@ import "tendermint/types/params.proto"; import "google/protobuf/timestamp.proto"; import "gogoproto/gogo.proto"; - // This file is a temporary workaround to enable development during the ABCI++ -// project. This file should be deleted and any references to it removed when +// project. This file should be deleted and any references to it removed when // the ongoing work on ABCI++ is completed. // // For the duration of ABCI++, this file should be able to build the `abci/types/types.pb.go` @@ -23,25 +22,25 @@ import "gogoproto/gogo.proto"; message Request { oneof value { - RequestEcho echo = 1; - RequestFlush flush = 2; - RequestInfo info = 3; - RequestInitChain init_chain = 4; - RequestQuery query = 5; - RequestBeginBlock begin_block = 6 [deprecated = true]; - RequestCheckTx check_tx = 7; - RequestDeliverTx deliver_tx = 8 [deprecated = true]; - RequestEndBlock end_block = 9 [deprecated = true]; - RequestCommit commit = 10; - RequestListSnapshots list_snapshots = 11; - RequestOfferSnapshot offer_snapshot = 12; - RequestLoadSnapshotChunk load_snapshot_chunk = 13; - RequestApplySnapshotChunk apply_snapshot_chunk = 14; - RequestPrepareProposal prepare_proposal = 15; - RequestProcessProposal process_proposal = 16; + RequestEcho echo = 1; + RequestFlush flush = 2; + RequestInfo info = 3; + RequestInitChain init_chain = 4; + RequestQuery query = 5; + RequestBeginBlock begin_block = 6 [deprecated = true]; + RequestCheckTx check_tx = 7; + RequestDeliverTx deliver_tx = 8 [deprecated = true]; + RequestEndBlock end_block = 9 [deprecated = true]; + RequestCommit commit = 10; + RequestListSnapshots list_snapshots = 11; + RequestOfferSnapshot offer_snapshot = 12; + RequestLoadSnapshotChunk load_snapshot_chunk = 13; + RequestApplySnapshotChunk apply_snapshot_chunk = 14; + RequestPrepareProposal prepare_proposal = 15; + RequestProcessProposal process_proposal = 16; RequestExtendVote extend_vote = 17; RequestVerifyVoteExtension verify_vote_extension = 18; - RequestFinalizeBlock finalize_block = 19; + RequestFinalizeBlock finalize_block = 19; } } @@ -135,18 +134,17 @@ message RequestVerifyVoteExtension { } 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 tendermint.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; } - message RequestProcessProposal { bytes hash = 1; tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; @@ -168,26 +166,26 @@ message RequestFinalizeBlock { message Response { oneof value { - ResponseException exception = 1; - ResponseEcho echo = 2; - ResponseFlush flush = 3; - ResponseInfo info = 4; - ResponseInitChain init_chain = 5; - ResponseQuery query = 6; - ResponseBeginBlock begin_block = 7 [deprecated = true]; - ResponseCheckTx check_tx = 8; - ResponseDeliverTx deliver_tx = 9 [deprecated = true]; - ResponseEndBlock end_block = 10 [deprecated = true]; - ResponseCommit commit = 11; - ResponseListSnapshots list_snapshots = 12; - ResponseOfferSnapshot offer_snapshot = 13; - ResponseLoadSnapshotChunk load_snapshot_chunk = 14; - ResponseApplySnapshotChunk apply_snapshot_chunk = 15; - ResponsePrepareProposal prepare_proposal = 16; - ResponseProcessProposal process_proposal = 17; + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseInitChain init_chain = 5; + ResponseQuery query = 6; + ResponseBeginBlock begin_block = 7 [deprecated = true]; + ResponseCheckTx check_tx = 8; + ResponseDeliverTx deliver_tx = 9 [deprecated = true]; + ResponseEndBlock end_block = 10 [deprecated = true]; + ResponseCommit commit = 11; + ResponseListSnapshots list_snapshots = 12; + ResponseOfferSnapshot offer_snapshot = 13; + ResponseLoadSnapshotChunk load_snapshot_chunk = 14; + ResponseApplySnapshotChunk apply_snapshot_chunk = 15; + ResponsePrepareProposal prepare_proposal = 16; + ResponseProcessProposal process_proposal = 17; ResponseExtendVote extend_vote = 18; ResponseVerifyVoteExtension verify_vote_extension = 19; - ResponseFinalizeBlock finalize_block = 20; + ResponseFinalizeBlock finalize_block = 20; } } @@ -330,7 +328,12 @@ message ResponseVerifyVoteExtension { } message ResponsePrepareProposal { - repeated bytes block_data = 1; + bool modified_tx = 1; + repeated TxRecord tx_records = 2; + bytes app_hash = 3; + repeated ExecTxResult tx_results = 4; + repeated ValidatorUpdate validator_updates = 5; + tendermint.types.ConsensusParams consensus_param_updates = 6; } message ResponseProcessProposal { @@ -359,6 +362,11 @@ message CommitInfo { 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. @@ -384,7 +392,7 @@ message ExecTxResult { string info = 4; // nondeterministic int64 gas_wanted = 5; int64 gas_used = 6; - repeated Event events = 7 + repeated Event events = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic string codespace = 8; } @@ -393,12 +401,25 @@ message ExecTxResult { // // One usage is indexing transaction results. message TxResult { - int64 height = 1; - uint32 index = 2; - bytes tx = 3; + int64 height = 1; + uint32 index = 2; + bytes tx = 3; ExecTxResult 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 @@ -423,6 +444,12 @@ message VoteInfo { 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; +} + enum EvidenceType { UNKNOWN = 0; DUPLICATE_VOTE = 1; diff --git a/spec/abci++/abci++_methods_002_draft.md b/spec/abci++/abci++_methods_002_draft.md index 316c16dbc..834c161bd 100644 --- a/spec/abci++/abci++_methods_002_draft.md +++ b/spec/abci++/abci++_methods_002_draft.md @@ -304,7 +304,6 @@ title: Methods | tx_results | repeated [ExecTxResult](#txresult) | List of structures containing the data resulting from executing the transactions | 4 | | validator_updates | repeated [ValidatorUpdate](#validatorupdate) | Changes to validator set (set voting power to 0 to remove). | 5 | | consensus_param_updates | [ConsensusParams](#consensusparams) | Changes to consensus-critical gas, size, and other parameters. | 6 | - | app_signed_updates | repeated bytes | Optional changes to the *app_signed* part of vote extensions. | 7 | * **Usage**: * The first five parameters of `RequestPrepareProposal` are the same as `RequestProcessProposal` @@ -321,10 +320,6 @@ title: Methods > Consider the following example: the Application transforms a client-submitted transaction `t1` into a second transaction `t2`, i.e., the Application asks Tendermint to remove `t1` and add `t2` to the mempool. If a client wants to eventually check what happened to `t1`, it will discover that `t_1` is not in the mempool or in a committed block, getting the wrong idea that `t_1` did not make it into a block. Note that `t_2` _will be_ in a committed block, but unless the Application tracks this information, no component will be aware of it. Thus, if the Application wants traceability, it is its responsability to support it. For instance, the Application could attach to a transformed transaction a list with the hashes of the transactions it derives from. * If the Application modifies the set of transactions, the modified transactions MUST NOT exceed the configured maximum size `RequestPrepareProposal.max_tx_bytes`. * If the Application does not modify the preliminary set of transactions `txs`, then it sets `ResponsePrepareProposal.modified_tx` to false. In this case, Tendermint will ignore the contents of `ResponsePrepareProposal.tx_records`. - * If the Application modifies the *app_signed* part of vote extensions via `ResponsePrepareProposal.app_signed_updates`, - the new total size of those extensions cannot exceed their initial size. - * The Application may choose to not modify the *app_signed* part of vote extensions by leaving parameter - `ResponsePrepareProposal.app_signed_updates` empty. * In same-block execution mode, the Application must provide values for `ResponsePrepareProposal.app_hash`, `ResponsePrepareProposal.tx_results`, `ResponsePrepareProposal.validator_updates`, and `ResponsePrepareProposal.consensus_param_updates`, as a result of fully executing the block. diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 098da250e..5739f06e5 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -305,7 +305,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} } // ProcessProposal implements part of the Application interface. diff --git a/types/results.go b/types/results.go deleted file mode 100644 index 511364000..000000000 --- a/types/results.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/crypto/merkle" -) - -// ABCIResults wraps the deliver tx results to return a proof. -type ABCIResults []*abci.ExecTxResult - -// NewResults strips non-deterministic fields from ResponseDeliverTx responses -// and returns ABCIResults. -func NewResults(responses []*abci.ExecTxResult) ABCIResults { - res := make(ABCIResults, len(responses)) - for i, d := range responses { - res[i] = deterministicExecTxResult(d) - } - return res -} - -// Hash returns a merkle hash of all results. -func (a ABCIResults) Hash() []byte { - return merkle.HashFromByteSlices(a.toByteSlices()) -} - -// ProveResult returns a merkle proof of one result from the set -func (a ABCIResults) ProveResult(i int) merkle.Proof { - _, proofs := merkle.ProofsFromByteSlices(a.toByteSlices()) - return *proofs[i] -} - -func (a ABCIResults) toByteSlices() [][]byte { - l := len(a) - bzs := make([][]byte, l) - for i := 0; i < l; i++ { - bz, err := a[i].Marshal() - if err != nil { - panic(err) - } - bzs[i] = bz - } - return bzs -} - -// deterministicExecTxResult strips non-deterministic fields from -// ResponseDeliverTx and returns another ResponseDeliverTx. -func deterministicExecTxResult(response *abci.ExecTxResult) *abci.ExecTxResult { - return &abci.ExecTxResult{ - Code: response.Code, - Data: response.Data, - GasWanted: response.GasWanted, - GasUsed: response.GasUsed, - } -} diff --git a/types/results_test.go b/types/results_test.go deleted file mode 100644 index da7eebed0..000000000 --- a/types/results_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package types - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" -) - -func TestABCIResults(t *testing.T) { - a := &abci.ExecTxResult{Code: 0, Data: nil} - b := &abci.ExecTxResult{Code: 0, Data: []byte{}} - c := &abci.ExecTxResult{Code: 0, Data: []byte("one")} - d := &abci.ExecTxResult{Code: 14, Data: nil} - e := &abci.ExecTxResult{Code: 14, Data: []byte("foo")} - f := &abci.ExecTxResult{Code: 14, Data: []byte("bar")} - - // Nil and []byte{} should produce the same bytes - bzA, err := a.Marshal() - require.NoError(t, err) - bzB, err := b.Marshal() - require.NoError(t, err) - - require.Equal(t, bzA, bzB) - - // a and b should be the same, don't go in results. - results := ABCIResults{a, c, d, e, f} - - // Make sure each result serializes differently - last := []byte{} - assert.Equal(t, last, bzA) // first one is empty - for i, res := range results[1:] { - bz, err := res.Marshal() - require.NoError(t, err) - - assert.NotEqual(t, last, bz, "%d", i) - last = bz - } - - // Make sure that we can get a root hash from results and verify proofs. - root := results.Hash() - assert.NotEmpty(t, root) - - for i, res := range results { - bz, err := res.Marshal() - require.NoError(t, err) - - proof := results.ProveResult(i) - valid := proof.Verify(root, bz) - assert.NoError(t, valid, "%d", i) - } -} diff --git a/types/tx.go b/types/tx.go index 746252238..2dd7d3a51 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" @@ -32,13 +34,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 @@ -61,16 +58,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, @@ -79,11 +69,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++ { @@ -92,14 +94,182 @@ func (txs Txs) ToSliceOfBytes() [][]byte { return txBzs } -// ToTxs converts a raw slice of byte slices into a Txs type. -// TODO This function is to disappear when TxRecord is introduced -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 e2f12772a..d8737e9f0 100644 --- a/types/tx_test.go +++ b/types/tx_test.go @@ -2,12 +2,13 @@ package types import ( "bytes" - mrand "math/rand" + "math/rand" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ctest "github.com/tendermint/tendermint/internal/libs/test" tmrand "github.com/tendermint/tendermint/libs/rand" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -21,11 +22,6 @@ func makeTxs(cnt, size int) Txs { return txs } -func randInt(low, high int) int { - off := mrand.Int() % (high - low) - return low + off -} - func TestTxIndex(t *testing.T) { for i := 0; i < 20; i++ { txs := makeTxs(15, 60) @@ -52,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 @@ -150,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 bb675e110..438d089b3 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 }