diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index aba94092b..eba36075e 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -65,6 +65,10 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi - [crypto] [\#4721](https://github.com/tendermint/tendermint/pull/4721) Remove `SimpleHashFromMap()` and `SimpleProofsFromMap()` (@erikgrinaker) - [types] \#4798 Simplify `VerifyCommitTrusting` func + remove extra validation (@melekes) - [libs] \#4831 Remove `Bech32` pkg from Tendermint. This pkg now lives in the [cosmos-sdk](https://github.com/cosmos/cosmos-sdk/tree/4173ea5ebad906dd9b45325bed69b9c655504867/types/bech32) + - [rpc/client] \#4947 `Validators`, `TxSearch` `page`/`per_page` params become pointers (@melekes) + `UnconfirmedTxs` `limit` param is a pointer + - [types] \#4845 Remove `ABCIResult` + - Blockchain Protocol - [types] [\#4792](https://github.com/tendermint/tendermint/pull/4792) Sort validators by voting power to enable faster commit verification (@melekes) @@ -72,8 +76,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi Add `max_num` to consensus evidence parameters (default: 50 items). - [mempool] \#4940 Migrate mempool from amino binary encoding to Protobuf - [statesync] \#4943 Migrate statesync reactor from amino binary encoding to Protobuf - - [rpc/client] \#4947 `Validators`, `TxSearch` `page`/`per_page` params become pointers (@melekes) - `UnconfirmedTxs` `limit` param is a pointer + - [state] \#4845 Include BeginBlock#Events, EndBlock#Events, DeliverTx#Events, GasWanted and GasUsed into `LastResultsHash` (@melekes) ### FEATURES: diff --git a/UPGRADING.md b/UPGRADING.md index 72276edda..84872e151 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -3,17 +3,33 @@ This guide provides steps to be followed when you upgrade your applications to a newer version of Tendermint Core. -## Unreleased +## v0.34.0 - +This release is not compatible with previous blockchains due to switching from +amino to proto3 encoding and breaking changes to the header. + +### Blockchain Protocol + +- `Header#LastResultsHash`, which previously was the root hash of a Merkle tree + built from `ResponseDeliverTx(Code, Data)` responses, became the root hash of + a Merkle tree built from: + - `BeginBlock#Events`; + - root hash of a Merkle tree built from `ResponseDeliverTx(Code, Data, GasWanted, GasUsed, Events)` responses; + - `BeginBlock#Events`. ### Events -- `KV.Pair` has been replaced with `abci.EventAttribute`. This allows applications to indicate if a msg should be indexed at runtime. Previously this was only possible if the node operator decided to index specific or all messages on startup of the node, now the application can indicate which msgs should be indexed. +- `KV.Pair` has been replaced with `abci.EventAttribute`. This allows + applications to indicate if a msg should be indexed at runtime. Previously + this was only possible if the node operator decided to index specific or all + messages on startup of the node, now the application can indicate which msgs + should be indexed. ### Crypto -- `Multsig` & `PubKeyMultisigThreshold` have been moved to the [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk). (https://github.com/cosmos/cosmos-sdk/blob/master/crypto/types/multisig/multisignature.go) +- `Multsig` & `PubKeyMultisigThreshold` have been moved to the + [Cosmos-SDK](https://github.com/cosmos/cosmos-sdk). + (https://github.com/cosmos/cosmos-sdk/blob/master/crypto/types/multisig/multisignature.go) ## v0.33.4 diff --git a/proto/types/canonical.pb.go b/proto/types/canonical.pb.go index 6740ba3d7..6cf57e159 100644 --- a/proto/types/canonical.pb.go +++ b/proto/types/canonical.pb.go @@ -133,8 +133,8 @@ func (m *CanonicalPartSetHeader) GetTotal() uint32 { type CanonicalProposal struct { Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.proto.types.SignedMsgType" json:"type,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - Round int64 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty" binary:" fixed64 "` + Round int64 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty" binary:" fixed64 "` POLRound int64 `protobuf:"varint,4,opt,name=pol_round,json=polRound,proto3" json:"pol_round,omitempty"` BlockID CanonicalBlockID `protobuf:"bytes,5,opt,name=block_id,json=blockId,proto3" json:"block_id"` Timestamp time.Time `protobuf:"bytes,6,opt,name=timestamp,proto3,stdtime" json:"timestamp"` @@ -225,8 +225,8 @@ func (m *CanonicalProposal) GetChainID() string { type CanonicalVote struct { Type SignedMsgType `protobuf:"varint,1,opt,name=type,proto3,enum=tendermint.proto.types.SignedMsgType" json:"type,omitempty"` - Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - Round int64 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty"` + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty" binary:" fixed64 "` + Round int64 `protobuf:"varint,3,opt,name=round,proto3" json:"round,omitempty" binary:" fixed64 "` BlockID CanonicalBlockID `protobuf:"bytes,5,opt,name=block_id,json=blockId,proto3" json:"block_id"` Timestamp time.Time `protobuf:"bytes,6,opt,name=timestamp,proto3,stdtime" json:"timestamp"` ChainID string `protobuf:"bytes,7,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` @@ -317,38 +317,39 @@ func init() { func init() { proto.RegisterFile("proto/types/canonical.proto", fileDescriptor_3f9b1d584b46f180) } var fileDescriptor_3f9b1d584b46f180 = []byte{ - // 482 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x53, 0x4f, 0x8b, 0xd3, 0x40, - 0x14, 0x6f, 0xba, 0xdd, 0x36, 0x9d, 0x76, 0xfd, 0x33, 0x48, 0x0d, 0x15, 0x92, 0x52, 0x70, 0xa9, - 0x20, 0x09, 0xac, 0x27, 0xaf, 0xb3, 0x22, 0x16, 0x14, 0x97, 0xd9, 0xa2, 0xe0, 0xa5, 0x4c, 0x93, - 0x31, 0x19, 0x4c, 0x33, 0x21, 0x99, 0x1e, 0x7a, 0xf2, 0x2b, 0xec, 0xe7, 0xf1, 0x13, 0xec, 0x71, - 0x8f, 0x9e, 0xaa, 0xa4, 0x27, 0xbf, 0x85, 0xcc, 0x9b, 0xfe, 0x3b, 0x54, 0xbc, 0x09, 0x5e, 0xc2, - 0x7b, 0xbf, 0xf7, 0xde, 0xef, 0xfd, 0xf2, 0x7b, 0x0c, 0x7a, 0x92, 0x17, 0x52, 0xc9, 0x40, 0x2d, - 0x73, 0x5e, 0x06, 0x21, 0xcb, 0x64, 0x26, 0x42, 0x96, 0xfa, 0x80, 0xe2, 0x9e, 0xe2, 0x59, 0xc4, - 0x8b, 0xb9, 0xc8, 0x94, 0x41, 0x7c, 0xe8, 0xeb, 0x9f, 0xab, 0x44, 0x14, 0xd1, 0x34, 0x67, 0x85, - 0x5a, 0x06, 0x86, 0x20, 0x96, 0xb1, 0xdc, 0x47, 0xa6, 0xbb, 0xff, 0xf8, 0x90, 0x1c, 0xbe, 0x9b, - 0x82, 0x17, 0x4b, 0x19, 0xa7, 0xdc, 0xcc, 0xce, 0x16, 0x9f, 0x03, 0x25, 0xe6, 0xbc, 0x54, 0x6c, - 0x9e, 0x9b, 0x86, 0xe1, 0x57, 0xf4, 0xe0, 0x72, 0x2b, 0x86, 0xa4, 0x32, 0xfc, 0x32, 0x7e, 0x85, - 0x31, 0x6a, 0x24, 0xac, 0x4c, 0x1c, 0x6b, 0x60, 0x8d, 0xba, 0x14, 0x62, 0xfc, 0x11, 0x75, 0xb5, - 0x8a, 0x72, 0x9a, 0x70, 0x16, 0xf1, 0xc2, 0xa9, 0x0f, 0xac, 0x51, 0xe7, 0xc2, 0xf7, 0x8f, 0x0b, - 0xf7, 0x77, 0x9c, 0x57, 0xac, 0x50, 0xd7, 0x5c, 0xbd, 0x81, 0x29, 0xd2, 0xb8, 0x5d, 0x79, 0x35, - 0xda, 0x01, 0x26, 0x03, 0x0d, 0x09, 0xea, 0x1d, 0x6f, 0x3e, 0x2a, 0xe3, 0x11, 0x3a, 0x55, 0x52, - 0xb1, 0x14, 0xf6, 0x9f, 0x51, 0x93, 0x0c, 0x7f, 0xd5, 0xd1, 0xc3, 0x3d, 0x49, 0x21, 0x73, 0x59, - 0xb2, 0x14, 0xbf, 0x44, 0x0d, 0x2d, 0x06, 0xe6, 0xef, 0x5d, 0x3c, 0xfd, 0x93, 0xd4, 0x6b, 0x11, - 0x67, 0x3c, 0x7a, 0x57, 0xc6, 0x93, 0x65, 0xce, 0x29, 0x8c, 0xe0, 0x1e, 0x6a, 0x26, 0x5c, 0xc4, - 0x89, 0x82, 0x3d, 0x27, 0x74, 0x93, 0xe9, 0xf5, 0x85, 0x5c, 0x64, 0x91, 0x73, 0x02, 0xb0, 0x49, - 0xf0, 0x33, 0xd4, 0xce, 0x65, 0x3a, 0x35, 0x95, 0x86, 0xae, 0x90, 0x6e, 0xb5, 0xf2, 0xec, 0xab, - 0xf7, 0x6f, 0xa9, 0xc6, 0xa8, 0x9d, 0xcb, 0x14, 0x22, 0x3c, 0x41, 0xf6, 0x4c, 0xbb, 0x3c, 0x15, - 0x91, 0x73, 0x0a, 0x16, 0x8e, 0xfe, 0x6a, 0xe1, 0xe6, 0x2c, 0xe4, 0xbe, 0x36, 0xaf, 0x5a, 0x79, - 0xad, 0x0d, 0x40, 0x5b, 0x40, 0x35, 0x8e, 0x30, 0x41, 0xed, 0xdd, 0x5d, 0x9d, 0x26, 0xd0, 0xf6, - 0x7d, 0x73, 0x79, 0x7f, 0x7b, 0x79, 0x7f, 0xb2, 0xed, 0x20, 0xb6, 0x26, 0xba, 0xf9, 0xe1, 0x59, - 0x74, 0x3f, 0x86, 0xcf, 0x91, 0x1d, 0x26, 0x4c, 0x64, 0x5a, 0x59, 0x6b, 0x60, 0x8d, 0xda, 0xa4, - 0xa3, 0x77, 0x5d, 0x6a, 0x4c, 0xef, 0x82, 0xe2, 0x38, 0x1a, 0x7e, 0xab, 0xa3, 0xb3, 0x9d, 0xb4, - 0x0f, 0x52, 0xf1, 0x7f, 0xe7, 0xf3, 0x7f, 0x6f, 0x1e, 0x79, 0x7d, 0x5b, 0xb9, 0xd6, 0x5d, 0xe5, - 0x5a, 0x3f, 0x2b, 0xd7, 0xba, 0x59, 0xbb, 0xb5, 0xbb, 0xb5, 0x5b, 0xfb, 0xbe, 0x76, 0x6b, 0x9f, - 0x9e, 0xc7, 0x42, 0x25, 0x8b, 0x99, 0x1f, 0xca, 0x79, 0xb0, 0xff, 0xa7, 0xc3, 0xf0, 0xe0, 0x89, - 0xcf, 0x9a, 0x90, 0xbc, 0xf8, 0x1d, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x73, 0xb0, 0x8c, 0x55, 0x04, - 0x00, 0x00, + // 506 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x54, 0x4d, 0x8b, 0xd3, 0x40, + 0x18, 0x6e, 0xb6, 0x5f, 0xe9, 0xb4, 0xeb, 0xc7, 0x20, 0x35, 0x54, 0x48, 0x42, 0xc0, 0xa5, 0xc2, + 0x32, 0x81, 0x55, 0x04, 0x3d, 0x66, 0x45, 0x2c, 0x28, 0x2e, 0xd9, 0xa2, 0xe0, 0xa5, 0x4c, 0x92, + 0xd9, 0x64, 0x30, 0xcd, 0x84, 0x64, 0x0a, 0xf6, 0xe4, 0x5f, 0xd8, 0xab, 0xff, 0x68, 0x8f, 0x3d, + 0x7a, 0xaa, 0x92, 0xde, 0x3c, 0xfa, 0x0b, 0x64, 0x66, 0xfa, 0x75, 0xa8, 0x7a, 0xd5, 0x4b, 0x79, + 0xe7, 0x99, 0xe7, 0x79, 0xde, 0xa7, 0xef, 0xbc, 0x04, 0x3c, 0xc8, 0x0b, 0xc6, 0x99, 0xcb, 0xe7, + 0x39, 0x29, 0xdd, 0x10, 0x67, 0x2c, 0xa3, 0x21, 0x4e, 0x91, 0x44, 0x61, 0x9f, 0x93, 0x2c, 0x22, + 0xc5, 0x94, 0x66, 0x5c, 0x21, 0x48, 0xf2, 0x06, 0x27, 0x3c, 0xa1, 0x45, 0x34, 0xc9, 0x71, 0xc1, + 0xe7, 0xae, 0x32, 0x88, 0x59, 0xcc, 0x76, 0x95, 0x62, 0x0f, 0xee, 0xef, 0x9b, 0xcb, 0xdf, 0xf5, + 0x85, 0x15, 0x33, 0x16, 0xa7, 0x44, 0x69, 0x83, 0xd9, 0x95, 0xcb, 0xe9, 0x94, 0x94, 0x1c, 0x4f, + 0x73, 0x45, 0x70, 0x3e, 0x83, 0x3b, 0xe7, 0x9b, 0x30, 0x5e, 0xca, 0xc2, 0x8f, 0xa3, 0x17, 0x10, + 0x82, 0x46, 0x82, 0xcb, 0xc4, 0xd0, 0x6c, 0x6d, 0xd8, 0xf3, 0x65, 0x0d, 0xdf, 0x83, 0x9e, 0x48, + 0x51, 0x4e, 0x12, 0x82, 0x23, 0x52, 0x18, 0x47, 0xb6, 0x36, 0xec, 0x9e, 0x21, 0x74, 0x38, 0x38, + 0xda, 0x7a, 0x5e, 0xe0, 0x82, 0x5f, 0x12, 0xfe, 0x4a, 0xaa, 0xbc, 0xc6, 0xcd, 0xd2, 0xaa, 0xf9, + 0x5d, 0xe9, 0xa4, 0x20, 0xc7, 0x03, 0xfd, 0xc3, 0xe4, 0x83, 0x31, 0xee, 0x81, 0x26, 0x67, 0x1c, + 0xa7, 0xb2, 0xff, 0xb1, 0xaf, 0x0e, 0xce, 0x97, 0x3a, 0xb8, 0xbb, 0x33, 0x29, 0x58, 0xce, 0x4a, + 0x9c, 0xc2, 0x67, 0xa0, 0x21, 0xc2, 0x48, 0xfd, 0xad, 0xb3, 0x87, 0xbf, 0x8b, 0x7a, 0x49, 0xe3, + 0x8c, 0x44, 0x6f, 0xca, 0x78, 0x3c, 0xcf, 0x89, 0x2f, 0x25, 0x10, 0x81, 0x56, 0x42, 0x68, 0x9c, + 0x70, 0xd9, 0xa7, 0xee, 0xf5, 0x7f, 0x2e, 0x2d, 0x18, 0xd0, 0x0c, 0x17, 0xf3, 0xe7, 0x8e, 0x7d, + 0x45, 0x3f, 0x91, 0xe8, 0xe9, 0x13, 0xdb, 0xf1, 0xd7, 0x2c, 0x78, 0x0a, 0x9a, 0x05, 0x9b, 0x65, + 0x91, 0x51, 0xff, 0x23, 0x5d, 0x91, 0xe0, 0x23, 0xd0, 0xc9, 0x59, 0x3a, 0x51, 0x8a, 0x86, 0x54, + 0xf4, 0xaa, 0xa5, 0xa5, 0x5f, 0xbc, 0x7d, 0xed, 0x0b, 0xcc, 0xd7, 0x73, 0x96, 0xca, 0x0a, 0x8e, + 0x81, 0x1e, 0x88, 0x57, 0x99, 0xd0, 0xc8, 0x68, 0xca, 0x91, 0x0f, 0xff, 0x3a, 0xf2, 0xf5, 0x33, + 0x7a, 0xb7, 0xc5, 0xb0, 0xab, 0xa5, 0xd5, 0x5e, 0x03, 0x7e, 0x5b, 0x5a, 0x8d, 0x22, 0xe8, 0x81, + 0xce, 0x76, 0x0f, 0x8c, 0x96, 0xb4, 0x1d, 0x20, 0xb5, 0x29, 0x68, 0xb3, 0x29, 0x68, 0xbc, 0x61, + 0x78, 0xba, 0x30, 0xba, 0xfe, 0x66, 0x69, 0xfe, 0x4e, 0x06, 0x4f, 0x80, 0x1e, 0x26, 0x98, 0x66, + 0x22, 0x59, 0xdb, 0xd6, 0x86, 0x1d, 0xaf, 0x2b, 0x7a, 0x9d, 0x0b, 0x4c, 0xf4, 0x92, 0x97, 0xa3, + 0xc8, 0xf9, 0x71, 0x04, 0x8e, 0xb7, 0xd1, 0xde, 0x31, 0x4e, 0xfe, 0xdd, 0x77, 0xf9, 0xef, 0x87, + 0xed, 0xbd, 0xbc, 0xa9, 0x4c, 0x6d, 0x51, 0x99, 0xda, 0xf7, 0xca, 0xd4, 0xae, 0x57, 0x66, 0x6d, + 0xb1, 0x32, 0x6b, 0x5f, 0x57, 0x66, 0xed, 0xc3, 0x69, 0x4c, 0x79, 0x32, 0x0b, 0x50, 0xc8, 0xa6, + 0xee, 0xee, 0x3f, 0xed, 0x97, 0x7b, 0x9f, 0x90, 0xa0, 0x25, 0x0f, 0x8f, 0x7f, 0x05, 0x00, 0x00, + 0xff, 0xff, 0x79, 0xf8, 0x2b, 0x08, 0xb5, 0x04, 0x00, 0x00, } func (m *CanonicalBlockID) Marshal() (dAtA []byte, err error) { diff --git a/proto/types/canonical.proto b/proto/types/canonical.proto index 431461bbc..ae85bdec2 100644 --- a/proto/types/canonical.proto +++ b/proto/types/canonical.proto @@ -19,8 +19,8 @@ message CanonicalPartSetHeader { message CanonicalProposal { SignedMsgType type = 1; // type alias for byte - int64 height = 2; - int64 round = 3; + int64 height = 2 [(gogoproto.moretags) = "binary:\" fixed64 \""]; + int64 round = 3 [(gogoproto.moretags) = "binary:\" fixed64 \""]; int64 pol_round = 4 [(gogoproto.customname) = "POLRound"]; CanonicalBlockID block_id = 5 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; google.protobuf.Timestamp timestamp = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; @@ -29,8 +29,8 @@ message CanonicalProposal { message CanonicalVote { SignedMsgType type = 1; // type alias for byte - int64 height = 2; - int64 round = 3; + int64 height = 2 [(gogoproto.moretags) = "binary:\" fixed64 \""]; + int64 round = 3 [(gogoproto.moretags) = "binary:\" fixed64 \""]; CanonicalBlockID block_id = 5 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; google.protobuf.Timestamp timestamp = 6 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; string chain_id = 7 [(gogoproto.customname) = "ChainID"]; diff --git a/proto/types/validator.pb.go b/proto/types/validator.pb.go index b39aee6bd..8a3dac774 100644 --- a/proto/types/validator.pb.go +++ b/proto/types/validator.pb.go @@ -162,9 +162,7 @@ func init() { } func init() { proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) } -func init() { - golang_proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) -} +func init() { golang_proto.RegisterFile("proto/types/validator.proto", fileDescriptor_2e7c6b38c20e5406) } var fileDescriptor_2e7c6b38c20e5406 = []byte{ // 358 bytes of a gzipped FileDescriptorProto diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh old mode 100644 new mode 100755 diff --git a/state/execution.go b/state/execution.go index 739855675..36e901202 100644 --- a/state/execution.go +++ b/state/execution.go @@ -452,7 +452,7 @@ func updateState( LastHeightValidatorsChanged: lastHeightValsChanged, ConsensusParams: nextParams, LastHeightConsensusParamsChanged: lastHeightParamsChanged, - LastResultsHash: ABCIResponsesResultsHash(*abciResponses), + LastResultsHash: ABCIResponsesResultsHash(abciResponses), AppHash: nil, }, nil } diff --git a/state/helpers_test.go b/state/helpers_test.go index bc7ce603e..9c3bfc88c 100644 --- a/state/helpers_test.go +++ b/state/helpers_test.go @@ -172,7 +172,8 @@ func makeHeaderPartsResponsesValPubKeyChange( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } // If the pubkey is new, remove the old and add the new. _, val := state.NextValidators.GetByIndex(0) @@ -195,7 +196,8 @@ func makeHeaderPartsResponsesValPowerChange( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } // If the pubkey is new, remove the old and add the new. @@ -218,7 +220,8 @@ func makeHeaderPartsResponsesParams( block := makeBlock(state, state.LastBlockHeight+1) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ConsensusParamUpdates: types.TM2PB.ConsensusParams(¶ms)}, } return block.Header, types.BlockID{Hash: block.Hash(), PartsHeader: types.PartSetHeader{}}, abciResponses } diff --git a/state/state_test.go b/state/state_test.go index 4cae6f97b..3db2f37ed 100644 --- a/state/state_test.go +++ b/state/state_test.go @@ -124,7 +124,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { // Height is implied to equal index+2, // as block 1 is created from genesis. added []*abci.ResponseDeliverTx - expected types.ABCIResults + expected []*abci.ResponseDeliverTx }{ 0: { nil, @@ -134,7 +134,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { []*abci.ResponseDeliverTx{ {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, }, - types.ABCIResults{ + []*abci.ResponseDeliverTx{ {Code: 32, Data: []byte("Hello")}, }}, 2: { @@ -148,9 +148,12 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { }, }, }, - types.ABCIResults{ + []*abci.ResponseDeliverTx{ {Code: 383, Data: nil}, - {Code: 0, Data: []byte("Gotcha!")}, + {Code: 0, Data: []byte("Gotcha!"), Events: []abci.Event{ + {Type: "type1", Attributes: []abci.EventAttribute{{Key: []byte("a"), Value: []byte("1")}}}, + {Type: "type2", Attributes: []abci.EventAttribute{{Key: []byte("build"), Value: []byte("stuff")}}}, + }}, }}, 3: { nil, @@ -173,6 +176,7 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { for i, tc := range cases { h := int64(i + 1) // last block height, one below what we save responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, DeliverTxs: tc.added, EndBlock: &abci.ResponseEndBlock{}, } @@ -183,8 +187,15 @@ func TestABCIResponsesSaveLoad2(t *testing.T) { for i, tc := range cases { h := int64(i + 1) res, err := sm.LoadABCIResponses(stateDB, h) - assert.NoError(err, "%d", i) - assert.Equal(tc.expected.Hash(), sm.ABCIResponsesResultsHash(*res), "%d", i) + if assert.NoError(err, "%d", i) { + t.Log(res) + responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, + DeliverTxs: tc.expected, + EndBlock: &abci.ResponseEndBlock{}, + } + assert.Equal(sm.ABCIResponsesResultsHash(responses), sm.ABCIResponsesResultsHash(res), "%d", i) + } } } @@ -420,7 +431,8 @@ func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { block := makeBlock(state, state.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -534,7 +546,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -636,7 +649,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { // -> proposers should alternate: oldState := updatedState3 abciResponses = &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -651,7 +665,8 @@ func TestProposerPriorityProposerAlternates(t *testing.T) { for i := 0; i < 1000; i++ { // no validator updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -708,7 +723,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 10; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -739,7 +755,8 @@ func TestLargeGenesisValidator(t *testing.T) { validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) assert.NoError(t, err) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, } block := makeBlock(oldState, oldState.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -750,7 +767,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 200; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -785,7 +803,8 @@ func TestLargeGenesisValidator(t *testing.T) { assert.NoError(t, err) abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, } block := makeBlock(oldState, oldState.LastBlockHeight+1) blockID := types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -799,7 +818,8 @@ func TestLargeGenesisValidator(t *testing.T) { require.NoError(t, err) removeGenesisVal := abci.ValidatorUpdate{PubKey: gp, Power: 0} abciResponses = &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, } block = makeBlock(oldState, oldState.LastBlockHeight+1) blockID = types.BlockID{Hash: block.Hash(), PartsHeader: block.MakePartSet(testPartSize).Header()} @@ -817,7 +837,8 @@ func TestLargeGenesisValidator(t *testing.T) { isProposerUnchanged := true for isProposerUnchanged { abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) @@ -840,7 +861,8 @@ func TestLargeGenesisValidator(t *testing.T) { for i := 0; i < 100; i++ { // no updates: abciResponses := &tmstate.ABCIResponses{ - EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, + BeginBlock: &abci.ResponseBeginBlock{}, + EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, } validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) require.NoError(t, err) diff --git a/state/store.go b/state/store.go index c51393a7a..16517317b 100644 --- a/state/store.go +++ b/state/store.go @@ -7,6 +7,7 @@ import ( dbm "github.com/tendermint/tm-db" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/merkle" tmmath "github.com/tendermint/tendermint/libs/math" tmos "github.com/tendermint/tendermint/libs/os" tmstate "github.com/tendermint/tendermint/proto/state" @@ -138,8 +139,6 @@ func BootstrapState(db dbm.DB, state State) error { return db.SetSync(stateKey, state.Bytes()) } -//------------------------------------------------------------------------ - // PruneStates deletes states between the given heights (including from, excluding to). It is not // guaranteed to delete all states, since the last checkpointed state and states being pointed to by // e.g. `LastHeightChanged` must remain. The state at to must also exist. @@ -253,15 +252,44 @@ func PruneStates(db dbm.DB, from int64, to int64) error { return nil } -// ABCIResponsesResultsHash returns the merkle hash of the deliverTxs within ABCIResponses -func ABCIResponsesResultsHash(ar tmstate.ABCIResponses) []byte { +//------------------------------------------------------------------------ + +// ABCIResponsesResultsHash returns the root hash of a Merkle tree with 3 leafs: +// 1) proto encoded ResponseBeginBlock.Events +// 2) root hash of a Merkle tree of ResponseDeliverTx responses (see ABCIResults.Hash) +// 3) proto encoded ResponseEndBlock.Events +// +// See merkle.SimpleHashFromByteSlices +func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte { + // proto-encode BeginBlock events. + bbeBytes, err := proto.Marshal(&abci.ResponseBeginBlock{ + Events: ar.BeginBlock.Events, + }) + if err != nil { + panic(err) + } + + // Build a Merkle tree of proto-encoded DeliverTx results and get a hash. results := types.NewResults(ar.DeliverTxs) - return results.Hash() + + // proto-encode EndBlock events. + ebeBytes, err := proto.Marshal(&abci.ResponseEndBlock{ + Events: ar.EndBlock.Events, + }) + if err != nil { + panic(err) + } + + // Build a Merkle tree out of the above 3 binary slices. + return merkle.HashFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes}) } -// LoadABCIResponses loads the ABCIResponses for the given height from the database. -// This is useful for recovering from crashes where we called app.Commit and before we called -// s.Save(). It can also be used to produce Merkle proofs of the result of txs. +// LoadABCIResponses loads the ABCIResponses for the given height from the +// database. If not found, ErrNoABCIResponsesForHeight is returned. +// +// This is useful for recovering from crashes where we called app.Commit and +// before we called s.Save(). It can also be used to produce Merkle proofs of +// the result of txs. func LoadABCIResponses(db dbm.DB, height int64) (*tmstate.ABCIResponses, error) { buf, err := db.Get(calcABCIResponsesKey(height)) if err != nil { diff --git a/state/store_test.go b/state/store_test.go index 2d8e0067b..1086220c7 100644 --- a/state/store_test.go +++ b/state/store_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -14,6 +15,7 @@ import ( cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/crypto/merkle" tmrand "github.com/tendermint/tendermint/libs/rand" tmstate "github.com/tendermint/tendermint/proto/state" tmproto "github.com/tendermint/tendermint/proto/types" @@ -187,6 +189,27 @@ func TestPruneStates(t *testing.T) { } } +func TestABCIResponsesResultsHash(t *testing.T) { + responses := &tmstate.ABCIResponses{ + BeginBlock: &abci.ResponseBeginBlock{}, + DeliverTxs: []*abci.ResponseDeliverTx{ + {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, + }, + EndBlock: &abci.ResponseEndBlock{}, + } + + root := sm.ABCIResponsesResultsHash(responses) + + bbeBytes, _ := proto.Marshal(responses.BeginBlock) + results := types.NewResults(responses.DeliverTxs) + ebeBytes, _ := proto.Marshal(responses.EndBlock) + + root2, proofs := merkle.ProofsFromByteSlices([][]byte{bbeBytes, results.Hash(), ebeBytes}) + + assert.Equal(t, root2, root) + assert.NoError(t, proofs[1].Verify(root, results.Hash())) +} + func sliceToMap(s []int64) map[int64]bool { m := make(map[int64]bool, len(s)) for _, i := range s { diff --git a/types/results.go b/types/results.go index 05937d550..0f41fab3c 100644 --- a/types/results.go +++ b/types/results.go @@ -3,57 +3,23 @@ package types import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/merkle" - "github.com/tendermint/tendermint/libs/bytes" ) -//----------------------------------------------------------------------------- +// ABCIResults wraps the deliver tx results to return a proof. +type ABCIResults []*abci.ResponseDeliverTx -// ABCIResult is the deterministic component of a ResponseDeliverTx. -// TODO: add tags and other fields -// https://github.com/tendermint/tendermint/issues/1007 -type ABCIResult struct { - Code uint32 `json:"code"` - Data bytes.HexBytes `json:"data"` -} - -// Bytes returns the amino encoded ABCIResult -func (a ABCIResult) Bytes() []byte { - return cdcEncode(a) -} - -// ABCIResults wraps the deliver tx results to return a proof -type ABCIResults []ABCIResult - -// NewResults creates ABCIResults from the list of ResponseDeliverTx. +// NewResults strips non-deterministic fields from ResponseDeliverTx responses +// and returns ABCIResults. func NewResults(responses []*abci.ResponseDeliverTx) ABCIResults { res := make(ABCIResults, len(responses)) for i, d := range responses { - res[i] = NewResultFromResponse(d) + res[i] = deterministicResponseDeliverTx(d) } return res } -// NewResultFromResponse creates ABCIResult from ResponseDeliverTx. -func NewResultFromResponse(response *abci.ResponseDeliverTx) ABCIResult { - return ABCIResult{ - Code: response.Code, - Data: response.Data, - } -} - -// Bytes serializes the ABCIResponse using amino -func (a ABCIResults) Bytes() []byte { - bz, err := cdc.MarshalBinaryLengthPrefixed(a) - if err != nil { - panic(err) - } - return bz -} - -// Hash returns a merkle hash of all results +// Hash returns a merkle hash of all results. func (a ABCIResults) Hash() []byte { - // NOTE: we copy the impl of the merkle tree for txs - - // we should be consistent and either do it for both or not. return merkle.HashFromByteSlices(a.toByteSlices()) } @@ -67,7 +33,23 @@ func (a ABCIResults) toByteSlices() [][]byte { l := len(a) bzs := make([][]byte, l) for i := 0; i < l; i++ { - bzs[i] = a[i].Bytes() + bz, err := a[i].Marshal() + if err != nil { + panic(err) + } + bzs[i] = bz } return bzs } + +// deterministicResponseDeliverTx strips non-deterministic fields from +// ResponseDeliverTx and returns another ResponseDeliverTx. +func deterministicResponseDeliverTx(response *abci.ResponseDeliverTx) *abci.ResponseDeliverTx { + return &abci.ResponseDeliverTx{ + Code: response.Code, + Data: response.Data, + GasWanted: response.GasWanted, + GasUsed: response.GasUsed, + Events: response.Events, + } +} diff --git a/types/results_test.go b/types/results_test.go index 9ecfe35ca..5b1be3466 100644 --- a/types/results_test.go +++ b/types/results_test.go @@ -10,26 +10,31 @@ import ( ) func TestABCIResults(t *testing.T) { - a := ABCIResult{Code: 0, Data: nil} - b := ABCIResult{Code: 0, Data: []byte{}} - c := ABCIResult{Code: 0, Data: []byte("one")} - d := ABCIResult{Code: 14, Data: nil} - e := ABCIResult{Code: 14, Data: []byte("foo")} - f := ABCIResult{Code: 14, Data: []byte("bar")} + a := &abci.ResponseDeliverTx{Code: 0, Data: nil} + b := &abci.ResponseDeliverTx{Code: 0, Data: []byte{}} + c := &abci.ResponseDeliverTx{Code: 0, Data: []byte("one")} + d := &abci.ResponseDeliverTx{Code: 14, Data: nil} + e := &abci.ResponseDeliverTx{Code: 14, Data: []byte("foo")} + f := &abci.ResponseDeliverTx{Code: 14, Data: []byte("bar")} // Nil and []byte{} should produce the same bytes - require.Equal(t, a.Bytes(), a.Bytes()) - require.Equal(t, b.Bytes(), b.Bytes()) - require.Equal(t, a.Bytes(), b.Bytes()) + bzA, err := a.Marshal() + require.NoError(t, err) + bzB, err := b.Marshal() + require.NoError(t, err) + + require.Equal(t, bzA, bzB) // a and b should be the same, don't go in results. results := ABCIResults{a, c, d, e, f} // Make sure each result serializes differently - var last []byte - assert.Equal(t, last, a.Bytes()) // first one is empty + last := []byte{} + assert.Equal(t, last, bzA) // first one is empty for i, res := range results[1:] { - bz := res.Bytes() + bz, err := res.Marshal() + require.NoError(t, err) + assert.NotEqual(t, last, bz, "%d", i) last = bz } @@ -39,19 +44,11 @@ func TestABCIResults(t *testing.T) { assert.NotEmpty(t, root) for i, res := range results { + bz, err := res.Marshal() + require.NoError(t, err) + proof := results.ProveResult(i) - valid := proof.Verify(root, res.Bytes()) + valid := proof.Verify(root, bz) assert.NoError(t, valid, "%d", i) } } - -func TestABCIResultsBytes(t *testing.T) { - results := NewResults([]*abci.ResponseDeliverTx{ - {Code: 0, Data: []byte{}}, - {Code: 0, Data: []byte("one")}, - {Code: 14, Data: nil}, - {Code: 14, Data: []byte("foo")}, - {Code: 14, Data: []byte("bar")}, - }) - assert.NotNil(t, results.Bytes()) -}