mirror of
https://github.com/tendermint/tendermint.git
synced 2026-07-24 17:12:45 +00:00
Merge remote-tracking branch 'upstream/develop' into HEAD
This commit is contained in:
+143
@@ -1,5 +1,148 @@
|
||||
# Changelog
|
||||
|
||||
## v0.26.0
|
||||
|
||||
*November 2, 2018*
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
@bradyjoestar, @connorwstein, @goolAdapter, @HaoyangLiu,
|
||||
@james-ray, @overbool, @phymbert, @Slamper, @Uzair1995, @yutianwu.
|
||||
|
||||
Special thanks to @Slamper for a series of bug reports in our [bug bounty
|
||||
program](https://hackerone.com/tendermint) which are fixed in this release.
|
||||
|
||||
This release is primarily about adding Version fields to various data structures,
|
||||
optimizing consensus messages for signing and verification in
|
||||
restricted environments (like HSMs and the Ethereum Virtual Machine), and
|
||||
aligning the consensus code with the [specification](https://arxiv.org/abs/1807.04938).
|
||||
It also includes our first take at a generalized merkle proof system, and
|
||||
changes the length of hashes used for hashing data structures from 20 to 32
|
||||
bytes.
|
||||
|
||||
See the [UPGRADING.md](UPGRADING.md#v0.26.0) for details on upgrading to the new
|
||||
version.
|
||||
|
||||
Please note that we are still making breaking changes to the protocols.
|
||||
While the new Version fields should help us to keep the software backwards compatible
|
||||
even while upgrading the protocols, we cannot guarantee that new releases will
|
||||
be compatible with old chains just yet. We expect there will be another breaking
|
||||
release or two before the Cosmos Hub launch, but we will otherwise be paying
|
||||
increasing attention to backwards compatibility. Thanks for bearing with us!
|
||||
|
||||
### BREAKING CHANGES:
|
||||
|
||||
* CLI/RPC/Config
|
||||
* [config] [\#2232](https://github.com/tendermint/tendermint/issues/2232) Timeouts are now strings like "3s" and "100ms", not ints
|
||||
* [config] [\#2505](https://github.com/tendermint/tendermint/issues/2505) Remove Mempool.RecheckEmpty (it was effectively useless anyways)
|
||||
* [config] [\#2490](https://github.com/tendermint/tendermint/issues/2490) `mempool.wal` is disabled by default
|
||||
* [privval] [\#2459](https://github.com/tendermint/tendermint/issues/2459) Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
||||
* [state] [\#2644](https://github.com/tendermint/tendermint/issues/2644) Add Version field to State, breaking the format of State as
|
||||
encoded on disk.
|
||||
* [rpc] [\#2298](https://github.com/tendermint/tendermint/issues/2298) `/abci_query` takes `prove` argument instead of `trusted` and switches the default
|
||||
behaviour to `prove=false`
|
||||
* [rpc] [\#2654](https://github.com/tendermint/tendermint/issues/2654) Remove all `node_info.other.*_version` fields in `/status` and
|
||||
`/net_info`
|
||||
* [rpc] [\#2636](https://github.com/tendermint/tendermint/issues/2636) Remove
|
||||
`_params` suffix from fields in `consensus_params`.
|
||||
|
||||
* Apps
|
||||
* [abci] [\#2298](https://github.com/tendermint/tendermint/issues/2298) ResponseQuery.Proof is now a structured merkle.Proof, not just
|
||||
arbitrary bytes
|
||||
* [abci] [\#2644](https://github.com/tendermint/tendermint/issues/2644) Add Version to Header and shift all fields by one
|
||||
* [abci] [\#2662](https://github.com/tendermint/tendermint/issues/2662) Bump the field numbers for some `ResponseInfo` fields to make room for
|
||||
`AppVersion`
|
||||
* [abci] [\#2636](https://github.com/tendermint/tendermint/issues/2636) Updates to ConsensusParams
|
||||
* Remove `Params` suffix from field names
|
||||
* Add `Params` suffix to message types
|
||||
* Add new field and type, `Validator ValidatorParams`, to control what types of validator keys are allowed.
|
||||
|
||||
* Go API
|
||||
* [config] [\#2232](https://github.com/tendermint/tendermint/issues/2232) Timeouts are time.Duration, not ints
|
||||
* [crypto/merkle & lite] [\#2298](https://github.com/tendermint/tendermint/issues/2298) Various changes to accomodate General Merkle trees
|
||||
* [crypto/merkle] [\#2595](https://github.com/tendermint/tendermint/issues/2595) Remove all Hasher objects in favor of byte slices
|
||||
* [crypto/merkle] [\#2635](https://github.com/tendermint/tendermint/issues/2635) merkle.SimpleHashFromTwoHashes is no longer exported
|
||||
* [node] [\#2479](https://github.com/tendermint/tendermint/issues/2479) Remove node.RunForever
|
||||
* [rpc/client] [\#2298](https://github.com/tendermint/tendermint/issues/2298) `ABCIQueryOptions.Trusted` -> `ABCIQueryOptions.Prove`
|
||||
* [types] [\#2298](https://github.com/tendermint/tendermint/issues/2298) Remove `Index` and `Total` fields from `TxProof`.
|
||||
* [types] [\#2598](https://github.com/tendermint/tendermint/issues/2598)
|
||||
`VoteTypeXxx` are now of type `SignedMsgType byte` and named `XxxType`, eg.
|
||||
`PrevoteType`, `PrecommitType`.
|
||||
* [types] [\#2636](https://github.com/tendermint/tendermint/issues/2636) Rename fields in ConsensusParams to remove `Params` suffixes
|
||||
* [types] [\#2735](https://github.com/tendermint/tendermint/issues/2735) Simplify Proposal message to align with spec
|
||||
|
||||
* Blockchain Protocol
|
||||
* [crypto/tmhash] [\#2732](https://github.com/tendermint/tendermint/issues/2732) TMHASH is now full 32-byte SHA256
|
||||
* All hashes in the block header and Merkle trees are now 32-bytes
|
||||
* PubKey Addresses are still only 20-bytes
|
||||
* [state] [\#2587](https://github.com/tendermint/tendermint/issues/2587) Require block.Time of the fist block to be genesis time
|
||||
* [state] [\#2644](https://github.com/tendermint/tendermint/issues/2644) Require block.Version to match state.Version
|
||||
* [types] Update SignBytes for `Vote`/`Proposal`/`Heartbeat`:
|
||||
* [\#2459](https://github.com/tendermint/tendermint/issues/2459) Use amino encoding instead of JSON in `SignBytes`.
|
||||
* [\#2598](https://github.com/tendermint/tendermint/issues/2598) Reorder fields and use fixed sized encoding.
|
||||
* [\#2598](https://github.com/tendermint/tendermint/issues/2598) Change `Type` field from `string` to `byte` and use new
|
||||
`SignedMsgType` to enumerate.
|
||||
* [types] [\#2730](https://github.com/tendermint/tendermint/issues/2730) Use
|
||||
same order for fields in `Vote` as in the SignBytes
|
||||
* [types] [\#2732](https://github.com/tendermint/tendermint/issues/2732) Remove the address field from the validator hash
|
||||
* [types] [\#2644](https://github.com/tendermint/tendermint/issues/2644) Add Version struct to Header
|
||||
* [types] [\#2609](https://github.com/tendermint/tendermint/issues/2609) ConsensusParams.Hash() is the hash of the amino encoded
|
||||
struct instead of the Merkle tree of the fields
|
||||
* [types] [\#2670](https://github.com/tendermint/tendermint/issues/2670) Header.Hash() builds Merkle tree out of fields in the same
|
||||
order they appear in the header, instead of sorting by field name
|
||||
* [types] [\#2682](https://github.com/tendermint/tendermint/issues/2682) Use proto3 `varint` encoding for ints that are usually unsigned (instead of zigzag encoding).
|
||||
* [types] [\#2636](https://github.com/tendermint/tendermint/issues/2636) Add Validator field to ConsensusParams
|
||||
(Used to control which pubkey types validators can use, by abci type).
|
||||
|
||||
* P2P Protocol
|
||||
* [consensus] [\#2652](https://github.com/tendermint/tendermint/issues/2652)
|
||||
Replace `CommitStepMessage` with `NewValidBlockMessage`
|
||||
* [consensus] [\#2735](https://github.com/tendermint/tendermint/issues/2735) Simplify `Proposal` message to align with spec
|
||||
* [consensus] [\#2730](https://github.com/tendermint/tendermint/issues/2730)
|
||||
Add `Type` field to `Proposal` and use same order of fields as in the
|
||||
SignBytes for both `Proposal` and `Vote`
|
||||
* [p2p] [\#2654](https://github.com/tendermint/tendermint/issues/2654) Add `ProtocolVersion` struct with protocol versions to top of
|
||||
DefaultNodeInfo and require `ProtocolVersion.Block` to match during peer handshake
|
||||
|
||||
|
||||
### FEATURES:
|
||||
- [abci] [\#2557](https://github.com/tendermint/tendermint/issues/2557) Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
|
||||
- [abci] [\#2662](https://github.com/tendermint/tendermint/issues/2662) Add `BlockVersion` and `P2PVersion` to `RequestInfo`
|
||||
- [crypto/merkle] [\#2298](https://github.com/tendermint/tendermint/issues/2298) General Merkle Proof scheme for chaining various types of Merkle trees together
|
||||
|
||||
### IMPROVEMENTS:
|
||||
- Additional Metrics
|
||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [config] [\#2232](https://github.com/tendermint/tendermint/issues/2232) Added ValidateBasic method, which performs basic checks
|
||||
- [crypto/ed25519] [\#2558](https://github.com/tendermint/tendermint/issues/2558) Switch to use latest `golang.org/x/crypto` through our fork at
|
||||
github.com/tendermint/crypto
|
||||
- [libs/log] [\#2707](https://github.com/tendermint/tendermint/issues/2707) Add year to log format (@yutianwu)
|
||||
- [tools] [\#2238](https://github.com/tendermint/tendermint/issues/2238) Binary dependencies are now locked to a specific git commit
|
||||
|
||||
### BUG FIXES:
|
||||
- [\#2711](https://github.com/tendermint/tendermint/issues/2711) Validate all incoming reactor messages. Fixes various bugs due to negative ints.
|
||||
- [autofile] [\#2428](https://github.com/tendermint/tendermint/issues/2428) Group.RotateFile need call Flush() before rename (@goolAdapter)
|
||||
- [common] [\#2533](https://github.com/tendermint/tendermint/issues/2533) Fixed a bug in the `BitArray.Or` method
|
||||
- [common] [\#2506](https://github.com/tendermint/tendermint/issues/2506) Fixed a bug in the `BitArray.Sub` method (@james-ray)
|
||||
- [common] [\#2534](https://github.com/tendermint/tendermint/issues/2534) Fix `BitArray.PickRandom` to choose uniformly from true bits
|
||||
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) Wait for
|
||||
timeoutPrecommit before starting next round
|
||||
- [consensus] [\#1745](https://github.com/tendermint/tendermint/issues/1745) Wait for
|
||||
Proposal or timeoutProposal before entering prevote
|
||||
- [consensus] [\#2642](https://github.com/tendermint/tendermint/issues/2642) Only propose ValidBlock, not LockedBlock
|
||||
- [consensus] [\#2642](https://github.com/tendermint/tendermint/issues/2642) Initialized ValidRound and LockedRound to -1
|
||||
- [consensus] [\#1637](https://github.com/tendermint/tendermint/issues/1637) Limit the amount of evidence that can be included in a
|
||||
block
|
||||
- [consensus] [\#2652](https://github.com/tendermint/tendermint/issues/2652) Ensure valid block property with faulty proposer
|
||||
- [evidence] [\#2515](https://github.com/tendermint/tendermint/issues/2515) Fix db iter leak (@goolAdapter)
|
||||
- [libs/event] [\#2518](https://github.com/tendermint/tendermint/issues/2518) Fix event concurrency flaw (@goolAdapter)
|
||||
- [node] [\#2434](https://github.com/tendermint/tendermint/issues/2434) Make node respond to signal interrupts while sleeping for genesis time
|
||||
- [state] [\#2616](https://github.com/tendermint/tendermint/issues/2616) Pass nil to NewValidatorSet() when genesis file's Validators field is nil
|
||||
- [p2p] [\#2555](https://github.com/tendermint/tendermint/issues/2555) Fix p2p switch FlushThrottle value (@goolAdapter)
|
||||
- [p2p] [\#2668](https://github.com/tendermint/tendermint/issues/2668) Reconnect to originally dialed address (not self-reported
|
||||
address) for persistent peers
|
||||
|
||||
|
||||
## v0.25.0
|
||||
|
||||
*September 22, 2018*
|
||||
|
||||
+14
-64
@@ -1,81 +1,31 @@
|
||||
# Pending
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
@goolAdapter, @bradyjoestar
|
||||
## v0.26.1
|
||||
|
||||
BREAKING CHANGES:
|
||||
*TBA*
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
|
||||
Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermint).
|
||||
|
||||
### BREAKING CHANGES:
|
||||
|
||||
* CLI/RPC/Config
|
||||
* [config] \#2232 timeouts as time.Duration, not ints
|
||||
* [config] \#2505 Remove Mempool.RecheckEmpty (it was effectively useless anyways)
|
||||
* [config] `mempool.wal` is disabled by default
|
||||
* [rpc] \#2298 `/abci_query` takes `prove` argument instead of `trusted` and switches the default
|
||||
behaviour to `prove=false`
|
||||
* [privval] \#2459 Split `SocketPVMsg`s implementations into Request and Response, where the Response may contain a error message (returned by the remote signer)
|
||||
* [state] \#2644 Add Version field to State, breaking the format of State as
|
||||
encoded on disk.
|
||||
* [rpc] \#2654 Remove all `node_info.other.*_version` fields in `/status` and
|
||||
`/net_info`
|
||||
|
||||
* Apps
|
||||
* [abci] \#2298 ResponseQuery.Proof is now a structured merkle.Proof, not just
|
||||
arbitrary bytes
|
||||
* [abci] \#2644 Add Version to Header and shift all fields by one
|
||||
|
||||
* Go API
|
||||
* [node] Remove node.RunForever
|
||||
* [config] \#2232 timeouts as time.Duration, not ints
|
||||
* [rpc/client] \#2298 `ABCIQueryOptions.Trusted` -> `ABCIQueryOptions.Prove`
|
||||
* [types] \#2298 Remove `Index` and `Total` fields from `TxProof`.
|
||||
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
|
||||
* [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices
|
||||
* [crypto/merkle] \#2635 merkle.SimpleHashFromTwoHashes is no longer exported
|
||||
* [types] \#2598 `VoteTypeXxx` are now of type `SignedMsgType byte` and named `XxxType`, eg. `PrevoteType`,
|
||||
`PrecommitType`.
|
||||
|
||||
* Blockchain Protocol
|
||||
* [types] Update SignBytes for `Vote`/`Proposal`/`Heartbeat`:
|
||||
* \#2459 Use amino encoding instead of JSON in `SignBytes`.
|
||||
* \#2598 Reorder fields and use fixed sized encoding.
|
||||
* \#2598 Change `Type` field fromt `string` to `byte` and use new
|
||||
`SignedMsgType` to enumerate.
|
||||
* [types] \#2512 Remove the pubkey field from the validator hash
|
||||
* [types] \#2644 Add Version struct to Header
|
||||
* [state] \#2587 Require block.Time of the fist block to be genesis time
|
||||
* [state] \#2644 Require block.Version to match state.Version
|
||||
|
||||
* P2P Protocol
|
||||
* [p2p] \#2654 Add `ProtocolVersion` struct with protocol versions to top of
|
||||
DefaultNodeInfo and require `ProtocolVersion.Block` to match during peer handshake
|
||||
|
||||
### FEATURES:
|
||||
|
||||
FEATURES:
|
||||
- [crypto/merkle] \#2298 General Merkle Proof scheme for chaining various types of Merkle trees together
|
||||
- [abci] \#2557 Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
|
||||
### IMPROVEMENTS:
|
||||
|
||||
IMPROVEMENTS:
|
||||
- Additional Metrics
|
||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [config] \#2232 Added ValidateBasic method, which performs basic checks
|
||||
- [crypto/ed25519] \#2558 Switch to use latest `golang.org/x/crypto` through our fork at
|
||||
github.com/tendermint/crypto
|
||||
- [tools] \#2238 Binary dependencies are now locked to a specific git commit
|
||||
- [crypto] \#2099 make crypto random use chacha, and have forward secrecy of generated randomness
|
||||
### BUG FIXES:
|
||||
|
||||
BUG FIXES:
|
||||
- [autofile] \#2428 Group.RotateFile need call Flush() before rename (@goolAdapter)
|
||||
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
||||
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) wait for
|
||||
timeoutPrecommit before starting next round
|
||||
- [consensus] [\#1745](https://github.com/tendermint/tendermint/issues/1745) wait for
|
||||
Proposal or timeoutProposal before entering prevote
|
||||
- [evidence] \#2515 fix db iter leak (@goolAdapter)
|
||||
- [common/bit_array] Fixed a bug in the `Or` function
|
||||
- [common/bit_array] Fixed a bug in the `Sub` function (@james-ray)
|
||||
- [common] \#2534 Make bit array's PickRandom choose uniformly from true bits
|
||||
- [consensus] \#1637 Limit the amount of evidence that can be included in a
|
||||
block
|
||||
- [p2p] \#2555 fix p2p switch FlushThrottle value (@goolAdapter)
|
||||
- [libs/event] \#2518 fix event concurrency flaw (@goolAdapter)
|
||||
- [state] \#2616 Pass nil to NewValidatorSet() when genesis file's Validators field is nil
|
||||
- [crypto/merkle] [\#2756](https://github.com/tendermint/tendermint/issues/2756) Fix crypto/merkle ProofOperators.Verify to check bounds on keypath parts.
|
||||
- [mempool] fix a bug where we create a WAL despite `wal_dir` being empty
|
||||
- [p2p] \#2771 Fix `peer-id` label name in prometheus metrics
|
||||
|
||||
Generated
+39
-47
@@ -11,11 +11,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
|
||||
digest = "1:c0decf632843204d2b8781de7b26e7038584e2dcccc7e2f401e88ae85b1df2b7"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "UT"
|
||||
revision = "f5e261fc9ec3437697fb31d8b38453c293204b29"
|
||||
revision = "67e573d211ace594f1366b4ce9d39726c4b19bd0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1d8e1cb71c33a9470bbbae09bfec09db43c6bf358dfcae13cd8807c4e2a9a2bf"
|
||||
@@ -28,19 +28,12 @@
|
||||
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
|
||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "UT"
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c7644c73a3d23741fdba8a99b1464e021a224b7e205be497271a8003a15ca41b"
|
||||
name = "github.com/ebuchman/fail-test"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
|
||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
||||
version = "v1.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:544229a3ca0fb2dd5ebc2896d3d2ff7ce096d9751635301e44e37e761349ee70"
|
||||
@@ -83,12 +76,12 @@
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c4a2528ccbcabf90f9f3c464a5fc9e302d592861bbfd0b7135a7de8a943d0406"
|
||||
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
|
||||
version = "v1.7.0"
|
||||
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
|
||||
version = "v1.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
|
||||
@@ -136,8 +129,7 @@
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
|
||||
digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
|
||||
name = "github.com/hashicorp/hcl"
|
||||
packages = [
|
||||
".",
|
||||
@@ -151,7 +143,8 @@
|
||||
"json/token",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
|
||||
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
@@ -193,12 +186,12 @@
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5ab79470a1d0fb19b041a624415612f8236b3c06070161a910562f2b2d064355"
|
||||
digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "f15292f7a699fcc1a38a80977f80a046874ba8ac"
|
||||
revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
|
||||
@@ -244,7 +237,7 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
|
||||
digest = "1:db712fde5d12d6cdbdf14b777f0c230f4ff5ab0be8e35b239fc319953ed577a4"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
@@ -252,11 +245,11 @@
|
||||
"model",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
|
||||
revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
|
||||
digest = "1:ef74914912f99c79434d9c09658274678bc85080ebe3ab32bec3940ebce5e1fc"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
@@ -265,7 +258,7 @@
|
||||
"xfs",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
|
||||
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c"
|
||||
@@ -275,23 +268,23 @@
|
||||
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
|
||||
digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "787d034dfe70e44075ccc060d346146ef53270ad"
|
||||
version = "v1.1.1"
|
||||
revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
|
||||
version = "v1.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f"
|
||||
digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc"
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
|
||||
@@ -302,20 +295,20 @@
|
||||
version = "v0.0.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:080e5f630945ad754f4b920e60b4d3095ba0237ebf88dc462eb28002932e3805"
|
||||
digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb"
|
||||
name = "github.com/spf13/jwalterweatherman"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
|
||||
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"
|
||||
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
|
||||
version = "v1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96"
|
||||
@@ -338,7 +331,7 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b3cfb8d82b1601a846417c3f31c03a7961862cb2c98dcf0959c473843e6d9a2b"
|
||||
digest = "1:59483b8e8183f10ab21a85ba1f4cbb4a2335d48891801f79ed7b9499f44d383c"
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
packages = [
|
||||
"leveldb",
|
||||
@@ -355,7 +348,7 @@
|
||||
"leveldb/util",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
||||
revision = "6b91fda63f2e36186f1c9d0e48578defb69c5d43"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:605b6546f3f43745695298ec2d342d3e952b6d91cdf9f349bea9315f677d759f"
|
||||
@@ -365,12 +358,12 @@
|
||||
revision = "e5840949ff4fff0c56f9b6a541e22b63581ea9df"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e0a2a4be1e20c305badc2b0a7a9ab7fef6da500763bec23ab81df3b5f9eec9ee"
|
||||
digest = "1:10b3a599325740c84a7c81f3f3cb2e1fdb70b3ea01b7fa28495567a2519df431"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
pruneopts = "UT"
|
||||
revision = "a8328986c1608950fa5d3d1c0472cccc4f8fc02c"
|
||||
version = "v0.12.0-rc0"
|
||||
revision = "6dcc6ddc143e116455c94b25c1004c99e0d0ca12"
|
||||
version = "v0.14.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:72b71e3a29775e5752ed7a8012052a3dee165e27ec18cedddae5288058f09acf"
|
||||
@@ -415,14 +408,14 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:bb0fe59917bdd5b89f49b9a8b26e5f465e325d9223b3a8e32254314bdf51e0f1"
|
||||
digest = "1:6f86e2f2e2217cd4d74dec6786163cf80e4d2b99adb341ecc60a45113b844dca"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"cpu",
|
||||
"unix",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "3dc4335d56c789b04b0ba99b7a37249d9b614314"
|
||||
revision = "7e31e0c00fa05cb5fbf4347b585621d6709e19a4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
|
||||
@@ -449,11 +442,11 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:077c1c599507b3b3e9156d17d36e1e61928ee9b53a5b420f10f28ebd4a0b275c"
|
||||
digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "UT"
|
||||
revision = "daca94659cb50e9f37c1b834680f2e46358f10b0"
|
||||
revision = "b69ba1387ce2108ac9bc8e8e5e5a46e7d5c72313"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
|
||||
@@ -503,7 +496,6 @@
|
||||
input-imports = [
|
||||
"github.com/btcsuite/btcutil/base58",
|
||||
"github.com/btcsuite/btcutil/bech32",
|
||||
"github.com/ebuchman/fail-test",
|
||||
"github.com/fortytw2/leaktest",
|
||||
"github.com/go-kit/kit/log",
|
||||
"github.com/go-kit/kit/log/level",
|
||||
|
||||
+1
-5
@@ -58,7 +58,7 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
version = "v0.12.0-rc0"
|
||||
version = "v0.14.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "google.golang.org/grpc"
|
||||
@@ -81,10 +81,6 @@
|
||||
name = "github.com/jmhodges/levigo"
|
||||
revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/ebuchman/fail-test"
|
||||
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
|
||||
|
||||
# last revision used by go-crypto
|
||||
[[constraint]]
|
||||
name = "github.com/btcsuite/btcutil"
|
||||
|
||||
@@ -36,7 +36,7 @@ install:
|
||||
########################################
|
||||
### Protobuf
|
||||
|
||||
protoc_all: protoc_libs protoc_merkle protoc_abci protoc_grpc
|
||||
protoc_all: protoc_libs protoc_merkle protoc_abci protoc_grpc protoc_proto3types
|
||||
|
||||
%.pb.go: %.proto
|
||||
## If you get the following error,
|
||||
@@ -52,6 +52,8 @@ protoc_all: protoc_libs protoc_merkle protoc_abci protoc_grpc
|
||||
# see protobuf section above
|
||||
protoc_abci: abci/types/types.pb.go
|
||||
|
||||
protoc_proto3types: types/proto3/block.pb.go
|
||||
|
||||
build_abci:
|
||||
@go build -i ./abci/cmd/...
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ We are also still making breaking changes to the protocol and the APIs.
|
||||
Thus, we tag the releases as *alpha software*.
|
||||
|
||||
In any case, if you intend to run Tendermint in production,
|
||||
please [contact us](https://riot.im/app/#/room/#tendermint:matrix.org) :)
|
||||
please [contact us](mailto:partners@tendermint.com) and [join the chat](https://riot.im/app/#/room/#tendermint:matrix.org).
|
||||
|
||||
## Security
|
||||
|
||||
|
||||
@@ -3,6 +3,86 @@
|
||||
This guide provides steps to be followed when you upgrade your applications to
|
||||
a newer version of Tendermint Core.
|
||||
|
||||
## v0.26.0
|
||||
|
||||
New 0.26.0 release contains a lot of changes to core data types and protocols. It is not
|
||||
compatible to the old versions and there is no straight forward way to update
|
||||
old data to be compatible with the new version.
|
||||
|
||||
To reset the state do:
|
||||
|
||||
```
|
||||
$ tendermint unsafe_reset_all
|
||||
```
|
||||
|
||||
Here we summarize some other notable changes to be mindful of.
|
||||
|
||||
### Config Changes
|
||||
|
||||
All timeouts must be changed from integers to strings with their duration, for
|
||||
instance `flush_throttle_timeout = 100` would be changed to
|
||||
`flush_throttle_timeout = "100ms"` and `timeout_propose = 3000` would be changed
|
||||
to `timeout_propose = "3s"`.
|
||||
|
||||
### RPC Changes
|
||||
|
||||
The default behaviour of `/abci_query` has been changed to not return a proof,
|
||||
and the name of the parameter that controls this has been changed from `trusted`
|
||||
to `prove`. To get proofs with your queries, ensure you set `prove=true`.
|
||||
|
||||
Various version fields like `amino_version`, `p2p_version`, `consensus_version`,
|
||||
and `rpc_version` have been removed from the `node_info.other` and are
|
||||
consolidated under the tendermint semantic version (ie. `node_info.version`) and
|
||||
the new `block` and `p2p` protocol versions under `node_info.protocol_version`.
|
||||
|
||||
### ABCI Changes
|
||||
|
||||
Field numbers were bumped in the `Header` and `ResponseInfo` messages to make
|
||||
room for new `version` fields. It should be straight forward to recompile the
|
||||
protobuf file for these changes.
|
||||
|
||||
#### Proofs
|
||||
|
||||
The `ResponseQuery.Proof` field is now structured as a `[]ProofOp` to support
|
||||
generalized Merkle tree constructions where the leaves of one Merkle tree are
|
||||
the root of another. If you don't need this functionality, and you used to
|
||||
return `<proof bytes>` here, you should instead return a single `ProofOp` with
|
||||
just the `Data` field set:
|
||||
|
||||
```
|
||||
[]ProofOp{
|
||||
ProofOp{
|
||||
Data: <proof bytes>,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more information, see:
|
||||
|
||||
- [ADR-026](https://github.com/tendermint/tendermint/blob/30519e8361c19f4bf320ef4d26288ebc621ad725/docs/architecture/adr-026-general-merkle-proof.md)
|
||||
- [Relevant ABCI
|
||||
documentation](https://github.com/tendermint/tendermint/blob/30519e8361c19f4bf320ef4d26288ebc621ad725/docs/spec/abci/apps.md#query-proofs)
|
||||
- [Description of
|
||||
keys](https://github.com/tendermint/tendermint/blob/30519e8361c19f4bf320ef4d26288ebc621ad725/crypto/merkle/proof_key_path.go#L14)
|
||||
|
||||
### Go API Changes
|
||||
|
||||
#### crypto.merkle
|
||||
|
||||
The `merkle.Hasher` interface was removed. Functions which used to take `Hasher`
|
||||
now simply take `[]byte`. This means that any objects being Merklized should be
|
||||
serialized before they are passed in.
|
||||
|
||||
#### node
|
||||
|
||||
The `node.RunForever` function was removed. Signal handling and running forever
|
||||
should instead be explicitly configured by the caller. See how we do it
|
||||
[here](https://github.com/tendermint/tendermint/blob/30519e8361c19f4bf320ef4d26288ebc621ad725/cmd/tendermint/commands/run_node.go#L60).
|
||||
|
||||
### Other
|
||||
|
||||
All hashes, except for public key addresses, are now 32-bytes.
|
||||
|
||||
## v0.25.0
|
||||
|
||||
This release has minimal impact.
|
||||
|
||||
@@ -10,11 +10,14 @@ import (
|
||||
"github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
var (
|
||||
stateKey = []byte("stateKey")
|
||||
kvPairPrefixKey = []byte("kvPairKey:")
|
||||
|
||||
ProtocolVersion version.Protocol = 0x1
|
||||
)
|
||||
|
||||
type State struct {
|
||||
@@ -65,7 +68,11 @@ func NewKVStoreApplication() *KVStoreApplication {
|
||||
}
|
||||
|
||||
func (app *KVStoreApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) {
|
||||
return types.ResponseInfo{Data: fmt.Sprintf("{\"size\":%v}", app.state.Size)}
|
||||
return types.ResponseInfo{
|
||||
Data: fmt.Sprintf("{\"size\":%v}", app.state.Size),
|
||||
Version: version.ABCIVersion,
|
||||
AppVersion: ProtocolVersion.Uint64(),
|
||||
}
|
||||
}
|
||||
|
||||
// tx is either "key=value" or just arbitrary bytes
|
||||
|
||||
+725
-317
File diff suppressed because it is too large
Load Diff
+16
-6
@@ -49,6 +49,8 @@ message RequestFlush {
|
||||
|
||||
message RequestInfo {
|
||||
string version = 1;
|
||||
uint64 block_version = 2;
|
||||
uint64 p2p_version = 3;
|
||||
}
|
||||
|
||||
// nondeterministic
|
||||
@@ -72,7 +74,6 @@ message RequestQuery {
|
||||
bool prove = 4;
|
||||
}
|
||||
|
||||
// NOTE: validators here have empty pubkeys.
|
||||
message RequestBeginBlock {
|
||||
bytes hash = 1;
|
||||
Header header = 2 [(gogoproto.nullable)=false];
|
||||
@@ -129,9 +130,12 @@ message ResponseFlush {
|
||||
|
||||
message ResponseInfo {
|
||||
string data = 1;
|
||||
|
||||
string version = 2;
|
||||
int64 last_block_height = 3;
|
||||
bytes last_block_app_hash = 4;
|
||||
uint64 app_version = 3;
|
||||
|
||||
int64 last_block_height = 4;
|
||||
bytes last_block_app_hash = 5;
|
||||
}
|
||||
|
||||
// nondeterministic
|
||||
@@ -203,12 +207,13 @@ message ResponseCommit {
|
||||
// ConsensusParams contains all consensus-relevant parameters
|
||||
// that can be adjusted by the abci app
|
||||
message ConsensusParams {
|
||||
BlockSize block_size = 1;
|
||||
EvidenceParams evidence_params = 2;
|
||||
BlockSizeParams block_size = 1;
|
||||
EvidenceParams evidence = 2;
|
||||
ValidatorParams validator = 3;
|
||||
}
|
||||
|
||||
// BlockSize contains limits on the block size.
|
||||
message BlockSize {
|
||||
message BlockSizeParams {
|
||||
// Note: must be greater than 0
|
||||
int64 max_bytes = 1;
|
||||
// Note: must be greater or equal to -1
|
||||
@@ -221,6 +226,11 @@ message EvidenceParams {
|
||||
int64 max_age = 1;
|
||||
}
|
||||
|
||||
// ValidatorParams contains limits on validators.
|
||||
message ValidatorParams {
|
||||
repeated string pub_key_types = 1;
|
||||
}
|
||||
|
||||
message LastCommitInfo {
|
||||
int32 round = 1;
|
||||
repeated VoteInfo votes = 2 [(gogoproto.nullable)=false];
|
||||
|
||||
+141
-17
@@ -1479,15 +1479,15 @@ func TestConsensusParamsMarshalTo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockSizeProto(t *testing.T) {
|
||||
func TestBlockSizeParamsProto(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, false)
|
||||
p := NewPopulatedBlockSizeParams(popr, false)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &BlockSize{}
|
||||
msg := &BlockSizeParams{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
@@ -1510,10 +1510,10 @@ func TestBlockSizeProto(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockSizeMarshalTo(t *testing.T) {
|
||||
func TestBlockSizeParamsMarshalTo(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, false)
|
||||
p := NewPopulatedBlockSizeParams(popr, false)
|
||||
size := p.Size()
|
||||
dAtA := make([]byte, size)
|
||||
for i := range dAtA {
|
||||
@@ -1523,7 +1523,7 @@ func TestBlockSizeMarshalTo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &BlockSize{}
|
||||
msg := &BlockSizeParams{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
@@ -1591,6 +1591,62 @@ func TestEvidenceParamsMarshalTo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorParamsProto(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, false)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &ValidatorParams{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
littlefuzz := make([]byte, len(dAtA))
|
||||
copy(littlefuzz, dAtA)
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
if len(littlefuzz) > 0 {
|
||||
fuzzamount := 100
|
||||
for i := 0; i < fuzzamount; i++ {
|
||||
littlefuzz[popr.Intn(len(littlefuzz))] = byte(popr.Intn(256))
|
||||
littlefuzz = append(littlefuzz, byte(popr.Intn(256)))
|
||||
}
|
||||
// shouldn't panic
|
||||
_ = github_com_gogo_protobuf_proto.Unmarshal(littlefuzz, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorParamsMarshalTo(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, false)
|
||||
size := p.Size()
|
||||
dAtA := make([]byte, size)
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
_, err := p.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &ValidatorParams{}
|
||||
if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
for i := range dAtA {
|
||||
dAtA[i] = byte(popr.Intn(256))
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastCommitInfoProto(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
@@ -2619,16 +2675,16 @@ func TestConsensusParamsJSON(t *testing.T) {
|
||||
t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
func TestBlockSizeJSON(t *testing.T) {
|
||||
func TestBlockSizeParamsJSON(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, true)
|
||||
p := NewPopulatedBlockSizeParams(popr, true)
|
||||
marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{}
|
||||
jsondata, err := marshaler.MarshalToString(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &BlockSize{}
|
||||
msg := &BlockSizeParams{}
|
||||
err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
@@ -2655,6 +2711,24 @@ func TestEvidenceParamsJSON(t *testing.T) {
|
||||
t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
func TestValidatorParamsJSON(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, true)
|
||||
marshaler := github_com_gogo_protobuf_jsonpb.Marshaler{}
|
||||
jsondata, err := marshaler.MarshalToString(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
msg := &ValidatorParams{}
|
||||
err = github_com_gogo_protobuf_jsonpb.UnmarshalString(jsondata, msg)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
func TestLastCommitInfoJSON(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
@@ -3563,12 +3637,12 @@ func TestConsensusParamsProtoCompactText(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockSizeProtoText(t *testing.T) {
|
||||
func TestBlockSizeParamsProtoText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, true)
|
||||
p := NewPopulatedBlockSizeParams(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p)
|
||||
msg := &BlockSize{}
|
||||
msg := &BlockSizeParams{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
@@ -3577,12 +3651,12 @@ func TestBlockSizeProtoText(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockSizeProtoCompactText(t *testing.T) {
|
||||
func TestBlockSizeParamsProtoCompactText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, true)
|
||||
p := NewPopulatedBlockSizeParams(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.CompactTextString(p)
|
||||
msg := &BlockSize{}
|
||||
msg := &BlockSizeParams{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
@@ -3619,6 +3693,34 @@ func TestEvidenceParamsProtoCompactText(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorParamsProtoText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.MarshalTextString(p)
|
||||
msg := &ValidatorParams{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorParamsProtoCompactText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, true)
|
||||
dAtA := github_com_gogo_protobuf_proto.CompactTextString(p)
|
||||
msg := &ValidatorParams{}
|
||||
if err := github_com_gogo_protobuf_proto.UnmarshalText(dAtA, msg); err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
if !p.Equal(msg) {
|
||||
t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastCommitInfoProtoText(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
@@ -4471,10 +4573,10 @@ func TestConsensusParamsSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockSizeSize(t *testing.T) {
|
||||
func TestBlockSizeParamsSize(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedBlockSize(popr, true)
|
||||
p := NewPopulatedBlockSizeParams(popr, true)
|
||||
size2 := github_com_gogo_protobuf_proto.Size(p)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
@@ -4515,6 +4617,28 @@ func TestEvidenceParamsSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatorParamsSize(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
p := NewPopulatedValidatorParams(popr, true)
|
||||
size2 := github_com_gogo_protobuf_proto.Size(p)
|
||||
dAtA, err := github_com_gogo_protobuf_proto.Marshal(p)
|
||||
if err != nil {
|
||||
t.Fatalf("seed = %d, err = %v", seed, err)
|
||||
}
|
||||
size := p.Size()
|
||||
if len(dAtA) != size {
|
||||
t.Errorf("seed = %d, size %v != marshalled size %v", seed, size, len(dAtA))
|
||||
}
|
||||
if size2 != size {
|
||||
t.Errorf("seed = %d, size %v != before marshal proto.Size %v", seed, size, size2)
|
||||
}
|
||||
size3 := github_com_gogo_protobuf_proto.Size(p)
|
||||
if size3 != size {
|
||||
t.Errorf("seed = %d, size %v != after marshal proto.Size %v", seed, size, size3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastCommitInfoSize(t *testing.T) {
|
||||
seed := time.Now().UnixNano()
|
||||
popr := math_rand.New(math_rand.NewSource(seed))
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func testNodeInfo(id p2p.ID) p2p.DefaultNodeInfo {
|
||||
return p2p.DefaultNodeInfo{
|
||||
ProtocolVersion: p2p.InitProtocolVersion,
|
||||
ProtocolVersion: p2p.ProtocolVersion{1, 2, 3},
|
||||
ID_: id,
|
||||
Moniker: "SOMENAME",
|
||||
Network: "SOMENAME",
|
||||
|
||||
+51
-2
@@ -1,6 +1,7 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
@@ -180,6 +181,12 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
return
|
||||
}
|
||||
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
bcR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
bcR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
bcR.Logger.Debug("Receive", "src", src, "chID", chID, "msg", msg)
|
||||
|
||||
switch msg := msg.(type) {
|
||||
@@ -188,7 +195,6 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
// Unfortunately not queued since the queue is full.
|
||||
}
|
||||
case *bcBlockResponseMessage:
|
||||
// Got a block.
|
||||
bcR.pool.AddBlock(src.ID(), msg.Block, len(msgBytes))
|
||||
case *bcStatusRequestMessage:
|
||||
// Send peer our state.
|
||||
@@ -352,7 +358,9 @@ func (bcR *BlockchainReactor) BroadcastStatusRequest() error {
|
||||
// Messages
|
||||
|
||||
// BlockchainMessage is a generic message for this reactor.
|
||||
type BlockchainMessage interface{}
|
||||
type BlockchainMessage interface {
|
||||
ValidateBasic() error
|
||||
}
|
||||
|
||||
func RegisterBlockchainMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*BlockchainMessage)(nil), nil)
|
||||
@@ -377,6 +385,14 @@ type bcBlockRequestMessage struct {
|
||||
Height int64
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *bcBlockRequestMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *bcBlockRequestMessage) String() string {
|
||||
return fmt.Sprintf("[bcBlockRequestMessage %v]", m.Height)
|
||||
}
|
||||
@@ -385,6 +401,14 @@ type bcNoBlockResponseMessage struct {
|
||||
Height int64
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *bcNoBlockResponseMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (brm *bcNoBlockResponseMessage) String() string {
|
||||
return fmt.Sprintf("[bcNoBlockResponseMessage %d]", brm.Height)
|
||||
}
|
||||
@@ -395,6 +419,15 @@ type bcBlockResponseMessage struct {
|
||||
Block *types.Block
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *bcBlockResponseMessage) ValidateBasic() error {
|
||||
if err := m.Block.ValidateBasic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *bcBlockResponseMessage) String() string {
|
||||
return fmt.Sprintf("[bcBlockResponseMessage %v]", m.Block.Height)
|
||||
}
|
||||
@@ -405,6 +438,14 @@ type bcStatusRequestMessage struct {
|
||||
Height int64
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *bcStatusRequestMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *bcStatusRequestMessage) String() string {
|
||||
return fmt.Sprintf("[bcStatusRequestMessage %v]", m.Height)
|
||||
}
|
||||
@@ -415,6 +456,14 @@ type bcStatusResponseMessage struct {
|
||||
Height int64
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *bcStatusResponseMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *bcStatusResponseMessage) String() string {
|
||||
return fmt.Sprintf("[bcStatusResponseMessage %v]", m.Height)
|
||||
}
|
||||
|
||||
@@ -206,3 +206,4 @@ func (tp *bcrTestPeer) IsPersistent() bool { return true }
|
||||
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
|
||||
func (tp *bcrTestPeer) Set(string, interface{}) {}
|
||||
func (tp *bcrTestPeer) RemoteIP() net.IP { return []byte{127, 0, 0, 1} }
|
||||
func (tp *bcrTestPeer) OriginalAddr() *p2p.NetAddress { return nil }
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ func (bs *BlockStore) LoadBlock(height int64) *types.Block {
|
||||
part := bs.LoadBlockPart(height, i)
|
||||
buf = append(buf, part.Bytes...)
|
||||
}
|
||||
err := cdc.UnmarshalBinary(buf, block)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(buf, block)
|
||||
if err != nil {
|
||||
// NOTE: The existence of meta should imply the existence of the
|
||||
// block. So, make sure meta is only saved after blocks are saved.
|
||||
|
||||
@@ -497,6 +497,11 @@ func (cfg *MempoolConfig) WalDir() string {
|
||||
return rootify(cfg.WalPath, cfg.RootDir)
|
||||
}
|
||||
|
||||
// WalEnabled returns true if the WAL is enabled.
|
||||
func (cfg *MempoolConfig) WalEnabled() bool {
|
||||
return cfg.WalPath != ""
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation (checking param bounds, etc.) and
|
||||
// returns an error if any check fails.
|
||||
func (cfg *MempoolConfig) ValidateBasic() error {
|
||||
|
||||
+1
-1
@@ -342,7 +342,7 @@ func ResetTestRoot(testName string) *Config {
|
||||
}
|
||||
|
||||
var testGenesis = `{
|
||||
"genesis_time": "2017-10-10T08:20:13.695936996Z",
|
||||
"genesis_time": "2018-10-10T08:20:13.695936996Z",
|
||||
"chain_id": "tendermint_test",
|
||||
"validators": [
|
||||
{
|
||||
|
||||
@@ -179,16 +179,16 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *Cons
|
||||
|
||||
// Create a new proposal block from state/txs from the mempool.
|
||||
block1, blockParts1 := cs.createProposalBlock()
|
||||
polRound, polBlockID := cs.Votes.POLInfo()
|
||||
proposal1 := types.NewProposal(height, round, blockParts1.Header(), polRound, polBlockID)
|
||||
polRound, propBlockID := cs.ValidRound, types.BlockID{block1.Hash(), blockParts1.Header()}
|
||||
proposal1 := types.NewProposal(height, round, polRound, propBlockID)
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal1); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Create a new proposal block from state/txs from the mempool.
|
||||
block2, blockParts2 := cs.createProposalBlock()
|
||||
polRound, polBlockID = cs.Votes.POLInfo()
|
||||
proposal2 := types.NewProposal(height, round, blockParts2.Header(), polRound, polBlockID)
|
||||
polRound, propBlockID = cs.ValidRound, types.BlockID{block2.Hash(), blockParts2.Header()}
|
||||
proposal2 := types.NewProposal(height, round, polRound, propBlockID)
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal2); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -263,7 +263,7 @@ func (br *ByzantineReactor) AddPeer(peer p2p.Peer) {
|
||||
// Send our state to peer.
|
||||
// If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
|
||||
if !br.reactor.fastSync {
|
||||
br.reactor.sendNewRoundStepMessages(peer)
|
||||
br.reactor.sendNewRoundStepMessage(peer)
|
||||
}
|
||||
}
|
||||
func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
|
||||
@@ -130,8 +130,8 @@ func decideProposal(cs1 *ConsensusState, vs *validatorStub, height int64, round
|
||||
}
|
||||
|
||||
// Make proposal
|
||||
polRound, polBlockID := cs1.Votes.POLInfo()
|
||||
proposal = types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
|
||||
polRound, propBlockID := cs1.ValidRound, types.BlockID{block.Hash(), blockParts.Header()}
|
||||
proposal = types.NewProposal(height, round, polRound, propBlockID)
|
||||
if err := vs.SignProposal(cs1.state.ChainID, proposal); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -420,6 +420,11 @@ func ensureNewProposal(proposalCh <-chan interface{}, height int64, round int) {
|
||||
"Timeout expired while waiting for NewProposal event")
|
||||
}
|
||||
|
||||
func ensureNewValidBlock(validBlockCh <-chan interface{}, height int64, round int) {
|
||||
ensureNewEvent(validBlockCh, height, round, ensureTimeout,
|
||||
"Timeout expired while waiting for NewValidBlock event")
|
||||
}
|
||||
|
||||
func ensureNewBlock(blockCh <-chan interface{}, height int64) {
|
||||
select {
|
||||
case <-time.After(ensureTimeout):
|
||||
@@ -610,8 +615,6 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []types.PrivValidator) {
|
||||
genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
|
||||
s0, _ := sm.MakeGenesisState(genDoc)
|
||||
db := dbm.NewMemDB() // remove this ?
|
||||
sm.SaveState(db, s0)
|
||||
return s0, privValidators
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/code"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
|
||||
+203
-47
@@ -8,8 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cstypes "github.com/tendermint/tendermint/consensus/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmevents "github.com/tendermint/tendermint/libs/events"
|
||||
@@ -174,7 +173,7 @@ func (conR *ConsensusReactor) AddPeer(peer p2p.Peer) {
|
||||
// Send our state to peer.
|
||||
// If we're fast_syncing, broadcast a RoundStepMessage later upon SwitchToConsensus().
|
||||
if !conR.FastSync() {
|
||||
conR.sendNewRoundStepMessages(peer)
|
||||
conR.sendNewRoundStepMessage(peer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +204,13 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
conR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
conR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
|
||||
|
||||
// Get peer states
|
||||
@@ -215,8 +221,8 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
switch msg := msg.(type) {
|
||||
case *NewRoundStepMessage:
|
||||
ps.ApplyNewRoundStepMessage(msg)
|
||||
case *CommitStepMessage:
|
||||
ps.ApplyCommitStepMessage(msg)
|
||||
case *NewValidBlockMessage:
|
||||
ps.ApplyNewValidBlockMessage(msg)
|
||||
case *HasVoteMessage:
|
||||
ps.ApplyHasVoteMessage(msg)
|
||||
case *VoteSetMaj23Message:
|
||||
@@ -242,8 +248,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
case types.PrecommitType:
|
||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
default:
|
||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||
return
|
||||
panic("Bad VoteSetBitsMessage field Type. Forgot to add a check in ValidateBasic?")
|
||||
}
|
||||
src.TrySend(VoteSetBitsChannel, cdc.MustMarshalBinaryBare(&VoteSetBitsMessage{
|
||||
Height: msg.Height,
|
||||
@@ -322,8 +327,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
case types.PrecommitType:
|
||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
default:
|
||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||
return
|
||||
panic("Bad VoteSetBitsMessage field Type. Forgot to add a check in ValidateBasic?")
|
||||
}
|
||||
ps.ApplyVoteSetBitsMessage(msg, ourVotes)
|
||||
} else {
|
||||
@@ -365,7 +369,12 @@ func (conR *ConsensusReactor) subscribeToBroadcastEvents() {
|
||||
const subscriber = "consensus-reactor"
|
||||
conR.conS.evsw.AddListenerForEvent(subscriber, types.EventNewRoundStep,
|
||||
func(data tmevents.EventData) {
|
||||
conR.broadcastNewRoundStepMessages(data.(*cstypes.RoundState))
|
||||
conR.broadcastNewRoundStepMessage(data.(*cstypes.RoundState))
|
||||
})
|
||||
|
||||
conR.conS.evsw.AddListenerForEvent(subscriber, types.EventValidBlock,
|
||||
func(data tmevents.EventData) {
|
||||
conR.broadcastNewValidBlockMessage(data.(*cstypes.RoundState))
|
||||
})
|
||||
|
||||
conR.conS.evsw.AddListenerForEvent(subscriber, types.EventVote,
|
||||
@@ -391,14 +400,20 @@ func (conR *ConsensusReactor) broadcastProposalHeartbeatMessage(hb *types.Heartb
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
}
|
||||
|
||||
func (conR *ConsensusReactor) broadcastNewRoundStepMessages(rs *cstypes.RoundState) {
|
||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||
if nrsMsg != nil {
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
if csMsg != nil {
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
|
||||
func (conR *ConsensusReactor) broadcastNewRoundStepMessage(rs *cstypes.RoundState) {
|
||||
nrsMsg := makeRoundStepMessage(rs)
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
|
||||
func (conR *ConsensusReactor) broadcastNewValidBlockMessage(rs *cstypes.RoundState) {
|
||||
csMsg := &NewValidBlockMessage{
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
||||
BlockParts: rs.ProposalBlockParts.BitArray(),
|
||||
IsCommit: rs.Step == cstypes.RoundStepCommit,
|
||||
}
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
|
||||
}
|
||||
|
||||
// Broadcasts HasVoteMessage to peers that care.
|
||||
@@ -427,33 +442,21 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
|
||||
*/
|
||||
}
|
||||
|
||||
func makeRoundStepMessages(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
||||
func makeRoundStepMessage(rs *cstypes.RoundState) (nrsMsg *NewRoundStepMessage) {
|
||||
nrsMsg = &NewRoundStepMessage{
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Step: rs.Step,
|
||||
Height: rs.Height,
|
||||
Round: rs.Round,
|
||||
Step: rs.Step,
|
||||
SecondsSinceStartTime: int(time.Since(rs.StartTime).Seconds()),
|
||||
LastCommitRound: rs.LastCommit.Round(),
|
||||
}
|
||||
if rs.Step == cstypes.RoundStepCommit {
|
||||
csMsg = &CommitStepMessage{
|
||||
Height: rs.Height,
|
||||
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
||||
BlockParts: rs.ProposalBlockParts.BitArray(),
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (conR *ConsensusReactor) sendNewRoundStepMessages(peer p2p.Peer) {
|
||||
func (conR *ConsensusReactor) sendNewRoundStepMessage(peer p2p.Peer) {
|
||||
rs := conR.conS.GetRoundState()
|
||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||
if nrsMsg != nil {
|
||||
peer.Send(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
if csMsg != nil {
|
||||
peer.Send(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
|
||||
}
|
||||
nrsMsg := makeRoundStepMessage(rs)
|
||||
peer.Send(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
|
||||
func (conR *ConsensusReactor) gossipDataRoutine(peer p2p.Peer, ps *PeerState) {
|
||||
@@ -524,6 +527,7 @@ OUTER_LOOP:
|
||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||
logger.Debug("Sending proposal", "height", prs.Height, "round", prs.Round)
|
||||
if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
|
||||
// NOTE[ZM]: A peer might have received different proposal msg so this Proposal msg will be rejected!
|
||||
ps.SetHasProposal(rs.Proposal)
|
||||
}
|
||||
}
|
||||
@@ -964,13 +968,20 @@ func (ps *PeerState) SetHasProposal(proposal *types.Proposal) {
|
||||
if ps.PRS.Height != proposal.Height || ps.PRS.Round != proposal.Round {
|
||||
return
|
||||
}
|
||||
|
||||
if ps.PRS.Proposal {
|
||||
return
|
||||
}
|
||||
|
||||
ps.PRS.Proposal = true
|
||||
ps.PRS.ProposalBlockPartsHeader = proposal.BlockPartsHeader
|
||||
ps.PRS.ProposalBlockParts = cmn.NewBitArray(proposal.BlockPartsHeader.Total)
|
||||
|
||||
// ps.PRS.ProposalBlockParts is set due to NewValidBlockMessage
|
||||
if ps.PRS.ProposalBlockParts != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ps.PRS.ProposalBlockPartsHeader = proposal.BlockID.PartsHeader
|
||||
ps.PRS.ProposalBlockParts = cmn.NewBitArray(proposal.BlockID.PartsHeader.Total)
|
||||
ps.PRS.ProposalPOLRound = proposal.POLRound
|
||||
ps.PRS.ProposalPOL = nil // Nil until ProposalPOLMessage received.
|
||||
}
|
||||
@@ -1211,7 +1222,6 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage) {
|
||||
// Just remember these values.
|
||||
psHeight := ps.PRS.Height
|
||||
psRound := ps.PRS.Round
|
||||
//psStep := ps.PRS.Step
|
||||
psCatchupCommitRound := ps.PRS.CatchupCommitRound
|
||||
psCatchupCommit := ps.PRS.CatchupCommit
|
||||
|
||||
@@ -1252,8 +1262,8 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
// ApplyCommitStepMessage updates the peer state for the new commit.
|
||||
func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
|
||||
// ApplyNewValidBlockMessage updates the peer state for the new valid block.
|
||||
func (ps *PeerState) ApplyNewValidBlockMessage(msg *NewValidBlockMessage) {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
@@ -1261,6 +1271,10 @@ func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
|
||||
return
|
||||
}
|
||||
|
||||
if ps.PRS.Round != msg.Round && !msg.IsCommit {
|
||||
return
|
||||
}
|
||||
|
||||
ps.PRS.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||
ps.PRS.ProposalBlockParts = msg.BlockParts
|
||||
}
|
||||
@@ -1339,12 +1353,14 @@ func (ps *PeerState) StringIndented(indent string) string {
|
||||
// Messages
|
||||
|
||||
// ConsensusMessage is a message that can be sent and received on the ConsensusReactor
|
||||
type ConsensusMessage interface{}
|
||||
type ConsensusMessage interface {
|
||||
ValidateBasic() error
|
||||
}
|
||||
|
||||
func RegisterConsensusMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*ConsensusMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&NewRoundStepMessage{}, "tendermint/NewRoundStepMessage", nil)
|
||||
cdc.RegisterConcrete(&CommitStepMessage{}, "tendermint/CommitStep", nil)
|
||||
cdc.RegisterConcrete(&NewValidBlockMessage{}, "tendermint/NewValidBlockMessage", nil)
|
||||
cdc.RegisterConcrete(&ProposalMessage{}, "tendermint/Proposal", nil)
|
||||
cdc.RegisterConcrete(&ProposalPOLMessage{}, "tendermint/ProposalPOL", nil)
|
||||
cdc.RegisterConcrete(&BlockPartMessage{}, "tendermint/BlockPart", nil)
|
||||
@@ -1375,6 +1391,27 @@ type NewRoundStepMessage struct {
|
||||
LastCommitRound int
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *NewRoundStepMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if !m.Step.IsValid() {
|
||||
return errors.New("Invalid Step")
|
||||
}
|
||||
|
||||
// NOTE: SecondsSinceStartTime may be negative
|
||||
|
||||
if (m.Height == 1 && m.LastCommitRound != -1) ||
|
||||
(m.Height > 1 && m.LastCommitRound < -1) { // TODO: #2737 LastCommitRound should always be >= 0 for heights > 1
|
||||
return errors.New("Invalid LastCommitRound (for 1st block: -1, for others: >= 0)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *NewRoundStepMessage) String() string {
|
||||
return fmt.Sprintf("[NewRoundStep H:%v R:%v S:%v LCR:%v]",
|
||||
@@ -1383,16 +1420,40 @@ func (m *NewRoundStepMessage) String() string {
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// CommitStepMessage is sent when a block is committed.
|
||||
type CommitStepMessage struct {
|
||||
// NewValidBlockMessage is sent when a validator observes a valid block B in some round r,
|
||||
//i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
// In case the block is also committed, then IsCommit flag is set to true.
|
||||
type NewValidBlockMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
BlockPartsHeader types.PartSetHeader
|
||||
BlockParts *cmn.BitArray
|
||||
IsCommit bool
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *NewValidBlockMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if err := m.BlockPartsHeader.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("Wrong BlockPartsHeader: %v", err)
|
||||
}
|
||||
if m.BlockParts.Size() != m.BlockPartsHeader.Total {
|
||||
return fmt.Errorf("BlockParts bit array size %d not equal to BlockPartsHeader.Total %d",
|
||||
m.BlockParts.Size(),
|
||||
m.BlockPartsHeader.Total)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *CommitStepMessage) String() string {
|
||||
return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockPartsHeader, m.BlockParts)
|
||||
func (m *NewValidBlockMessage) String() string {
|
||||
return fmt.Sprintf("[ValidBlockMessage H:%v R:%v BP:%v BA:%v IsCommit:%v]",
|
||||
m.Height, m.Round, m.BlockPartsHeader, m.BlockParts, m.IsCommit)
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
@@ -1402,6 +1463,11 @@ type ProposalMessage struct {
|
||||
Proposal *types.Proposal
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *ProposalMessage) ValidateBasic() error {
|
||||
return m.Proposal.ValidateBasic()
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *ProposalMessage) String() string {
|
||||
return fmt.Sprintf("[Proposal %v]", m.Proposal)
|
||||
@@ -1416,6 +1482,20 @@ type ProposalPOLMessage struct {
|
||||
ProposalPOL *cmn.BitArray
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *ProposalPOLMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.ProposalPOLRound < 0 {
|
||||
return errors.New("Negative ProposalPOLRound")
|
||||
}
|
||||
if m.ProposalPOL.Size() == 0 {
|
||||
return errors.New("Empty ProposalPOL bit array")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *ProposalPOLMessage) String() string {
|
||||
return fmt.Sprintf("[ProposalPOL H:%v POLR:%v POL:%v]", m.Height, m.ProposalPOLRound, m.ProposalPOL)
|
||||
@@ -1430,6 +1510,20 @@ type BlockPartMessage struct {
|
||||
Part *types.Part
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *BlockPartMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if err := m.Part.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("Wrong Part: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *BlockPartMessage) String() string {
|
||||
return fmt.Sprintf("[BlockPart H:%v R:%v P:%v]", m.Height, m.Round, m.Part)
|
||||
@@ -1442,6 +1536,11 @@ type VoteMessage struct {
|
||||
Vote *types.Vote
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *VoteMessage) ValidateBasic() error {
|
||||
return m.Vote.ValidateBasic()
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *VoteMessage) String() string {
|
||||
return fmt.Sprintf("[Vote %v]", m.Vote)
|
||||
@@ -1457,6 +1556,23 @@ type HasVoteMessage struct {
|
||||
Index int
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *HasVoteMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if !types.IsVoteTypeValid(m.Type) {
|
||||
return errors.New("Invalid Type")
|
||||
}
|
||||
if m.Index < 0 {
|
||||
return errors.New("Negative Index")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *HasVoteMessage) String() string {
|
||||
return fmt.Sprintf("[HasVote VI:%v V:{%v/%02d/%v}]", m.Index, m.Height, m.Round, m.Type)
|
||||
@@ -1472,6 +1588,23 @@ type VoteSetMaj23Message struct {
|
||||
BlockID types.BlockID
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *VoteSetMaj23Message) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if !types.IsVoteTypeValid(m.Type) {
|
||||
return errors.New("Invalid Type")
|
||||
}
|
||||
if err := m.BlockID.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("Wrong BlockID: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *VoteSetMaj23Message) String() string {
|
||||
return fmt.Sprintf("[VSM23 %v/%02d/%v %v]", m.Height, m.Round, m.Type, m.BlockID)
|
||||
@@ -1488,6 +1621,24 @@ type VoteSetBitsMessage struct {
|
||||
Votes *cmn.BitArray
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *VoteSetBitsMessage) ValidateBasic() error {
|
||||
if m.Height < 0 {
|
||||
return errors.New("Negative Height")
|
||||
}
|
||||
if m.Round < 0 {
|
||||
return errors.New("Negative Round")
|
||||
}
|
||||
if !types.IsVoteTypeValid(m.Type) {
|
||||
return errors.New("Invalid Type")
|
||||
}
|
||||
if err := m.BlockID.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("Wrong BlockID: %v", err)
|
||||
}
|
||||
// NOTE: Votes.Size() can be zero if the node does not have any
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *VoteSetBitsMessage) String() string {
|
||||
return fmt.Sprintf("[VSB %v/%02d/%v %v %v]", m.Height, m.Round, m.Type, m.BlockID, m.Votes)
|
||||
@@ -1500,6 +1651,11 @@ type ProposalHeartbeatMessage struct {
|
||||
Heartbeat *types.Heartbeat
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *ProposalHeartbeatMessage) ValidateBasic() error {
|
||||
return m.Heartbeat.ValidateBasic()
|
||||
}
|
||||
|
||||
// String returns a string representation.
|
||||
func (m *ProposalHeartbeatMessage) String() string {
|
||||
return fmt.Sprintf("[HEARTBEAT %v]", m.Heartbeat)
|
||||
|
||||
+17
-7
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
//auto "github.com/tendermint/tendermint/libs/autofile"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
@@ -19,7 +20,6 @@ import (
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
var crc32c = crc32.MakeTable(crc32.Castagnoli)
|
||||
@@ -73,7 +73,7 @@ func (cs *ConsensusState) readReplayMessage(msg *TimedWALMessage, newStepCh chan
|
||||
case *ProposalMessage:
|
||||
p := msg.Proposal
|
||||
cs.Logger.Info("Replay: Proposal", "height", p.Height, "round", p.Round, "header",
|
||||
p.BlockPartsHeader, "pol", p.POLRound, "peer", peerID)
|
||||
p.BlockID.PartsHeader, "pol", p.POLRound, "peer", peerID)
|
||||
case *BlockPartMessage:
|
||||
cs.Logger.Info("Replay: BlockPart", "height", msg.Height, "round", msg.Round, "peer", peerID)
|
||||
case *VoteMessage:
|
||||
@@ -227,7 +227,7 @@ func (h *Handshaker) NBlocks() int {
|
||||
func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
|
||||
|
||||
// Handshake is done via ABCI Info on the query conn.
|
||||
res, err := proxyApp.Query().InfoSync(abci.RequestInfo{Version: version.Version})
|
||||
res, err := proxyApp.Query().InfoSync(proxy.RequestInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error calling Info: %v", err)
|
||||
}
|
||||
@@ -238,9 +238,15 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
|
||||
}
|
||||
appHash := res.LastBlockAppHash
|
||||
|
||||
h.logger.Info("ABCI Handshake", "appHeight", blockHeight, "appHash", fmt.Sprintf("%X", appHash))
|
||||
h.logger.Info("ABCI Handshake App Info",
|
||||
"height", blockHeight,
|
||||
"hash", fmt.Sprintf("%X", appHash),
|
||||
"software-version", res.Version,
|
||||
"protocol-version", res.AppVersion,
|
||||
)
|
||||
|
||||
// TODO: check app version.
|
||||
// Set AppVersion on the state.
|
||||
h.initialState.Version.Consensus.App = version.Protocol(res.AppVersion)
|
||||
|
||||
// Replay blocks up to the latest in the blockstore.
|
||||
_, err = h.ReplayBlocks(h.initialState, appHash, blockHeight, proxyApp)
|
||||
@@ -258,8 +264,12 @@ func (h *Handshaker) Handshake(proxyApp proxy.AppConns) error {
|
||||
|
||||
// Replay all blocks since appBlockHeight and ensure the result matches the current state.
|
||||
// Returns the final AppHash or an error.
|
||||
func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight int64, proxyApp proxy.AppConns) ([]byte, error) {
|
||||
|
||||
func (h *Handshaker) ReplayBlocks(
|
||||
state sm.State,
|
||||
appHash []byte,
|
||||
appBlockHeight int64,
|
||||
proxyApp proxy.AppConns,
|
||||
) ([]byte, error) {
|
||||
storeBlockHeight := h.store.Height()
|
||||
stateBlockHeight := state.LastBlockHeight
|
||||
h.logger.Info("ABCI Replay Blocks", "appHeight", appBlockHeight, "storeHeight", storeBlockHeight, "stateHeight", stateBlockHeight)
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
crypto "github.com/tendermint/tendermint/crypto"
|
||||
auto "github.com/tendermint/tendermint/libs/autofile"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -337,7 +338,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey())
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), kvstore.ProtocolVersion)
|
||||
store.chain = chain
|
||||
store.commits = commits
|
||||
|
||||
@@ -352,7 +353,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
||||
// run nBlocks against a new client to build up the app state.
|
||||
// use a throwaway tendermint state
|
||||
proxyApp := proxy.NewAppConns(clientCreator2)
|
||||
stateDB, state, _ := stateAndStore(config, privVal.GetPubKey())
|
||||
stateDB, state, _ := stateAndStore(config, privVal.GetPubKey(), kvstore.ProtocolVersion)
|
||||
buildAppStateFromChain(proxyApp, stateDB, state, chain, nBlocks, mode)
|
||||
}
|
||||
|
||||
@@ -442,7 +443,7 @@ func buildAppStateFromChain(proxyApp proxy.AppConns, stateDB dbm.DB,
|
||||
func buildTMStateFromChain(config *cfg.Config, stateDB dbm.DB, state sm.State, chain []*types.Block, mode uint) sm.State {
|
||||
// run the whole chain against this client to build up the tendermint state
|
||||
clientCreator := proxy.NewLocalClientCreator(kvstore.NewPersistentKVStoreApplication(path.Join(config.DBDir(), "1")))
|
||||
proxyApp := proxy.NewAppConns(clientCreator) // sm.NewHandshaker(config, state, store, ReplayLastBlock))
|
||||
proxyApp := proxy.NewAppConns(clientCreator)
|
||||
if err := proxyApp.Start(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -519,7 +520,7 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
||||
// if its not the first one, we have a full block
|
||||
if thisBlockParts != nil {
|
||||
var block = new(types.Block)
|
||||
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(thisBlockParts.GetReader(), block, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -552,7 +553,7 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
||||
}
|
||||
// grab the last block too
|
||||
var block = new(types.Block)
|
||||
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(thisBlockParts.GetReader(), block, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -574,7 +575,7 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} {
|
||||
case msgInfo:
|
||||
switch msg := m.Msg.(type) {
|
||||
case *ProposalMessage:
|
||||
return &msg.Proposal.BlockPartsHeader
|
||||
return &msg.Proposal.BlockID.PartsHeader
|
||||
case *BlockPartMessage:
|
||||
return msg.Part
|
||||
case *VoteMessage:
|
||||
@@ -588,9 +589,10 @@ func readPieceFromWAL(msg *TimedWALMessage) interface{} {
|
||||
}
|
||||
|
||||
// fresh state and mock store
|
||||
func stateAndStore(config *cfg.Config, pubKey crypto.PubKey) (dbm.DB, sm.State, *mockBlockStore) {
|
||||
func stateAndStore(config *cfg.Config, pubKey crypto.PubKey, appVersion version.Protocol) (dbm.DB, sm.State, *mockBlockStore) {
|
||||
stateDB := dbm.NewMemDB()
|
||||
state, _ := sm.MakeGenesisStateFromFile(config.GenesisFile())
|
||||
state.Version.Consensus.App = appVersion
|
||||
store := NewMockBlockStore(config, state.ConsensusParams)
|
||||
return stateDB, state, store
|
||||
}
|
||||
@@ -639,7 +641,7 @@ func TestInitChainUpdateValidators(t *testing.T) {
|
||||
|
||||
config := ResetConfig("proxy_test_")
|
||||
privVal := privval.LoadFilePV(config.PrivValidatorFile())
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey())
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), 0x0)
|
||||
|
||||
oldValAddr := state.Validators.Validators[0].Address
|
||||
|
||||
|
||||
+37
-37
@@ -9,8 +9,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
fail "github.com/ebuchman/fail-test"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/fail"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
@@ -901,15 +901,9 @@ func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
|
||||
}
|
||||
|
||||
// Make proposal
|
||||
polRound, polBlockID := cs.Votes.POLInfo()
|
||||
proposal := types.NewProposal(height, round, blockParts.Header(), polRound, polBlockID)
|
||||
propBlockId := types.BlockID{block.Hash(), blockParts.Header()}
|
||||
proposal := types.NewProposal(height, round, cs.ValidRound, propBlockId)
|
||||
if err := cs.privValidator.SignProposal(cs.state.ChainID, proposal); err == nil {
|
||||
// Set fields
|
||||
/* fields set by setProposal and addBlockPart
|
||||
cs.Proposal = proposal
|
||||
cs.ProposalBlock = block
|
||||
cs.ProposalBlockParts = blockParts
|
||||
*/
|
||||
|
||||
// send proposal and block parts on internal msg queue
|
||||
cs.sendInternalMessage(msgInfo{&ProposalMessage{proposal}, ""})
|
||||
@@ -994,14 +988,6 @@ func (cs *ConsensusState) enterPrevote(height int64, round int) {
|
||||
cs.newStep()
|
||||
}()
|
||||
|
||||
// fire event for how we got here
|
||||
if cs.isProposalComplete() {
|
||||
cs.eventBus.PublishEventCompleteProposal(cs.RoundStateEvent())
|
||||
} else {
|
||||
// we received +2/3 prevotes for a future round
|
||||
// TODO: catchup event?
|
||||
}
|
||||
|
||||
cs.Logger.Info(fmt.Sprintf("enterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||
|
||||
// Sign and broadcast vote as necessary
|
||||
@@ -1240,6 +1226,8 @@ func (cs *ConsensusState) enterCommit(height int64, commitRound int) {
|
||||
// Set up ProposalBlockParts and keep waiting.
|
||||
cs.ProposalBlock = nil
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
|
||||
cs.eventBus.PublishEventValidBlock(cs.RoundStateEvent())
|
||||
cs.evsw.FireEvent(types.EventValidBlock, &cs.RoundState)
|
||||
} else {
|
||||
// We just need to keep waiting.
|
||||
}
|
||||
@@ -1420,14 +1408,9 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't care about the proposal if we're already in cstypes.RoundStepCommit.
|
||||
if cstypes.RoundStepCommit <= cs.Step {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify POLRound, which must be -1 or between 0 and proposal.Round exclusive.
|
||||
if proposal.POLRound != -1 &&
|
||||
(proposal.POLRound < 0 || proposal.Round <= proposal.POLRound) {
|
||||
// Verify POLRound, which must be -1 or in range [0, proposal.Round).
|
||||
if proposal.POLRound < -1 ||
|
||||
(proposal.POLRound >= 0 && proposal.POLRound >= proposal.Round) {
|
||||
return ErrInvalidProposalPOLRound
|
||||
}
|
||||
|
||||
@@ -1437,7 +1420,12 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
|
||||
}
|
||||
|
||||
cs.Proposal = proposal
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(proposal.BlockPartsHeader)
|
||||
// We don't update cs.ProposalBlockParts if it is already set.
|
||||
// This happens if we're already in cstypes.RoundStepCommit or if there is a valid block in the current round.
|
||||
// TODO: We can check if Proposal is for a different block as this is a sign of misbehavior!
|
||||
if cs.ProposalBlockParts == nil {
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(proposal.BlockID.PartsHeader)
|
||||
}
|
||||
cs.Logger.Info("Received proposal", "proposal", proposal)
|
||||
return nil
|
||||
}
|
||||
@@ -1468,7 +1456,7 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p
|
||||
}
|
||||
if added && cs.ProposalBlockParts.IsComplete() {
|
||||
// Added and completed!
|
||||
_, err = cdc.UnmarshalBinaryReader(
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(
|
||||
cs.ProposalBlockParts.GetReader(),
|
||||
&cs.ProposalBlock,
|
||||
int64(cs.state.ConsensusParams.BlockSize.MaxBytes),
|
||||
@@ -1478,6 +1466,7 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p
|
||||
}
|
||||
// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
|
||||
cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
|
||||
cs.eventBus.PublishEventCompleteProposal(cs.RoundStateEvent())
|
||||
|
||||
// Update Valid* if we can.
|
||||
prevotes := cs.Votes.Prevotes(cs.Round)
|
||||
@@ -1616,16 +1605,26 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
||||
|
||||
// Update Valid* if we can.
|
||||
// NOTE: our proposal block may be nil or not what received a polka..
|
||||
// TODO: we may want to still update the ValidBlock and obtain it via gossipping
|
||||
if len(blockID.Hash) != 0 &&
|
||||
(cs.ValidRound < vote.Round) &&
|
||||
(vote.Round <= cs.Round) &&
|
||||
cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||
if len(blockID.Hash) != 0 && (cs.ValidRound < vote.Round) && (vote.Round == cs.Round) {
|
||||
|
||||
cs.Logger.Info("Updating ValidBlock because of POL.", "validRound", cs.ValidRound, "POLRound", vote.Round)
|
||||
cs.ValidRound = vote.Round
|
||||
cs.ValidBlock = cs.ProposalBlock
|
||||
cs.ValidBlockParts = cs.ProposalBlockParts
|
||||
if cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||
cs.Logger.Info(
|
||||
"Updating ValidBlock because of POL.", "validRound", cs.ValidRound, "POLRound", vote.Round)
|
||||
cs.ValidRound = vote.Round
|
||||
cs.ValidBlock = cs.ProposalBlock
|
||||
cs.ValidBlockParts = cs.ProposalBlockParts
|
||||
} else {
|
||||
cs.Logger.Info(
|
||||
"Valid block we don't know about. Set ProposalBlock=nil",
|
||||
"proposal", cs.ProposalBlock.Hash(), "blockId", blockID.Hash)
|
||||
// We're getting the wrong block.
|
||||
cs.ProposalBlock = nil
|
||||
}
|
||||
if !cs.ProposalBlockParts.HasHeader(blockID.PartsHeader) {
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
|
||||
}
|
||||
cs.evsw.FireEvent(types.EventValidBlock, &cs.RoundState)
|
||||
cs.eventBus.PublishEventValidBlock(cs.RoundStateEvent())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1634,7 +1633,8 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
||||
// Round-skip if there is any 2/3+ of votes ahead of us
|
||||
cs.enterNewRound(height, vote.Round)
|
||||
} else if cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step { // current round
|
||||
if prevotes.HasTwoThirdsMajority() {
|
||||
blockID, ok := prevotes.TwoThirdsMajority()
|
||||
if ok && (cs.isProposalComplete() || len(blockID.Hash) == 0) {
|
||||
cs.enterPrecommit(height, vote.Round)
|
||||
} else if prevotes.HasTwoThirdsAny() {
|
||||
cs.enterPrevoteWait(height, vote.Round)
|
||||
|
||||
+193
-4
@@ -197,7 +197,9 @@ func TestStateBadProposal(t *testing.T) {
|
||||
stateHash[0] = byte((stateHash[0] + 1) % 255)
|
||||
propBlock.AppHash = stateHash
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
proposal := types.NewProposal(vs2.Height, round, propBlockParts.Header(), -1, types.BlockID{})
|
||||
proposal := types.NewProposal(
|
||||
vs2.Height, round, -1,
|
||||
types.BlockID{propBlock.Hash(), propBlockParts.Header()})
|
||||
if err := vs2.SignProposal(config.ChainID(), proposal); err != nil {
|
||||
t.Fatal("failed to sign bad proposal", err)
|
||||
}
|
||||
@@ -811,6 +813,7 @@ func TestStateLockPOLSafety2(t *testing.T) {
|
||||
_, propBlock0 := decideProposal(cs1, vss[0], height, round)
|
||||
propBlockHash0 := propBlock0.Hash()
|
||||
propBlockParts0 := propBlock0.MakePartSet(partSize)
|
||||
propBlockID0 := types.BlockID{propBlockHash0, propBlockParts0.Header()}
|
||||
|
||||
// the others sign a polka but we don't see it
|
||||
prevotes := signVotes(types.PrevoteType, propBlockHash0, propBlockParts0.Header(), vs2, vs3, vs4)
|
||||
@@ -819,7 +822,6 @@ func TestStateLockPOLSafety2(t *testing.T) {
|
||||
prop1, propBlock1 := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
|
||||
propBlockHash1 := propBlock1.Hash()
|
||||
propBlockParts1 := propBlock1.MakePartSet(partSize)
|
||||
propBlockID1 := types.BlockID{propBlockHash1, propBlockParts1.Header()}
|
||||
|
||||
incrementRound(vs2, vs3, vs4)
|
||||
|
||||
@@ -854,7 +856,7 @@ func TestStateLockPOLSafety2(t *testing.T) {
|
||||
|
||||
round = round + 1 // moving to the next round
|
||||
// in round 2 we see the polkad block from round 0
|
||||
newProp := types.NewProposal(height, round, propBlockParts0.Header(), 0, propBlockID1)
|
||||
newProp := types.NewProposal(height, round, 0, propBlockID0)
|
||||
if err := vs3.SignProposal(config.ChainID(), newProp); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -909,7 +911,7 @@ func TestProposeValidBlock(t *testing.T) {
|
||||
ensurePrevote(voteCh, height, round)
|
||||
validatePrevote(t, cs1, round, vss[0], propBlockHash)
|
||||
|
||||
// the others sign a polka but we don't see it
|
||||
// the others sign a polka
|
||||
signAddVotes(cs1, types.PrevoteType, propBlockHash, propBlock.MakePartSet(partSize).Header(), vs2, vs3, vs4)
|
||||
|
||||
ensurePrecommit(voteCh, height, round)
|
||||
@@ -964,6 +966,119 @@ func TestProposeValidBlock(t *testing.T) {
|
||||
rs = cs1.GetRoundState()
|
||||
assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), propBlockHash))
|
||||
assert.True(t, bytes.Equal(rs.ProposalBlock.Hash(), rs.ValidBlock.Hash()))
|
||||
assert.True(t, rs.Proposal.POLRound == rs.ValidRound)
|
||||
assert.True(t, bytes.Equal(rs.Proposal.BlockID.Hash, rs.ValidBlock.Hash()))
|
||||
}
|
||||
|
||||
// What we want:
|
||||
// P0 miss to lock B but set valid block to B after receiving delayed prevote.
|
||||
func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
|
||||
cs1, vss := randConsensusState(4)
|
||||
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
partSize := types.BlockPartSizeBytes
|
||||
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
|
||||
// start round and wait for propose and prevote
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
rs := cs1.GetRoundState()
|
||||
propBlock := rs.ProposalBlock
|
||||
propBlockHash := propBlock.Hash()
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
|
||||
ensurePrevote(voteCh, height, round)
|
||||
validatePrevote(t, cs1, round, vss[0], propBlockHash)
|
||||
|
||||
// vs2 send prevote for propBlock
|
||||
signAddVotes(cs1, types.PrevoteType, propBlockHash, propBlockParts.Header(), vs2)
|
||||
|
||||
// vs3 send prevote nil
|
||||
signAddVotes(cs1, types.PrevoteType, nil, types.PartSetHeader{}, vs3)
|
||||
|
||||
ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.TimeoutPrevote.Nanoseconds())
|
||||
|
||||
ensurePrecommit(voteCh, height, round)
|
||||
// we should have precommitted
|
||||
validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
|
||||
|
||||
rs = cs1.GetRoundState()
|
||||
|
||||
assert.True(t, rs.ValidBlock == nil)
|
||||
assert.True(t, rs.ValidBlockParts == nil)
|
||||
assert.True(t, rs.ValidRound == -1)
|
||||
|
||||
// vs2 send (delayed) prevote for propBlock
|
||||
signAddVotes(cs1, types.PrevoteType, propBlockHash, propBlockParts.Header(), vs4)
|
||||
|
||||
ensureNewValidBlock(validBlockCh, height, round)
|
||||
|
||||
rs = cs1.GetRoundState()
|
||||
|
||||
assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.ValidRound == round)
|
||||
}
|
||||
|
||||
// What we want:
|
||||
// P0 miss to lock B as Proposal Block is missing, but set valid block to B after
|
||||
// receiving delayed Block Proposal.
|
||||
func TestSetValidBlockOnDelayedProposal(t *testing.T) {
|
||||
cs1, vss := randConsensusState(4)
|
||||
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
|
||||
height, round := cs1.Height, cs1.Round
|
||||
|
||||
partSize := types.BlockPartSizeBytes
|
||||
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
|
||||
round = round + 1 // move to round in which P0 is not proposer
|
||||
incrementRound(vs2, vs3, vs4)
|
||||
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
|
||||
ensureNewTimeout(timeoutProposeCh, height, round, cs1.config.TimeoutPropose.Nanoseconds())
|
||||
|
||||
ensurePrevote(voteCh, height, round)
|
||||
validatePrevote(t, cs1, round, vss[0], nil)
|
||||
|
||||
prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round+1)
|
||||
propBlockHash := propBlock.Hash()
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
|
||||
// vs2, vs3 and vs4 send prevote for propBlock
|
||||
signAddVotes(cs1, types.PrevoteType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
|
||||
ensureNewValidBlock(validBlockCh, height, round)
|
||||
|
||||
ensureNewTimeout(timeoutWaitCh, height, round, cs1.config.TimeoutPrevote.Nanoseconds())
|
||||
|
||||
ensurePrecommit(voteCh, height, round)
|
||||
validatePrecommit(t, cs1, round, -1, vss[0], nil, nil)
|
||||
|
||||
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
rs := cs1.GetRoundState()
|
||||
|
||||
assert.True(t, bytes.Equal(rs.ValidBlock.Hash(), propBlockHash))
|
||||
assert.True(t, rs.ValidBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
assert.True(t, rs.ValidRound == round)
|
||||
}
|
||||
|
||||
// 4 vals, 3 Nil Precommits at P0
|
||||
@@ -1078,6 +1193,80 @@ func TestWaitTimeoutProposeOnNilPolkaForTheCurrentRound(t *testing.T) {
|
||||
validatePrevote(t, cs1, round, vss[0], nil)
|
||||
}
|
||||
|
||||
// What we want:
|
||||
// P0 emit NewValidBlock event upon receiving 2/3+ Precommit for B but hasn't received block B yet
|
||||
func TestEmitNewValidBlockEventOnCommitWithoutBlock(t *testing.T) {
|
||||
cs1, vss := randConsensusState(4)
|
||||
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
|
||||
height, round := cs1.Height, 1
|
||||
|
||||
incrementRound(vs2, vs3, vs4)
|
||||
|
||||
partSize := types.BlockPartSizeBytes
|
||||
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
|
||||
_, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round)
|
||||
propBlockHash := propBlock.Hash()
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
|
||||
// start round in which PO is not proposer
|
||||
startTestRound(cs1, height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
|
||||
// vs2, vs3 and vs4 send precommit for propBlock
|
||||
signAddVotes(cs1, types.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
|
||||
ensureNewValidBlock(validBlockCh, height, round)
|
||||
|
||||
rs := cs1.GetRoundState()
|
||||
assert.True(t, rs.Step == cstypes.RoundStepCommit)
|
||||
assert.True(t, rs.ProposalBlock == nil)
|
||||
assert.True(t, rs.ProposalBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
|
||||
}
|
||||
|
||||
// What we want:
|
||||
// P0 receives 2/3+ Precommit for B for round 0, while being in round 1. It emits NewValidBlock event.
|
||||
// After receiving block, it executes block and moves to the next height.
|
||||
func TestCommitFromPreviousRound(t *testing.T) {
|
||||
cs1, vss := randConsensusState(4)
|
||||
vs2, vs3, vs4 := vss[1], vss[2], vss[3]
|
||||
height, round := cs1.Height, 1
|
||||
|
||||
partSize := types.BlockPartSizeBytes
|
||||
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
|
||||
prop, propBlock := decideProposal(cs1, vs2, vs2.Height, vs2.Round)
|
||||
propBlockHash := propBlock.Hash()
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
|
||||
// start round in which PO is not proposer
|
||||
startTestRound(cs1, height, round)
|
||||
ensureNewRound(newRoundCh, height, round)
|
||||
|
||||
// vs2, vs3 and vs4 send precommit for propBlock for the previous round
|
||||
signAddVotes(cs1, types.PrecommitType, propBlockHash, propBlockParts.Header(), vs2, vs3, vs4)
|
||||
|
||||
ensureNewValidBlock(validBlockCh, height, round)
|
||||
|
||||
rs := cs1.GetRoundState()
|
||||
assert.True(t, rs.Step == cstypes.RoundStepCommit)
|
||||
assert.True(t, rs.CommitRound == vs2.Round)
|
||||
assert.True(t, rs.ProposalBlock == nil)
|
||||
assert.True(t, rs.ProposalBlockParts.Header().Equals(propBlockParts.Header()))
|
||||
|
||||
if err := cs1.SetProposalAndBlock(prop, propBlock, propBlockParts, "some peer"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ensureNewProposal(proposalCh, height, round)
|
||||
ensureNewRound(newRoundCh, height+1, 0)
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
// SlashingSuite
|
||||
// TODO: Slashing
|
||||
|
||||
@@ -26,8 +26,15 @@ const (
|
||||
RoundStepPrecommitWait = RoundStepType(0x07) // Did receive any +2/3 precommits, start timeout
|
||||
RoundStepCommit = RoundStepType(0x08) // Entered commit state machine
|
||||
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
|
||||
|
||||
// NOTE: Update IsValid method if you change this!
|
||||
)
|
||||
|
||||
// IsValid returns true if the step is valid, false if unknown/undefined.
|
||||
func (rs RoundStepType) IsValid() bool {
|
||||
return uint8(rs) >= 0x01 && uint8(rs) <= 0x08
|
||||
}
|
||||
|
||||
// String returns a string
|
||||
func (rs RoundStepType) String() string {
|
||||
switch rs {
|
||||
|
||||
@@ -63,11 +63,8 @@ func BenchmarkRoundStateDeepCopy(b *testing.B) {
|
||||
// Random Proposal
|
||||
proposal := &types.Proposal{
|
||||
Timestamp: tmtime.Now(),
|
||||
BlockPartsHeader: types.PartSetHeader{
|
||||
Hash: cmn.RandBytes(20),
|
||||
},
|
||||
POLBlockID: blockID,
|
||||
Signature: sig,
|
||||
BlockID: blockID,
|
||||
Signature: sig,
|
||||
}
|
||||
// Random HeightVoteSet
|
||||
// TODO: hvs :=
|
||||
|
||||
@@ -38,7 +38,8 @@ func WALGenerateNBlocks(wr io.Writer, numBlocks int) (err error) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// COPY PASTE FROM node.go WITH A FEW MODIFICATIONS
|
||||
// NOTE: we can't import node package because of circular dependency
|
||||
// NOTE: we can't import node package because of circular dependency.
|
||||
// NOTE: we don't do handshake so need to set state.Version.Consensus.App directly.
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
privValidator := privval.LoadOrGenFilePV(privValidatorFile)
|
||||
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
|
||||
@@ -51,6 +52,7 @@ func WALGenerateNBlocks(wr io.Writer, numBlocks int) (err error) {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to make genesis state")
|
||||
}
|
||||
state.Version.Consensus.App = kvstore.ProtocolVersion
|
||||
blockStore := bc.NewBlockStore(blockStoreDB)
|
||||
proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app))
|
||||
proxyApp.SetLogger(logger.With("module", "proxy"))
|
||||
|
||||
+16
-6
@@ -1,21 +1,24 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
type PrivKey interface {
|
||||
Bytes() []byte
|
||||
Sign(msg []byte) ([]byte, error)
|
||||
PubKey() PubKey
|
||||
Equals(PrivKey) bool
|
||||
}
|
||||
const (
|
||||
// AddressSize is the size of a pubkey address.
|
||||
AddressSize = tmhash.TruncatedSize
|
||||
)
|
||||
|
||||
// An address is a []byte, but hex-encoded even in JSON.
|
||||
// []byte leaves us the option to change the address length.
|
||||
// Use an alias so Unmarshal methods (with ptr receivers) are available too.
|
||||
type Address = cmn.HexBytes
|
||||
|
||||
func AddressHash(bz []byte) Address {
|
||||
return Address(tmhash.SumTruncated(bz))
|
||||
}
|
||||
|
||||
type PubKey interface {
|
||||
Address() Address
|
||||
Bytes() []byte
|
||||
@@ -23,6 +26,13 @@ type PubKey interface {
|
||||
Equals(PubKey) bool
|
||||
}
|
||||
|
||||
type PrivKey interface {
|
||||
Bytes() []byte
|
||||
Sign(msg []byte) ([]byte, error)
|
||||
PubKey() PubKey
|
||||
Equals(PrivKey) bool
|
||||
}
|
||||
|
||||
type Symmetric interface {
|
||||
Keygen() []byte
|
||||
Encrypt(plaintext []byte, secret []byte) (ciphertext []byte)
|
||||
|
||||
@@ -136,7 +136,7 @@ type PubKeyEd25519 [PubKeyEd25519Size]byte
|
||||
|
||||
// Address is the SHA256-20 of the raw pubkey bytes.
|
||||
func (pubKey PubKeyEd25519) Address() crypto.Address {
|
||||
return crypto.Address(tmhash.Sum(pubKey[:]))
|
||||
return crypto.Address(tmhash.SumTruncated(pubKey[:]))
|
||||
}
|
||||
|
||||
// Bytes marshals the PubKey using amino encoding.
|
||||
|
||||
@@ -43,10 +43,14 @@ func (poz ProofOperators) Verify(root []byte, keypath string, args [][]byte) (er
|
||||
for i, op := range poz {
|
||||
key := op.GetKey()
|
||||
if len(key) != 0 {
|
||||
if !bytes.Equal(keys[0], key) {
|
||||
return cmn.NewError("Key mismatch on operation #%d: expected %+v but %+v", i, []byte(keys[0]), []byte(key))
|
||||
if len(keys) == 0 {
|
||||
return cmn.NewError("Key path has insufficient # of parts: expected no more keys but got %+v", string(key))
|
||||
}
|
||||
keys = keys[1:]
|
||||
lastKey := keys[len(keys)-1]
|
||||
if !bytes.Equal(lastKey, key) {
|
||||
return cmn.NewError("Key mismatch on operation #%d: expected %+v but got %+v", i, string(lastKey), string(key))
|
||||
}
|
||||
keys = keys[:len(keys)-1]
|
||||
}
|
||||
args, err = op.Run(args)
|
||||
if err != nil {
|
||||
@@ -54,7 +58,7 @@ func (poz ProofOperators) Verify(root []byte, keypath string, args [][]byte) (er
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(root, args[0]) {
|
||||
return cmn.NewError("Calculated root hash is invalid: expected %+v but %+v", root, args[0])
|
||||
return cmn.NewError("Calculated root hash is invalid: expected %+v but got %+v", root, args[0])
|
||||
}
|
||||
if len(keys) != 0 {
|
||||
return cmn.NewError("Keypath not consumed all")
|
||||
|
||||
@@ -42,7 +42,7 @@ func SimpleValueOpDecoder(pop ProofOp) (ProofOperator, error) {
|
||||
return nil, cmn.NewError("unexpected ProofOp.Type; got %v, want %v", pop.Type, ProofOpSimpleValue)
|
||||
}
|
||||
var op SimpleValueOp // a bit strange as we'll discard this, but it works.
|
||||
err := cdc.UnmarshalBinary(pop.Data, &op)
|
||||
err := cdc.UnmarshalBinaryLengthPrefixed(pop.Data, &op)
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into SimpleValueOp")
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func SimpleValueOpDecoder(pop ProofOp) (ProofOperator, error) {
|
||||
}
|
||||
|
||||
func (op SimpleValueOp) ProofOp() ProofOp {
|
||||
bz := cdc.MustMarshalBinary(op)
|
||||
bz := cdc.MustMarshalBinaryLengthPrefixed(op)
|
||||
return ProofOp{
|
||||
Type: ProofOpSimpleValue,
|
||||
Key: op.key,
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package merkle
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
const ProofOpDomino = "test:domino"
|
||||
|
||||
// Expects given input, produces given output.
|
||||
// Like the game dominos.
|
||||
type DominoOp struct {
|
||||
key string // unexported, may be empty
|
||||
Input string
|
||||
Output string
|
||||
}
|
||||
|
||||
func NewDominoOp(key, input, output string) DominoOp {
|
||||
return DominoOp{
|
||||
key: key,
|
||||
Input: input,
|
||||
Output: output,
|
||||
}
|
||||
}
|
||||
|
||||
func DominoOpDecoder(pop ProofOp) (ProofOperator, error) {
|
||||
if pop.Type != ProofOpDomino {
|
||||
panic("unexpected proof op type")
|
||||
}
|
||||
var op DominoOp // a bit strange as we'll discard this, but it works.
|
||||
err := amino.UnmarshalBinaryLengthPrefixed(pop.Data, &op)
|
||||
if err != nil {
|
||||
return nil, cmn.ErrorWrap(err, "decoding ProofOp.Data into SimpleValueOp")
|
||||
}
|
||||
return NewDominoOp(string(pop.Key), op.Input, op.Output), nil
|
||||
}
|
||||
|
||||
func (dop DominoOp) ProofOp() ProofOp {
|
||||
bz := amino.MustMarshalBinaryLengthPrefixed(dop)
|
||||
return ProofOp{
|
||||
Type: ProofOpDomino,
|
||||
Key: []byte(dop.key),
|
||||
Data: bz,
|
||||
}
|
||||
}
|
||||
|
||||
func (dop DominoOp) Run(input [][]byte) (output [][]byte, err error) {
|
||||
if len(input) != 1 {
|
||||
return nil, cmn.NewError("Expected input of length 1")
|
||||
}
|
||||
if string(input[0]) != dop.Input {
|
||||
return nil, cmn.NewError("Expected input %v, got %v",
|
||||
dop.Input, string(input[0]))
|
||||
}
|
||||
return [][]byte{[]byte(dop.Output)}, nil
|
||||
}
|
||||
|
||||
func (dop DominoOp) GetKey() []byte {
|
||||
return []byte(dop.key)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func TestProofOperators(t *testing.T) {
|
||||
var err error
|
||||
|
||||
// ProofRuntime setup
|
||||
// TODO test this somehow.
|
||||
// prt := NewProofRuntime()
|
||||
// prt.RegisterOpDecoder(ProofOpDomino, DominoOpDecoder)
|
||||
|
||||
// ProofOperators setup
|
||||
op1 := NewDominoOp("KEY1", "INPUT1", "INPUT2")
|
||||
op2 := NewDominoOp("KEY2", "INPUT2", "INPUT3")
|
||||
op3 := NewDominoOp("", "INPUT3", "INPUT4")
|
||||
op4 := NewDominoOp("KEY4", "INPUT4", "OUTPUT4")
|
||||
|
||||
// Good
|
||||
popz := ProofOperators([]ProofOperator{op1, op2, op3, op4})
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.Nil(t, err)
|
||||
err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1"))
|
||||
assert.Nil(t, err)
|
||||
|
||||
// BAD INPUT
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1_WRONG")})
|
||||
assert.NotNil(t, err)
|
||||
err = popz.VerifyValue(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", bz("INPUT1_WRONG"))
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD KEY 1
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY3/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD KEY 2
|
||||
err = popz.Verify(bz("OUTPUT4"), "KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD KEY 3
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1/", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD KEY 4
|
||||
err = popz.Verify(bz("OUTPUT4"), "//KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD KEY 5
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD OUTPUT 1
|
||||
err = popz.Verify(bz("OUTPUT4_WRONG"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD OUTPUT 2
|
||||
err = popz.Verify(bz(""), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD POPZ 1
|
||||
popz = []ProofOperator{op1, op2, op4}
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD POPZ 2
|
||||
popz = []ProofOperator{op4, op3, op2, op1}
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// BAD POPZ 3
|
||||
popz = []ProofOperator{}
|
||||
err = popz.Verify(bz("OUTPUT4"), "/KEY4/KEY2/KEY1", [][]byte{bz("INPUT1")})
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func bz(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
@@ -13,14 +13,14 @@ func TestSimpleMap(t *testing.T) {
|
||||
values []string // each string gets converted to []byte in test
|
||||
want string
|
||||
}{
|
||||
{[]string{"key1"}, []string{"value1"}, "fa9bc106ffd932d919bee935ceb6cf2b3dd72d8f"},
|
||||
{[]string{"key1"}, []string{"value2"}, "e00e7dcfe54e9fafef5111e813a587f01ba9c3e8"},
|
||||
{[]string{"key1"}, []string{"value1"}, "321d150de16dceb51c72981b432b115045383259b1a550adf8dc80f927508967"},
|
||||
{[]string{"key1"}, []string{"value2"}, "2a9e4baf321eac99f6eecc3406603c14bc5e85bb7b80483cbfc75b3382d24a2f"},
|
||||
// swap order with 2 keys
|
||||
{[]string{"key1", "key2"}, []string{"value1", "value2"}, "eff12d1c703a1022ab509287c0f196130123d786"},
|
||||
{[]string{"key2", "key1"}, []string{"value2", "value1"}, "eff12d1c703a1022ab509287c0f196130123d786"},
|
||||
{[]string{"key1", "key2"}, []string{"value1", "value2"}, "c4d8913ab543ba26aa970646d4c99a150fd641298e3367cf68ca45fb45a49881"},
|
||||
{[]string{"key2", "key1"}, []string{"value2", "value1"}, "c4d8913ab543ba26aa970646d4c99a150fd641298e3367cf68ca45fb45a49881"},
|
||||
// swap order with 3 keys
|
||||
{[]string{"key1", "key2", "key3"}, []string{"value1", "value2", "value3"}, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26"},
|
||||
{[]string{"key1", "key3", "key2"}, []string{"value1", "value3", "value2"}, "b2c62a277c08dbd2ad73ca53cd1d6bfdf5830d26"},
|
||||
{[]string{"key1", "key2", "key3"}, []string{"value1", "value2", "value3"}, "b23cef00eda5af4548a213a43793f2752d8d9013b3f2b64bc0523a4791196268"},
|
||||
{[]string{"key1", "key3", "key2"}, []string{"value1", "value3", "value2"}, "b23cef00eda5af4548a213a43793f2752d8d9013b3f2b64bc0523a4791196268"},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
db := newSimpleMap()
|
||||
|
||||
+31
-11
@@ -9,10 +9,11 @@ import (
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
. "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// NOTE: This is ignored for now until we have time
|
||||
// to properly review the MixEntropy function - https://github.com/tendermint/tendermint/issues/2099.
|
||||
//
|
||||
// The randomness here is derived from xoring a chacha20 keystream with
|
||||
// output from crypto/rand's OS Entropy Reader. (Due to fears of the OS'
|
||||
// entropy being backdoored)
|
||||
@@ -23,9 +24,13 @@ var gRandInfo *randInfo
|
||||
|
||||
func init() {
|
||||
gRandInfo = &randInfo{}
|
||||
gRandInfo.MixEntropy(randBytes(32)) // Init
|
||||
|
||||
// TODO: uncomment after reviewing MixEntropy -
|
||||
// https://github.com/tendermint/tendermint/issues/2099
|
||||
// gRandInfo.MixEntropy(randBytes(32)) // Init
|
||||
}
|
||||
|
||||
// WARNING: This function needs review - https://github.com/tendermint/tendermint/issues/2099.
|
||||
// Mix additional bytes of randomness, e.g. from hardware, user-input, etc.
|
||||
// It is OK to call it multiple times. It does not diminish security.
|
||||
func MixEntropy(seedBytes []byte) {
|
||||
@@ -37,20 +42,28 @@ func randBytes(numBytes int) []byte {
|
||||
b := make([]byte, numBytes)
|
||||
_, err := crand.Read(b)
|
||||
if err != nil {
|
||||
PanicCrisis(err)
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// This only uses the OS's randomness
|
||||
func CRandBytes(numBytes int) []byte {
|
||||
return randBytes(numBytes)
|
||||
}
|
||||
|
||||
/* TODO: uncomment after reviewing MixEntropy - https://github.com/tendermint/tendermint/issues/2099
|
||||
// This uses the OS and the Seed(s).
|
||||
func CRandBytes(numBytes int) []byte {
|
||||
b := make([]byte, numBytes)
|
||||
_, err := gRandInfo.Read(b)
|
||||
if err != nil {
|
||||
PanicCrisis(err)
|
||||
}
|
||||
return b
|
||||
return randBytes(numBytes)
|
||||
b := make([]byte, numBytes)
|
||||
_, err := gRandInfo.Read(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
*/
|
||||
|
||||
// CRandHex returns a hex encoded string that's floor(numDigits/2) * 2 long.
|
||||
//
|
||||
@@ -60,10 +73,17 @@ func CRandHex(numDigits int) string {
|
||||
return hex.EncodeToString(CRandBytes(numDigits / 2))
|
||||
}
|
||||
|
||||
// Returns a crand.Reader.
|
||||
func CReader() io.Reader {
|
||||
return crand.Reader
|
||||
}
|
||||
|
||||
/* TODO: uncomment after reviewing MixEntropy - https://github.com/tendermint/tendermint/issues/2099
|
||||
// Returns a crand.Reader mixed with user-supplied entropy
|
||||
func CReader() io.Reader {
|
||||
return gRandInfo
|
||||
}
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
@@ -75,7 +95,7 @@ type randInfo struct {
|
||||
}
|
||||
|
||||
// You can call this as many times as you'd like.
|
||||
// XXX TODO review
|
||||
// XXX/TODO: review - https://github.com/tendermint/tendermint/issues/2099
|
||||
func (ri *randInfo) MixEntropy(seedBytes []byte) {
|
||||
ri.mtx.Lock()
|
||||
defer ri.mtx.Unlock()
|
||||
|
||||
+25
-8
@@ -6,10 +6,27 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
Size = 20
|
||||
Size = sha256.Size
|
||||
BlockSize = sha256.BlockSize
|
||||
)
|
||||
|
||||
// New returns a new hash.Hash.
|
||||
func New() hash.Hash {
|
||||
return sha256.New()
|
||||
}
|
||||
|
||||
// Sum returns the SHA256 of the bz.
|
||||
func Sum(bz []byte) []byte {
|
||||
h := sha256.Sum256(bz)
|
||||
return h[:]
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
|
||||
const (
|
||||
TruncatedSize = 20
|
||||
)
|
||||
|
||||
type sha256trunc struct {
|
||||
sha256 hash.Hash
|
||||
}
|
||||
@@ -19,7 +36,7 @@ func (h sha256trunc) Write(p []byte) (n int, err error) {
|
||||
}
|
||||
func (h sha256trunc) Sum(b []byte) []byte {
|
||||
shasum := h.sha256.Sum(b)
|
||||
return shasum[:Size]
|
||||
return shasum[:TruncatedSize]
|
||||
}
|
||||
|
||||
func (h sha256trunc) Reset() {
|
||||
@@ -27,22 +44,22 @@ func (h sha256trunc) Reset() {
|
||||
}
|
||||
|
||||
func (h sha256trunc) Size() int {
|
||||
return Size
|
||||
return TruncatedSize
|
||||
}
|
||||
|
||||
func (h sha256trunc) BlockSize() int {
|
||||
return h.sha256.BlockSize()
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash.
|
||||
func New() hash.Hash {
|
||||
// NewTruncated returns a new hash.Hash.
|
||||
func NewTruncated() hash.Hash {
|
||||
return sha256trunc{
|
||||
sha256: sha256.New(),
|
||||
}
|
||||
}
|
||||
|
||||
// Sum returns the first 20 bytes of SHA256 of the bz.
|
||||
func Sum(bz []byte) []byte {
|
||||
// SumTruncated returns the first 20 bytes of SHA256 of the bz.
|
||||
func SumTruncated(bz []byte) []byte {
|
||||
hash := sha256.Sum256(bz)
|
||||
return hash[:Size]
|
||||
return hash[:TruncatedSize]
|
||||
}
|
||||
|
||||
@@ -14,10 +14,29 @@ func TestHash(t *testing.T) {
|
||||
hasher.Write(testVector)
|
||||
bz := hasher.Sum(nil)
|
||||
|
||||
bz2 := tmhash.Sum(testVector)
|
||||
|
||||
hasher = sha256.New()
|
||||
hasher.Write(testVector)
|
||||
bz2 := hasher.Sum(nil)
|
||||
bz2 = bz2[:20]
|
||||
bz3 := hasher.Sum(nil)
|
||||
|
||||
assert.Equal(t, bz, bz2)
|
||||
assert.Equal(t, bz, bz3)
|
||||
}
|
||||
|
||||
func TestHashTruncated(t *testing.T) {
|
||||
testVector := []byte("abc")
|
||||
hasher := tmhash.NewTruncated()
|
||||
hasher.Write(testVector)
|
||||
bz := hasher.Sum(nil)
|
||||
|
||||
bz2 := tmhash.SumTruncated(testVector)
|
||||
|
||||
hasher = sha256.New()
|
||||
hasher.Write(testVector)
|
||||
bz3 := hasher.Sum(nil)
|
||||
bz3 = bz3[:tmhash.TruncatedSize]
|
||||
|
||||
assert.Equal(t, bz, bz2)
|
||||
assert.Equal(t, bz, bz3)
|
||||
}
|
||||
|
||||
@@ -163,6 +163,12 @@
|
||||
"language": "Python",
|
||||
"author": "Dave Bryson"
|
||||
},
|
||||
{
|
||||
"name": "tm-abci",
|
||||
"url": "https://github.com/SoftblocksCo/tm-abci",
|
||||
"language": "Python",
|
||||
"author": "Softblocks"
|
||||
},
|
||||
{
|
||||
"name": "Spearmint",
|
||||
"url": "https://github.com/dennismckinnon/spearmint",
|
||||
|
||||
@@ -52,13 +52,13 @@ On top of this interface, we will need to implement a stdout logger, which will
|
||||
Many people say that they like the current output, so let's stick with it.
|
||||
|
||||
```
|
||||
NOTE[04-25|14:45:08] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0
|
||||
NOTE[2017-04-25|14:45:08] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0
|
||||
```
|
||||
|
||||
Couple of minor changes:
|
||||
|
||||
```
|
||||
I[04-25|14:45:08.322] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0
|
||||
I[2017-04-25|14:45:08.322] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0
|
||||
```
|
||||
|
||||
Notice the level is encoded using only one char plus milliseconds.
|
||||
@@ -155,14 +155,14 @@ Important keyvals should go first. Example:
|
||||
|
||||
```
|
||||
correct
|
||||
I[04-25|14:45:08.322] ABCI Replay Blocks module=consensus instance=1 appHeight=0 storeHeight=0 stateHeight=0
|
||||
I[2017-04-25|14:45:08.322] ABCI Replay Blocks module=consensus instance=1 appHeight=0 storeHeight=0 stateHeight=0
|
||||
```
|
||||
|
||||
not
|
||||
|
||||
```
|
||||
wrong
|
||||
I[04-25|14:45:08.322] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 instance=1
|
||||
I[2017-04-25|14:45:08.322] ABCI Replay Blocks module=consensus appHeight=0 storeHeight=0 stateHeight=0 instance=1
|
||||
```
|
||||
|
||||
for that in most cases you'll need to add `instance` field to a logger upon creating, not when u log a particular message:
|
||||
|
||||
@@ -96,7 +96,7 @@ Each component of the software is independently versioned in a modular way and i
|
||||
|
||||
## Proposal
|
||||
|
||||
Each of BlockVersion, AppVersion, P2PVersion, is a monotonically increasing int64.
|
||||
Each of BlockVersion, AppVersion, P2PVersion, is a monotonically increasing uint64.
|
||||
|
||||
To use these versions, we need to update the block Header, the p2p NodeInfo, and the ABCI.
|
||||
|
||||
@@ -106,8 +106,8 @@ Block Header should include a `Version` struct as its first field like:
|
||||
|
||||
```
|
||||
type Version struct {
|
||||
Block int64
|
||||
App int64
|
||||
Block uint64
|
||||
App uint64
|
||||
}
|
||||
```
|
||||
|
||||
@@ -130,9 +130,9 @@ NodeInfo should include a Version struct as its first field like:
|
||||
|
||||
```
|
||||
type Version struct {
|
||||
P2P int64
|
||||
Block int64
|
||||
App int64
|
||||
P2P uint64
|
||||
Block uint64
|
||||
App uint64
|
||||
|
||||
Other []string
|
||||
}
|
||||
@@ -168,9 +168,9 @@ RequestInfo should add support for protocol versions like:
|
||||
|
||||
```
|
||||
message RequestInfo {
|
||||
string software_version
|
||||
int64 block_version
|
||||
int64 p2p_version
|
||||
string version
|
||||
uint64 block_version
|
||||
uint64 p2p_version
|
||||
}
|
||||
```
|
||||
|
||||
@@ -180,39 +180,46 @@ Similarly, ResponseInfo should return the versions:
|
||||
message ResponseInfo {
|
||||
string data
|
||||
|
||||
string software_version
|
||||
int64 app_version
|
||||
string version
|
||||
uint64 app_version
|
||||
|
||||
int64 last_block_height
|
||||
bytes last_block_app_hash
|
||||
}
|
||||
```
|
||||
|
||||
The existing `version` fields should be called `software_version` but we leave
|
||||
them for now to reduce the number of breaking changes.
|
||||
|
||||
#### EndBlock
|
||||
|
||||
Updating the version could be done either with new fields or by using the
|
||||
existing `tags`. Since we're trying to communicate information that will be
|
||||
included in Tendermint block Headers, it should be native to the ABCI, and not
|
||||
something embedded through some scheme in the tags.
|
||||
something embedded through some scheme in the tags. Thus, version updates should
|
||||
be communicated through EndBlock.
|
||||
|
||||
ResponseEndBlock will include a new field `version_updates`:
|
||||
EndBlock already contains `ConsensusParams`. We can add version information to
|
||||
the ConsensusParams as well:
|
||||
|
||||
```
|
||||
message ResponseEndBlock {
|
||||
repeated Validator validator_updates
|
||||
ConsensusParams consensus_param_updates
|
||||
repeated common.KVPair tags
|
||||
message ConsensusParams {
|
||||
|
||||
VersionUpdate version_update
|
||||
BlockSize block_size
|
||||
EvidenceParams evidence_params
|
||||
VersionParams version
|
||||
}
|
||||
|
||||
message VersionUpdate {
|
||||
int64 app_version
|
||||
message VersionParams {
|
||||
uint64 block_version
|
||||
uint64 app_version
|
||||
}
|
||||
```
|
||||
|
||||
Tendermint will use the information in VersionUpdate for the next block it
|
||||
proposes.
|
||||
For now, the `block_version` will be ignored, as we do not allow block version
|
||||
to be updated live. If the `app_version` is set, it signals that the app's
|
||||
protocol version has changed, and the new `app_version` will be included in the
|
||||
`Block.Header.Version.App` for the next block.
|
||||
|
||||
### BlockVersion
|
||||
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
# ADR 033: pubsub 2.0
|
||||
|
||||
Author: Anton Kaliaev (@melekes)
|
||||
|
||||
## Changelog
|
||||
|
||||
02-10-2018: Initial draft
|
||||
|
||||
## Context
|
||||
|
||||
Since the initial version of the pubsub, there's been a number of issues
|
||||
raised: #951, #1879, #1880. Some of them are high-level issues questioning the
|
||||
core design choices made. Others are minor and mostly about the interface of
|
||||
`Subscribe()` / `Publish()` functions.
|
||||
|
||||
### Sync vs Async
|
||||
|
||||
Now, when publishing a message to subscribers, we can do it in a goroutine:
|
||||
|
||||
_using channels for data transmission_
|
||||
```go
|
||||
for each subscriber {
|
||||
out := subscriber.outc
|
||||
go func() {
|
||||
out <- msg
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
_by invoking callback functions_
|
||||
```go
|
||||
for each subscriber {
|
||||
go subscriber.callbackFn()
|
||||
}
|
||||
```
|
||||
|
||||
This gives us greater performance and allows us to avoid "slow client problem"
|
||||
(when other subscribers have to wait for a slow subscriber). A pool of
|
||||
goroutines can be used to avoid uncontrolled memory growth.
|
||||
|
||||
In certain cases, this is what you want. But in our case, because we need
|
||||
strict ordering of events (if event A was published before B, the guaranteed
|
||||
delivery order will be A -> B), we can't use goroutines.
|
||||
|
||||
There is also a question whenever we should have a non-blocking send:
|
||||
|
||||
```go
|
||||
for each subscriber {
|
||||
out := subscriber.outc
|
||||
select {
|
||||
case out <- msg:
|
||||
default:
|
||||
log("subscriber %v buffer is full, skipping...")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This fixes the "slow client problem", but there is no way for a slow client to
|
||||
know if it had missed a message. On the other hand, if we're going to stick
|
||||
with blocking send, **devs must always ensure subscriber's handling code does not
|
||||
block**. As you can see, there is an implicit choice between ordering guarantees
|
||||
and using goroutines.
|
||||
|
||||
The interim option is to run goroutines pool for a single message, wait for all
|
||||
goroutines to finish. This will solve "slow client problem", but we'd still
|
||||
have to wait `max(goroutine_X_time)` before we can publish the next message.
|
||||
My opinion: not worth doing.
|
||||
|
||||
### Channels vs Callbacks
|
||||
|
||||
Yet another question is whether we should use channels for message transmission or
|
||||
call subscriber-defined callback functions. Callback functions give subscribers
|
||||
more flexibility - you can use mutexes in there, channels, spawn goroutines,
|
||||
anything you really want. But they also carry local scope, which can result in
|
||||
memory leaks and/or memory usage increase.
|
||||
|
||||
Go channels are de-facto standard for carrying data between goroutines.
|
||||
|
||||
**Question: Is it worth switching to callback functions?**
|
||||
|
||||
### Why `Subscribe()` accepts an `out` channel?
|
||||
|
||||
Because in our tests, we create buffered channels (cap: 1). Alternatively, we
|
||||
can make capacity an argument.
|
||||
|
||||
## Decision
|
||||
|
||||
Change Subscribe() function to return out channel:
|
||||
|
||||
```go
|
||||
// outCap can be used to set capacity of out channel (unbuffered by default).
|
||||
Subscribe(ctx context.Context, clientID string, query Query, outCap... int) (out <-chan interface{}, err error) {
|
||||
```
|
||||
|
||||
It's more idiomatic since we're closing it during Unsubscribe/UnsubscribeAll calls.
|
||||
|
||||
Also, we should make tags available to subscribers:
|
||||
|
||||
```go
|
||||
type MsgAndTags struct {
|
||||
Msg interface{}
|
||||
Tags TagMap
|
||||
}
|
||||
|
||||
// outCap can be used to set capacity of out channel (unbuffered by default).
|
||||
Subscribe(ctx context.Context, clientID string, query Query, outCap... int) (out <-chan MsgAndTags, err error) {
|
||||
```
|
||||
|
||||
## Status
|
||||
|
||||
In review
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- more idiomatic interface
|
||||
- subscribers know what tags msg was published with
|
||||
|
||||
### Negative
|
||||
|
||||
### Neutral
|
||||
@@ -1,5 +1,9 @@
|
||||
# ADR 000: Template for an ADR
|
||||
|
||||
Author:
|
||||
|
||||
## Changelog
|
||||
|
||||
## Context
|
||||
|
||||
## Decision
|
||||
|
||||
+16
-5
@@ -134,10 +134,13 @@ Commit are included in the header of the next block.
|
||||
### Info
|
||||
|
||||
- **Request**:
|
||||
- `Version (string)`: The Tendermint version
|
||||
- `Version (string)`: The Tendermint software semantic version
|
||||
- `BlockVersion (uint64)`: The Tendermint Block Protocol version
|
||||
- `P2PVersion (uint64)`: The Tendermint P2P Protocol version
|
||||
- **Response**:
|
||||
- `Data (string)`: Some arbitrary information
|
||||
- `Version (Version)`: Version information
|
||||
- `Version (string)`: The application software semantic version
|
||||
- `AppVersion (uint64)`: The application protocol version
|
||||
- `LastBlockHeight (int64)`: Latest block for which the app has
|
||||
called Commit
|
||||
- `LastBlockAppHash ([]byte)`: Latest result of Commit
|
||||
@@ -145,6 +148,7 @@ Commit are included in the header of the next block.
|
||||
- Return information about the application state.
|
||||
- Used to sync Tendermint with the application during a handshake
|
||||
that happens on startup.
|
||||
- The returned `AppVersion` will be included in the Header of every block.
|
||||
- Tendermint expects `LastBlockAppHash` and `LastBlockHeight` to
|
||||
be updated during `Commit`, ensuring that `Commit` is never
|
||||
called twice for the same block height.
|
||||
@@ -437,11 +441,12 @@ Commit are included in the header of the next block.
|
||||
### ConsensusParams
|
||||
|
||||
- **Fields**:
|
||||
- `BlockSize (BlockSize)`: Parameters limiting the size of a block.
|
||||
- `EvidenceParams (EvidenceParams)`: Parameters limiting the validity of
|
||||
- `BlockSize (BlockSizeParams)`: Parameters limiting the size of a block.
|
||||
- `Evidence (EvidenceParams)`: Parameters limiting the validity of
|
||||
evidence of byzantine behaviour.
|
||||
- `Validator (ValidatorParams)`: Parameters limitng the types of pubkeys validators can use.
|
||||
|
||||
### BlockSize
|
||||
### BlockSizeParams
|
||||
|
||||
- **Fields**:
|
||||
- `MaxBytes (int64)`: Max size of a block, in bytes.
|
||||
@@ -459,6 +464,12 @@ Commit are included in the header of the next block.
|
||||
similar mechanism for handling Nothing-At-Stake attacks.
|
||||
- NOTE: this should change to time (instead of blocks)!
|
||||
|
||||
### ValidatorParams
|
||||
|
||||
- **Fields**:
|
||||
- `PubKeyTypes ([]string)`: List of accepted pubkey types. Uses same
|
||||
naming as `PubKey.Type`.
|
||||
|
||||
### Proof
|
||||
|
||||
- **Fields**:
|
||||
|
||||
@@ -146,14 +146,14 @@ The vote includes information about the validator signing it.
|
||||
|
||||
```go
|
||||
type Vote struct {
|
||||
ValidatorAddress []byte
|
||||
ValidatorIndex int
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp Time
|
||||
Type int8
|
||||
BlockID BlockID
|
||||
Signature []byte
|
||||
Type SignedMsgType // byte
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp time.Time
|
||||
BlockID BlockID
|
||||
ValidatorAddress Address
|
||||
ValidatorIndex int
|
||||
Signature []byte
|
||||
}
|
||||
```
|
||||
|
||||
@@ -344,7 +344,7 @@ next validator sets Merkle root.
|
||||
### ConsensusParamsHash
|
||||
|
||||
```go
|
||||
block.ConsensusParamsHash == tmhash(amino(state.ConsensusParams))
|
||||
block.ConsensusParamsHash == TMHASH(amino(state.ConsensusParams))
|
||||
```
|
||||
|
||||
Hash of the amino-encoded consensus parameters.
|
||||
|
||||
@@ -176,13 +176,12 @@ greater, for example:
|
||||
h0 h1 h3 h4 h0 h1 h2 h3 h4 h5
|
||||
```
|
||||
|
||||
Tendermint always uses the `TMHASH` hash function, which is the first 20-bytes
|
||||
of the SHA256:
|
||||
Tendermint always uses the `TMHASH` hash function, which is equivalent to
|
||||
SHA256:
|
||||
|
||||
```
|
||||
func TMHASH(bz []byte) []byte {
|
||||
shasum := SHA256(bz)
|
||||
return shasum[:20]
|
||||
return SHA256(bz)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -216,7 +215,7 @@ prefix) before being concatenated together and hashed.
|
||||
|
||||
Note: we will abuse notion and invoke `SimpleMerkleRoot` with arguments of type `struct` or type `[]struct`.
|
||||
For `struct` arguments, we compute a `[][]byte` containing the hash of each
|
||||
field in the struct sorted by the hash of the field name.
|
||||
field in the struct, in the same order the fields appear in the struct.
|
||||
For `[]struct` arguments, we compute a `[][]byte` by hashing the individual `struct` elements.
|
||||
|
||||
### Simple Merkle Proof
|
||||
@@ -301,16 +300,15 @@ Where the `"value"` is the base64 encoding of the raw pubkey bytes, and the
|
||||
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino.
|
||||
|
||||
When signing, the elements of a message are re-ordered so the fixed-length fields
|
||||
are first, making it easy to quickly check the version, height, round, and type.
|
||||
are first, making it easy to quickly check the type, height, and round.
|
||||
The `ChainID` is also appended to the end.
|
||||
We call this encoding the SignBytes. For instance, SignBytes for a vote is the Amino encoding of the following struct:
|
||||
|
||||
```go
|
||||
type CanonicalVote struct {
|
||||
Version uint64 `binary:"fixed64"`
|
||||
Type byte
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
VoteType byte
|
||||
Timestamp time.Time
|
||||
BlockID CanonicalBlockID
|
||||
ChainID string
|
||||
|
||||
@@ -56,8 +56,8 @@ type Validator struct {
|
||||
}
|
||||
```
|
||||
|
||||
When hashing the Validator struct, the pubkey is not hashed,
|
||||
because the address is already the hash of the pubkey.
|
||||
When hashing the Validator struct, the address is not included,
|
||||
because it is redundant with the pubkey.
|
||||
|
||||
The `state.Validators`, `state.LastValidators`, and `state.NextValidators`, must always by sorted by validator address,
|
||||
so that there is a canonical order for computing the SimpleMerkleRoot.
|
||||
|
||||
@@ -129,13 +129,16 @@ handleMessage(msg):
|
||||
Reset prs.CatchupCommitRound and prs.CatchupCommit
|
||||
```
|
||||
|
||||
### CommitStepMessage handler
|
||||
### NewValidBlockMessage handler
|
||||
|
||||
```
|
||||
handleMessage(msg):
|
||||
if prs.Height == msg.Height then
|
||||
prs.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||
prs.ProposalBlockParts = msg.BlockParts
|
||||
if prs.Height != msg.Height then return
|
||||
|
||||
if prs.Round != msg.Round && !msg.IsCommit then return
|
||||
|
||||
prs.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||
prs.ProposalBlockParts = msg.BlockParts
|
||||
```
|
||||
|
||||
### HasVoteMessage handler
|
||||
@@ -161,8 +164,8 @@ handleMessage(msg):
|
||||
handleMessage(msg):
|
||||
if prs.Height != msg.Height || prs.Round != msg.Round || prs.Proposal then return
|
||||
prs.Proposal = true
|
||||
prs.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||
prs.ProposalBlockParts = empty set
|
||||
if prs.ProposalBlockParts == empty set then // otherwise it is set in NewValidBlockMessage handler
|
||||
prs.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||
prs.ProposalPOLRound = msg.POLRound
|
||||
prs.ProposalPOL = nil
|
||||
Send msg through internal peerMsgQueue to ConsensusState service
|
||||
|
||||
@@ -26,7 +26,7 @@ only to a subset of processes called peers. By the gossiping protocol, a validat
|
||||
all needed information (`ProposalMessage`, `VoteMessage` and `BlockPartMessage`) so they can
|
||||
reach agreement on some block, and also obtain the content of the chosen block (block parts). As
|
||||
part of the gossiping protocol, processes also send auxiliary messages that inform peers about the
|
||||
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `CommitStepMessage`), and
|
||||
executed steps of the core consensus algorithm (`NewRoundStepMessage` and `NewValidBlockMessage`), and
|
||||
also messages that inform peers what votes the process has seen (`HasVoteMessage`,
|
||||
`VoteSetMaj23Message` and `VoteSetBitsMessage`). These messages are then used in the gossiping
|
||||
protocol to determine what messages a process should send to its peers.
|
||||
@@ -47,25 +47,21 @@ type ProposalMessage struct {
|
||||
### Proposal
|
||||
|
||||
Proposal contains height and round for which this proposal is made, BlockID as a unique identifier
|
||||
of proposed block, timestamp, and two fields (POLRound and POLBlockID) that are needed for
|
||||
termination of the consensus. The message is signed by the validator private key.
|
||||
of proposed block, timestamp, and POLRound (a so-called Proof-of-Lock (POL) round) that is needed for
|
||||
termination of the consensus. If POLRound >= 0, then BlockID corresponds to the block that
|
||||
is locked in POLRound. The message is signed by the validator private key.
|
||||
|
||||
```go
|
||||
type Proposal struct {
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp Time
|
||||
BlockID BlockID
|
||||
POLRound int
|
||||
POLBlockID BlockID
|
||||
BlockID BlockID
|
||||
Timestamp Time
|
||||
Signature Signature
|
||||
}
|
||||
```
|
||||
|
||||
NOTE: In the current version of the Tendermint, the consensus value in proposal is represented with
|
||||
PartSetHeader, and with BlockID in vote message. It should be aligned as suggested in this spec as
|
||||
BlockID contains PartSetHeader.
|
||||
|
||||
## VoteMessage
|
||||
|
||||
VoteMessage is sent to vote for some block (or to inform others that a process does not vote in the
|
||||
@@ -136,23 +132,26 @@ type NewRoundStepMessage struct {
|
||||
}
|
||||
```
|
||||
|
||||
## CommitStepMessage
|
||||
## NewValidBlockMessage
|
||||
|
||||
CommitStepMessage is sent when an agreement on some block is reached. It contains height for which
|
||||
agreement is reached, block parts header that describes the decided block and is used to obtain all
|
||||
NewValidBlockMessage is sent when a validator observes a valid block B in some round r,
|
||||
i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in the round r.
|
||||
It contains height and round in which valid block is observed, block parts header that describes
|
||||
the valid block and is used to obtain all
|
||||
block parts, and a bit array of the block parts a process currently has, so its peers can know what
|
||||
parts it is missing so they can send them.
|
||||
In case the block is also committed, then IsCommit flag is set to true.
|
||||
|
||||
```go
|
||||
type CommitStepMessage struct {
|
||||
type NewValidBlockMessage struct {
|
||||
Height int64
|
||||
BlockID BlockID
|
||||
Round int
|
||||
BlockPartsHeader PartSetHeader
|
||||
BlockParts BitArray
|
||||
IsCommit bool
|
||||
}
|
||||
```
|
||||
|
||||
TODO: We use BlockID instead of BlockPartsHeader (in current implementation) for symmetry.
|
||||
|
||||
## ProposalPOLMessage
|
||||
|
||||
ProposalPOLMessage is sent when a previous block is re-proposed.
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ func (evpool *EvidencePool) MarkEvidenceAsCommitted(height int64, evidence []typ
|
||||
}
|
||||
|
||||
// remove committed evidence from the clist
|
||||
maxAge := evpool.State().ConsensusParams.EvidenceParams.MaxAge
|
||||
maxAge := evpool.State().ConsensusParams.Evidence.MaxAge
|
||||
evpool.removeEvidence(height, maxAge, blockEvidenceMap)
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
|
||||
NextValidators: valSet.CopyIncrementAccum(1),
|
||||
LastHeightValidatorsChanged: 1,
|
||||
ConsensusParams: types.ConsensusParams{
|
||||
EvidenceParams: types.EvidenceParams{
|
||||
Evidence: types.EvidenceParams{
|
||||
MaxAge: 1000000,
|
||||
},
|
||||
},
|
||||
|
||||
+22
-3
@@ -74,6 +74,13 @@ func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
evR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = msg.ValidateBasic(); err != nil {
|
||||
evR.Logger.Error("Peer sent us invalid msg", "peer", src, "msg", msg, "err", err)
|
||||
evR.Switch.StopPeerForError(src, err)
|
||||
return
|
||||
}
|
||||
|
||||
evR.Logger.Debug("Receive", "src", src, "chId", chID, "msg", msg)
|
||||
|
||||
switch msg := msg.(type) {
|
||||
@@ -164,7 +171,7 @@ func (evR EvidenceReactor) checkSendEvidenceMessage(peer p2p.Peer, ev types.Evid
|
||||
|
||||
// NOTE: We only send evidence to peers where
|
||||
// peerHeight - maxAge < evidenceHeight < peerHeight
|
||||
maxAge := evR.evpool.State().ConsensusParams.EvidenceParams.MaxAge
|
||||
maxAge := evR.evpool.State().ConsensusParams.Evidence.MaxAge
|
||||
peerHeight := peerState.GetHeight()
|
||||
if peerHeight < evHeight {
|
||||
// peer is behind. sleep while he catches up
|
||||
@@ -191,7 +198,9 @@ type PeerState interface {
|
||||
// Messages
|
||||
|
||||
// EvidenceMessage is a message sent or received by the EvidenceReactor.
|
||||
type EvidenceMessage interface{}
|
||||
type EvidenceMessage interface {
|
||||
ValidateBasic() error
|
||||
}
|
||||
|
||||
func RegisterEvidenceMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*EvidenceMessage)(nil), nil)
|
||||
@@ -209,11 +218,21 @@ func decodeMsg(bz []byte) (msg EvidenceMessage, err error) {
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// EvidenceMessage contains a list of evidence.
|
||||
// EvidenceListMessage contains a list of evidence.
|
||||
type EvidenceListMessage struct {
|
||||
Evidence []types.Evidence
|
||||
}
|
||||
|
||||
// ValidateBasic performs basic validation.
|
||||
func (m *EvidenceListMessage) ValidateBasic() error {
|
||||
for i, ev := range m.Evidence {
|
||||
if err := ev.ValidateBasic(); err != nil {
|
||||
return fmt.Errorf("Invalid evidence (#%d): %v", i, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns a string representation of the EvidenceListMessage.
|
||||
func (m *EvidenceListMessage) String() string {
|
||||
return fmt.Sprintf("[EvidenceListMessage %v]", m.Evidence)
|
||||
|
||||
@@ -24,7 +24,7 @@ func TestErrorPanic(t *testing.T) {
|
||||
var err = capturePanic()
|
||||
|
||||
assert.Equal(t, pnk{"something"}, err.Data())
|
||||
assert.Equal(t, "{something}", fmt.Sprintf("%v", err))
|
||||
assert.Equal(t, "{something}", fmt.Sprintf("%v", err))
|
||||
assert.Contains(t, fmt.Sprintf("%#v", err), "This is the message in ErrorWrap(r, message).")
|
||||
assert.Contains(t, fmt.Sprintf("%#v", err), "Stack Trace:\n 0")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package fail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var callIndexToFail int
|
||||
|
||||
func init() {
|
||||
callIndexToFailS := os.Getenv("FAIL_TEST_INDEX")
|
||||
|
||||
if callIndexToFailS == "" {
|
||||
callIndexToFail = -1
|
||||
} else {
|
||||
var err error
|
||||
callIndexToFail, err = strconv.Atoi(callIndexToFailS)
|
||||
if err != nil {
|
||||
callIndexToFail = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fail when FAIL_TEST_INDEX == callIndex
|
||||
var (
|
||||
callIndex int //indexes Fail calls
|
||||
|
||||
callRandIndex int // indexes a run of FailRand calls
|
||||
callRandIndexToFail = -1 // the callRandIndex to fail on in FailRand
|
||||
)
|
||||
|
||||
func Fail() {
|
||||
if callIndexToFail < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if callIndex == callIndexToFail {
|
||||
Exit()
|
||||
}
|
||||
|
||||
callIndex += 1
|
||||
}
|
||||
|
||||
// FailRand should be called n successive times.
|
||||
// It will fail on a random one of those calls
|
||||
// n must be greater than 0
|
||||
func FailRand(n int) {
|
||||
if callIndexToFail < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if callRandIndexToFail < 0 {
|
||||
// first call in the loop, pick a random index to fail at
|
||||
callRandIndexToFail = rand.Intn(n)
|
||||
callRandIndex = 0
|
||||
}
|
||||
|
||||
if callIndex == callIndexToFail {
|
||||
if callRandIndex == callRandIndexToFail {
|
||||
Exit()
|
||||
}
|
||||
}
|
||||
|
||||
callRandIndex += 1
|
||||
|
||||
if callRandIndex == n {
|
||||
callIndex += 1
|
||||
}
|
||||
}
|
||||
|
||||
func Exit() {
|
||||
fmt.Printf("*** fail-test %d ***\n", callIndex)
|
||||
proc, _ := os.FindProcess(os.Getpid())
|
||||
proc.Signal(os.Interrupt)
|
||||
// panic(fmt.Sprintf("*** fail-test %d ***", callIndex))
|
||||
}
|
||||
@@ -84,13 +84,13 @@ func (l tmfmtLogger) Log(keyvals ...interface{}) error {
|
||||
// Form a custom Tendermint line
|
||||
//
|
||||
// Example:
|
||||
// D[05-02|11:06:44.322] Stopping AddrBook (ignoring: already stopped)
|
||||
// D[2016-05-02|11:06:44.322] Stopping AddrBook (ignoring: already stopped)
|
||||
//
|
||||
// Description:
|
||||
// D - first character of the level, uppercase (ASCII only)
|
||||
// [05-02|11:06:44.322] - our time format (see https://golang.org/src/time/format.go)
|
||||
// [2016-05-02|11:06:44.322] - our time format (see https://golang.org/src/time/format.go)
|
||||
// Stopping ... - message
|
||||
enc.buf.WriteString(fmt.Sprintf("%c[%s] %-44s ", lvl[0]-32, time.Now().Format("01-02|15:04:05.000"), msg))
|
||||
enc.buf.WriteString(fmt.Sprintf("%c[%s] %-44s ", lvl[0]-32, time.Now().Format("2016-01-02|15:04:05.000"), msg))
|
||||
|
||||
if module != unknown {
|
||||
enc.buf.WriteString("module=" + module + " ")
|
||||
|
||||
+5
-5
@@ -56,7 +56,7 @@ func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error {
|
||||
// We might be overwriting what we already have, but
|
||||
// it makes the logic easier for now.
|
||||
vsKey := validatorSetKey(fc.ChainID(), fc.Height())
|
||||
vsBz, err := dbp.cdc.MarshalBinary(fc.Validators)
|
||||
vsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.Validators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error {
|
||||
|
||||
// Save the fc.NextValidators.
|
||||
nvsKey := validatorSetKey(fc.ChainID(), fc.Height()+1)
|
||||
nvsBz, err := dbp.cdc.MarshalBinary(fc.NextValidators)
|
||||
nvsBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.NextValidators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -72,7 +72,7 @@ func (dbp *DBProvider) SaveFullCommit(fc FullCommit) error {
|
||||
|
||||
// Save the fc.SignedHeader
|
||||
shKey := signedHeaderKey(fc.ChainID(), fc.Height())
|
||||
shBz, err := dbp.cdc.MarshalBinary(fc.SignedHeader)
|
||||
shBz, err := dbp.cdc.MarshalBinaryLengthPrefixed(fc.SignedHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func (dbp *DBProvider) LatestFullCommit(chainID string, minHeight, maxHeight int
|
||||
// Found the latest full commit signed header.
|
||||
shBz := itr.Value()
|
||||
sh := types.SignedHeader{}
|
||||
err := dbp.cdc.UnmarshalBinary(shBz, &sh)
|
||||
err := dbp.cdc.UnmarshalBinaryLengthPrefixed(shBz, &sh)
|
||||
if err != nil {
|
||||
return FullCommit{}, err
|
||||
} else {
|
||||
@@ -150,7 +150,7 @@ func (dbp *DBProvider) getValidatorSet(chainID string, height int64) (valset *ty
|
||||
err = lerr.ErrUnknownValidators(chainID, height)
|
||||
return
|
||||
}
|
||||
err = dbp.cdc.UnmarshalBinary(vsBz, &valset)
|
||||
err = dbp.cdc.UnmarshalBinaryLengthPrefixed(vsBz, &valset)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
+77
-46
@@ -25,12 +25,12 @@ import (
|
||||
// PreCheckFunc is an optional filter executed before CheckTx and rejects
|
||||
// transaction if false is returned. An example would be to ensure that a
|
||||
// transaction doesn't exceeded the block size.
|
||||
type PreCheckFunc func(types.Tx) bool
|
||||
type PreCheckFunc func(types.Tx) error
|
||||
|
||||
// PostCheckFunc is an optional filter executed after CheckTx and rejects
|
||||
// transaction if false is returned. An example would be to ensure a
|
||||
// transaction doesn't require more gas than available for the block.
|
||||
type PostCheckFunc func(types.Tx, *abci.ResponseCheckTx) bool
|
||||
type PostCheckFunc func(types.Tx, *abci.ResponseCheckTx) error
|
||||
|
||||
/*
|
||||
|
||||
@@ -68,24 +68,48 @@ var (
|
||||
ErrMempoolIsFull = errors.New("Mempool is full")
|
||||
)
|
||||
|
||||
// ErrPreCheck is returned when tx is too big
|
||||
type ErrPreCheck struct {
|
||||
Reason error
|
||||
}
|
||||
|
||||
func (e ErrPreCheck) Error() string {
|
||||
return e.Reason.Error()
|
||||
}
|
||||
|
||||
// IsPreCheckError returns true if err is due to pre check failure.
|
||||
func IsPreCheckError(err error) bool {
|
||||
_, ok := err.(ErrPreCheck)
|
||||
return ok
|
||||
}
|
||||
|
||||
// PreCheckAminoMaxBytes checks that the size of the transaction plus the amino
|
||||
// overhead is smaller or equal to the expected maxBytes.
|
||||
func PreCheckAminoMaxBytes(maxBytes int64) PreCheckFunc {
|
||||
return func(tx types.Tx) bool {
|
||||
return func(tx types.Tx) error {
|
||||
// We have to account for the amino overhead in the tx size as well
|
||||
aminoOverhead := amino.UvarintSize(uint64(len(tx)))
|
||||
return int64(len(tx)+aminoOverhead) <= maxBytes
|
||||
txSize := int64(len(tx) + aminoOverhead)
|
||||
if txSize > maxBytes {
|
||||
return fmt.Errorf("Tx size (including amino overhead) is too big: %d, max: %d",
|
||||
txSize, maxBytes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// PostCheckMaxGas checks that the wanted gas is smaller or equal to the passed
|
||||
// maxGas. Returns true if maxGas is -1.
|
||||
// maxGas. Returns nil if maxGas is -1.
|
||||
func PostCheckMaxGas(maxGas int64) PostCheckFunc {
|
||||
return func(tx types.Tx, res *abci.ResponseCheckTx) bool {
|
||||
return func(tx types.Tx, res *abci.ResponseCheckTx) error {
|
||||
if maxGas == -1 {
|
||||
return true
|
||||
return nil
|
||||
}
|
||||
return res.GasWanted <= maxGas
|
||||
if res.GasWanted > maxGas {
|
||||
return fmt.Errorf("gas wanted %d is greater than max gas %d",
|
||||
res.GasWanted, maxGas)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,39 +213,33 @@ func WithMetrics(metrics *Metrics) MempoolOption {
|
||||
return func(mem *Mempool) { mem.metrics = metrics }
|
||||
}
|
||||
|
||||
// InitWAL creates a directory for the WAL file and opens a file itself.
|
||||
//
|
||||
// *panics* if can't create directory or open file.
|
||||
// *not thread safe*
|
||||
func (mem *Mempool) InitWAL() {
|
||||
walDir := mem.config.WalDir()
|
||||
err := cmn.EnsureDir(walDir, 0700)
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "Error ensuring Mempool WAL dir"))
|
||||
}
|
||||
af, err := auto.OpenAutoFile(walDir + "/wal")
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "Error opening Mempool WAL file"))
|
||||
}
|
||||
mem.wal = af
|
||||
}
|
||||
|
||||
// CloseWAL closes and discards the underlying WAL file.
|
||||
// Any further writes will not be relayed to disk.
|
||||
func (mem *Mempool) CloseWAL() bool {
|
||||
if mem == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
func (mem *Mempool) CloseWAL() {
|
||||
mem.proxyMtx.Lock()
|
||||
defer mem.proxyMtx.Unlock()
|
||||
|
||||
if mem.wal == nil {
|
||||
return false
|
||||
}
|
||||
if err := mem.wal.Close(); err != nil && mem.logger != nil {
|
||||
mem.logger.Error("Mempool.CloseWAL", "err", err)
|
||||
if err := mem.wal.Close(); err != nil {
|
||||
mem.logger.Error("Error closing WAL", "err", err)
|
||||
}
|
||||
mem.wal = nil
|
||||
return true
|
||||
}
|
||||
|
||||
func (mem *Mempool) InitWAL() {
|
||||
walDir := mem.config.WalDir()
|
||||
if walDir != "" {
|
||||
err := cmn.EnsureDir(walDir, 0700)
|
||||
if err != nil {
|
||||
cmn.PanicSanity(errors.Wrap(err, "Error ensuring Mempool wal dir"))
|
||||
}
|
||||
af, err := auto.OpenAutoFile(walDir + "/wal")
|
||||
if err != nil {
|
||||
cmn.PanicSanity(errors.Wrap(err, "Error opening Mempool wal file"))
|
||||
}
|
||||
mem.wal = af
|
||||
}
|
||||
}
|
||||
|
||||
// Lock locks the mempool. The consensus must be able to hold lock to safely update.
|
||||
@@ -285,8 +303,10 @@ func (mem *Mempool) CheckTx(tx types.Tx, cb func(*abci.Response)) (err error) {
|
||||
return ErrMempoolIsFull
|
||||
}
|
||||
|
||||
if mem.preCheck != nil && !mem.preCheck(tx) {
|
||||
return
|
||||
if mem.preCheck != nil {
|
||||
if err := mem.preCheck(tx); err != nil {
|
||||
return ErrPreCheck{err}
|
||||
}
|
||||
}
|
||||
|
||||
// CACHE
|
||||
@@ -336,8 +356,11 @@ func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) {
|
||||
switch r := res.Value.(type) {
|
||||
case *abci.Response_CheckTx:
|
||||
tx := req.GetCheckTx().Tx
|
||||
if (r.CheckTx.Code == abci.CodeTypeOK) &&
|
||||
mem.isPostCheckPass(tx, r.CheckTx) {
|
||||
var postCheckErr error
|
||||
if mem.postCheck != nil {
|
||||
postCheckErr = mem.postCheck(tx, r.CheckTx)
|
||||
}
|
||||
if (r.CheckTx.Code == abci.CodeTypeOK) && postCheckErr == nil {
|
||||
mem.counter++
|
||||
memTx := &mempoolTx{
|
||||
counter: mem.counter,
|
||||
@@ -346,12 +369,18 @@ func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) {
|
||||
tx: tx,
|
||||
}
|
||||
mem.txs.PushBack(memTx)
|
||||
mem.logger.Info("Added good transaction", "tx", TxID(tx), "res", r, "total", mem.Size())
|
||||
mem.logger.Info("Added good transaction",
|
||||
"tx", TxID(tx),
|
||||
"res", r,
|
||||
"height", memTx.height,
|
||||
"total", mem.Size(),
|
||||
"counter", memTx.counter,
|
||||
)
|
||||
mem.metrics.TxSizeBytes.Observe(float64(len(tx)))
|
||||
mem.notifyTxsAvailable()
|
||||
} else {
|
||||
// ignore bad transaction
|
||||
mem.logger.Info("Rejected bad transaction", "tx", TxID(tx), "res", r)
|
||||
mem.logger.Info("Rejected bad transaction", "tx", TxID(tx), "res", r, "err", postCheckErr)
|
||||
mem.metrics.FailedTxs.Add(1)
|
||||
// remove from cache (it might be good later)
|
||||
mem.cache.Remove(tx)
|
||||
@@ -364,6 +393,7 @@ func (mem *Mempool) resCbNormal(req *abci.Request, res *abci.Response) {
|
||||
func (mem *Mempool) resCbRecheck(req *abci.Request, res *abci.Response) {
|
||||
switch r := res.Value.(type) {
|
||||
case *abci.Response_CheckTx:
|
||||
tx := req.GetCheckTx().Tx
|
||||
memTx := mem.recheckCursor.Value.(*mempoolTx)
|
||||
if !bytes.Equal(req.GetCheckTx().Tx, memTx.tx) {
|
||||
cmn.PanicSanity(
|
||||
@@ -374,15 +404,20 @@ func (mem *Mempool) resCbRecheck(req *abci.Request, res *abci.Response) {
|
||||
),
|
||||
)
|
||||
}
|
||||
if (r.CheckTx.Code == abci.CodeTypeOK) && mem.isPostCheckPass(memTx.tx, r.CheckTx) {
|
||||
var postCheckErr error
|
||||
if mem.postCheck != nil {
|
||||
postCheckErr = mem.postCheck(tx, r.CheckTx)
|
||||
}
|
||||
if (r.CheckTx.Code == abci.CodeTypeOK) && postCheckErr == nil {
|
||||
// Good, nothing to do.
|
||||
} else {
|
||||
// Tx became invalidated due to newly committed block.
|
||||
mem.logger.Info("Tx is no longer valid", "tx", TxID(tx), "res", r, "err", postCheckErr)
|
||||
mem.txs.Remove(mem.recheckCursor)
|
||||
mem.recheckCursor.DetachPrev()
|
||||
|
||||
// remove from cache (it might be good later)
|
||||
mem.cache.Remove(req.GetCheckTx().Tx)
|
||||
mem.cache.Remove(tx)
|
||||
}
|
||||
if mem.recheckCursor == mem.recheckEnd {
|
||||
mem.recheckCursor = nil
|
||||
@@ -565,10 +600,6 @@ func (mem *Mempool) recheckTxs(goodTxs []types.Tx) {
|
||||
mem.proxyAppConn.FlushAsync()
|
||||
}
|
||||
|
||||
func (mem *Mempool) isPostCheckPass(tx types.Tx, r *abci.ResponseCheckTx) bool {
|
||||
return mem.postCheck == nil || mem.postCheck(tx, r)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// mempoolTx is a transaction that successfully ran
|
||||
|
||||
+24
-40
@@ -14,7 +14,6 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/abci/example/counter"
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@@ -66,7 +65,13 @@ func checkTxs(t *testing.T, mempool *Mempool, count int) types.Txs {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := mempool.CheckTx(txBytes, nil); err != nil {
|
||||
t.Fatalf("Error after CheckTx: %v", err)
|
||||
// Skip invalid txs.
|
||||
// TestMempoolFilters will fail otherwise. It asserts a number of txs
|
||||
// returned.
|
||||
if IsPreCheckError(err) {
|
||||
continue
|
||||
}
|
||||
t.Fatalf("CheckTx failed: %v while checking #%d tx", err, i)
|
||||
}
|
||||
}
|
||||
return txs
|
||||
@@ -126,47 +131,29 @@ func TestMempoolFilters(t *testing.T) {
|
||||
mempool := newMempoolWithApp(cc)
|
||||
emptyTxArr := []types.Tx{[]byte{}}
|
||||
|
||||
nopPreFilter := func(tx types.Tx) bool { return true }
|
||||
nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) bool { return true }
|
||||
|
||||
// This is the same filter we expect to be used within node/node.go and state/execution.go
|
||||
nBytePreFilter := func(n int) func(tx types.Tx) bool {
|
||||
return func(tx types.Tx) bool {
|
||||
// We have to account for the amino overhead in the tx size as well
|
||||
aminoOverhead := amino.UvarintSize(uint64(len(tx)))
|
||||
return (len(tx) + aminoOverhead) <= n
|
||||
}
|
||||
}
|
||||
|
||||
nGasPostFilter := func(n int64) func(tx types.Tx, res *abci.ResponseCheckTx) bool {
|
||||
return func(tx types.Tx, res *abci.ResponseCheckTx) bool {
|
||||
if n == -1 {
|
||||
return true
|
||||
}
|
||||
return res.GasWanted <= n
|
||||
}
|
||||
}
|
||||
nopPreFilter := func(tx types.Tx) error { return nil }
|
||||
nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) error { return nil }
|
||||
|
||||
// each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs.
|
||||
// each tx has 20 bytes + amino overhead = 21 bytes, 1 gas
|
||||
tests := []struct {
|
||||
numTxsToCreate int
|
||||
preFilter func(tx types.Tx) bool
|
||||
postFilter func(tx types.Tx, res *abci.ResponseCheckTx) bool
|
||||
preFilter PreCheckFunc
|
||||
postFilter PostCheckFunc
|
||||
expectedNumTxs int
|
||||
}{
|
||||
{10, nopPreFilter, nopPostFilter, 10},
|
||||
{10, nBytePreFilter(10), nopPostFilter, 0},
|
||||
{10, nBytePreFilter(20), nopPostFilter, 0},
|
||||
{10, nBytePreFilter(21), nopPostFilter, 10},
|
||||
{10, nopPreFilter, nGasPostFilter(-1), 10},
|
||||
{10, nopPreFilter, nGasPostFilter(0), 0},
|
||||
{10, nopPreFilter, nGasPostFilter(1), 10},
|
||||
{10, nopPreFilter, nGasPostFilter(3000), 10},
|
||||
{10, nBytePreFilter(10), nGasPostFilter(20), 0},
|
||||
{10, nBytePreFilter(30), nGasPostFilter(20), 10},
|
||||
{10, nBytePreFilter(21), nGasPostFilter(1), 10},
|
||||
{10, nBytePreFilter(21), nGasPostFilter(0), 0},
|
||||
{10, PreCheckAminoMaxBytes(10), nopPostFilter, 0},
|
||||
{10, PreCheckAminoMaxBytes(20), nopPostFilter, 0},
|
||||
{10, PreCheckAminoMaxBytes(21), nopPostFilter, 10},
|
||||
{10, nopPreFilter, PostCheckMaxGas(-1), 10},
|
||||
{10, nopPreFilter, PostCheckMaxGas(0), 0},
|
||||
{10, nopPreFilter, PostCheckMaxGas(1), 10},
|
||||
{10, nopPreFilter, PostCheckMaxGas(3000), 10},
|
||||
{10, PreCheckAminoMaxBytes(10), PostCheckMaxGas(20), 0},
|
||||
{10, PreCheckAminoMaxBytes(30), PostCheckMaxGas(20), 10},
|
||||
{10, PreCheckAminoMaxBytes(21), PostCheckMaxGas(1), 10},
|
||||
{10, PreCheckAminoMaxBytes(21), PostCheckMaxGas(0), 0},
|
||||
}
|
||||
for tcIndex, tt := range tests {
|
||||
mempool.Update(1, emptyTxArr, tt.preFilter, tt.postFilter)
|
||||
@@ -385,15 +372,12 @@ func TestMempoolCloseWAL(t *testing.T) {
|
||||
|
||||
// 7. Invoke CloseWAL() and ensure it discards the
|
||||
// WAL thus any other write won't go through.
|
||||
require.True(t, mempool.CloseWAL(), "CloseWAL should CloseWAL")
|
||||
mempool.CloseWAL()
|
||||
mempool.CheckTx(types.Tx([]byte("bar")), nil)
|
||||
sum2 := checksumFile(walFilepath, t)
|
||||
require.Equal(t, sum1, sum2, "expected no change to the WAL after invoking CloseWAL() since it was discarded")
|
||||
|
||||
// 8. Second CloseWAL should do nothing
|
||||
require.False(t, mempool.CloseWAL(), "CloseWAL should CloseWAL")
|
||||
|
||||
// 9. Sanity check to ensure that the WAL file still exists
|
||||
// 8. Sanity check to ensure that the WAL file still exists
|
||||
m3, err := filepath.Glob(filepath.Join(rootDir, "*"))
|
||||
require.Nil(t, err, "successful globbing expected")
|
||||
require.Equal(t, 1, len(m3), "expecting the wal match in")
|
||||
|
||||
+28
-7
@@ -13,8 +13,8 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/tendermint/go-amino"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
bc "github.com/tendermint/tendermint/blockchain"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
@@ -195,8 +195,8 @@ func NewNode(config *cfg.Config,
|
||||
return nil, fmt.Errorf("Error starting proxy app connections: %v", err)
|
||||
}
|
||||
|
||||
// Create the handshaker, which calls RequestInfo and replays any blocks
|
||||
// as necessary to sync tendermint with the app.
|
||||
// Create the handshaker, which calls RequestInfo, sets the AppVersion on the state,
|
||||
// and replays any blocks as necessary to sync tendermint with the app.
|
||||
consensusLogger := logger.With("module", "consensus")
|
||||
handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc)
|
||||
handshaker.SetLogger(consensusLogger)
|
||||
@@ -204,9 +204,12 @@ func NewNode(config *cfg.Config,
|
||||
return nil, fmt.Errorf("Error during handshake: %v", err)
|
||||
}
|
||||
|
||||
// reload the state (it may have been updated by the handshake)
|
||||
// Reload the state. It will have the Version.Consensus.App set by the
|
||||
// Handshake, and may have other modifications as well (ie. depending on
|
||||
// what happened during block replay).
|
||||
state = sm.LoadState(stateDB)
|
||||
|
||||
// Ensure the state's block version matches that of the software.
|
||||
if state.Version.Consensus.Block != version.BlockProtocol {
|
||||
return nil, fmt.Errorf(
|
||||
"Block version of the software does not match that of the state.\n"+
|
||||
@@ -276,7 +279,9 @@ func NewNode(config *cfg.Config,
|
||||
)
|
||||
mempoolLogger := logger.With("module", "mempool")
|
||||
mempool.SetLogger(mempoolLogger)
|
||||
mempool.InitWAL() // no need to have the mempool wal during tests
|
||||
if config.Mempool.WalEnabled() {
|
||||
mempool.InitWAL() // no need to have the mempool wal during tests
|
||||
}
|
||||
mempoolReactor := mempl.NewMempoolReactor(config.Mempool, mempool)
|
||||
mempoolReactor.SetLogger(mempoolLogger)
|
||||
|
||||
@@ -359,7 +364,17 @@ func NewNode(config *cfg.Config,
|
||||
|
||||
var (
|
||||
p2pLogger = logger.With("module", "p2p")
|
||||
nodeInfo = makeNodeInfo(config, nodeKey.ID(), txIndexer, genDoc.ChainID)
|
||||
nodeInfo = makeNodeInfo(
|
||||
config,
|
||||
nodeKey.ID(),
|
||||
txIndexer,
|
||||
genDoc.ChainID,
|
||||
p2p.NewProtocolVersion(
|
||||
version.P2PProtocol, // global
|
||||
state.Version.Consensus.Block,
|
||||
state.Version.Consensus.App,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
// Setup Transport.
|
||||
@@ -573,6 +588,11 @@ func (n *Node) OnStop() {
|
||||
// TODO: gracefully disconnect from peers.
|
||||
n.sw.Stop()
|
||||
|
||||
// stop mempool WAL
|
||||
if n.config.Mempool.WalEnabled() {
|
||||
n.mempoolReactor.Mempool.CloseWAL()
|
||||
}
|
||||
|
||||
if err := n.transport.Close(); err != nil {
|
||||
n.Logger.Error("Error closing transport", "err", err)
|
||||
}
|
||||
@@ -764,13 +784,14 @@ func makeNodeInfo(
|
||||
nodeID p2p.ID,
|
||||
txIndexer txindex.TxIndexer,
|
||||
chainID string,
|
||||
protocolVersion p2p.ProtocolVersion,
|
||||
) p2p.NodeInfo {
|
||||
txIndexerStatus := "on"
|
||||
if _, ok := txIndexer.(*null.TxIndex); ok {
|
||||
txIndexerStatus = "off"
|
||||
}
|
||||
nodeInfo := p2p.DefaultNodeInfo{
|
||||
ProtocolVersion: p2p.InitProtocolVersion,
|
||||
ProtocolVersion: protocolVersion,
|
||||
ID_: nodeID,
|
||||
Network: chainID,
|
||||
Version: version.TMCoreSemVer,
|
||||
|
||||
@@ -10,7 +10,11 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/tendermint/tendermint/abci/example/kvstore"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -91,3 +95,21 @@ func TestNodeDelayedStop(t *testing.T) {
|
||||
startTime := tmtime.Now()
|
||||
assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
|
||||
}
|
||||
|
||||
func TestNodeSetAppVersion(t *testing.T) {
|
||||
config := cfg.ResetTestRoot("node_app_version_test")
|
||||
|
||||
// create & start node
|
||||
n, err := DefaultNewNode(config, log.TestingLogger())
|
||||
assert.NoError(t, err, "expected no err on DefaultNewNode")
|
||||
|
||||
// default config uses the kvstore app
|
||||
var appVersion version.Protocol = kvstore.ProtocolVersion
|
||||
|
||||
// check version is set in state
|
||||
state := sm.LoadState(n.stateDB)
|
||||
assert.Equal(t, state.Version.Consensus.App, appVersion)
|
||||
|
||||
// check version is set in node info
|
||||
assert.Equal(t, n.nodeInfo.(p2p.DefaultNodeInfo).ProtocolVersion.App, appVersion)
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ FOR_LOOP:
|
||||
}
|
||||
case <-c.pingTimer.Chan():
|
||||
c.Logger.Debug("Send Ping")
|
||||
_n, err = cdc.MarshalBinaryWriter(c.bufConnWriter, PacketPing{})
|
||||
_n, err = cdc.MarshalBinaryLengthPrefixedWriter(c.bufConnWriter, PacketPing{})
|
||||
if err != nil {
|
||||
break SELECTION
|
||||
}
|
||||
@@ -359,7 +359,7 @@ FOR_LOOP:
|
||||
}
|
||||
case <-c.pong:
|
||||
c.Logger.Debug("Send Pong")
|
||||
_n, err = cdc.MarshalBinaryWriter(c.bufConnWriter, PacketPong{})
|
||||
_n, err = cdc.MarshalBinaryLengthPrefixedWriter(c.bufConnWriter, PacketPong{})
|
||||
if err != nil {
|
||||
break SELECTION
|
||||
}
|
||||
@@ -477,7 +477,7 @@ FOR_LOOP:
|
||||
var packet Packet
|
||||
var _n int64
|
||||
var err error
|
||||
_n, err = cdc.UnmarshalBinaryReader(c.bufConnReader, &packet, int64(c._maxPacketMsgSize))
|
||||
_n, err = cdc.UnmarshalBinaryLengthPrefixedReader(c.bufConnReader, &packet, int64(c._maxPacketMsgSize))
|
||||
c.recvMonitor.Update(int(_n))
|
||||
if err != nil {
|
||||
if c.IsRunning() {
|
||||
@@ -553,7 +553,7 @@ func (c *MConnection) stopPongTimer() {
|
||||
// maxPacketMsgSize returns a maximum size of PacketMsg, including the overhead
|
||||
// of amino encoding.
|
||||
func (c *MConnection) maxPacketMsgSize() int {
|
||||
return len(cdc.MustMarshalBinary(PacketMsg{
|
||||
return len(cdc.MustMarshalBinaryLengthPrefixed(PacketMsg{
|
||||
ChannelID: 0x01,
|
||||
EOF: 1,
|
||||
Bytes: make([]byte, c.config.MaxPacketMsgPayloadSize),
|
||||
@@ -723,7 +723,7 @@ func (ch *Channel) nextPacketMsg() PacketMsg {
|
||||
// Not goroutine-safe
|
||||
func (ch *Channel) writePacketMsgTo(w io.Writer) (n int64, err error) {
|
||||
var packet = ch.nextPacketMsg()
|
||||
n, err = cdc.MarshalBinaryWriter(w, packet)
|
||||
n, err = cdc.MarshalBinaryLengthPrefixedWriter(w, packet)
|
||||
atomic.AddInt64(&ch.recentlySent, n)
|
||||
return
|
||||
}
|
||||
|
||||
+19
-19
@@ -140,7 +140,7 @@ func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
|
||||
go func() {
|
||||
// read ping
|
||||
var pkt PacketPing
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
assert.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
}()
|
||||
@@ -176,22 +176,22 @@ func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) {
|
||||
defer mconn.Stop()
|
||||
|
||||
// sending 3 pongs in a row (abuse)
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
|
||||
serverGotPing := make(chan struct{})
|
||||
go func() {
|
||||
// read ping (one byte)
|
||||
var packet, err = Packet(nil), error(nil)
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &packet, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &packet, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
// respond with pong
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
}()
|
||||
<-serverGotPing
|
||||
@@ -227,18 +227,18 @@ func TestMConnectionMultiplePings(t *testing.T) {
|
||||
|
||||
// sending 3 pings in a row (abuse)
|
||||
// see https://github.com/tendermint/tendermint/issues/1190
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
var pkt PacketPong
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.True(t, mconn.IsRunning())
|
||||
@@ -270,20 +270,20 @@ func TestMConnectionPingPongs(t *testing.T) {
|
||||
go func() {
|
||||
// read ping
|
||||
var pkt PacketPing
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
// respond with pong
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
|
||||
time.Sleep(mconn.config.PingInterval)
|
||||
|
||||
// read ping
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPingPongPacketSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(server, &pkt, maxPingPongPacketSize)
|
||||
require.Nil(t, err)
|
||||
// respond with pong
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
_, err = server.Write(cdc.MustMarshalBinaryLengthPrefixed(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
}()
|
||||
<-serverGotPing
|
||||
@@ -380,7 +380,7 @@ func TestMConnectionReadErrorBadEncoding(t *testing.T) {
|
||||
client := mconnClient.conn
|
||||
|
||||
// send badly encoded msgPacket
|
||||
bz := cdc.MustMarshalBinary(PacketMsg{})
|
||||
bz := cdc.MustMarshalBinaryLengthPrefixed(PacketMsg{})
|
||||
bz[4] += 0x01 // Invalid prefix bytes.
|
||||
|
||||
// Write it.
|
||||
@@ -428,7 +428,7 @@ func TestMConnectionReadErrorLongMessage(t *testing.T) {
|
||||
EOF: 1,
|
||||
Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize),
|
||||
}
|
||||
_, err = cdc.MarshalBinaryWriter(buf, packet)
|
||||
_, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
|
||||
assert.Nil(t, err)
|
||||
_, err = client.Write(buf.Bytes())
|
||||
assert.Nil(t, err)
|
||||
@@ -441,7 +441,7 @@ func TestMConnectionReadErrorLongMessage(t *testing.T) {
|
||||
EOF: 1,
|
||||
Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+100),
|
||||
}
|
||||
_, err = cdc.MarshalBinaryWriter(buf, packet)
|
||||
_, err = cdc.MarshalBinaryLengthPrefixedWriter(buf, packet)
|
||||
assert.Nil(t, err)
|
||||
_, err = client.Write(buf.Bytes())
|
||||
assert.NotNil(t, err)
|
||||
|
||||
@@ -211,7 +211,7 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
|
||||
// Send our pubkey and receive theirs in tandem.
|
||||
var trs, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _, err1 = cdc.MarshalBinaryWriter(conn, locEphPub)
|
||||
var _, err1 = cdc.MarshalBinaryLengthPrefixedWriter(conn, locEphPub)
|
||||
if err1 != nil {
|
||||
return nil, err1, true // abort
|
||||
}
|
||||
@@ -219,7 +219,7 @@ func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[3
|
||||
},
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _remEphPub [32]byte
|
||||
var _, err2 = cdc.UnmarshalBinaryReader(conn, &_remEphPub, 1024*1024) // TODO
|
||||
var _, err2 = cdc.UnmarshalBinaryLengthPrefixedReader(conn, &_remEphPub, 1024*1024) // TODO
|
||||
if err2 != nil {
|
||||
return nil, err2, true // abort
|
||||
}
|
||||
@@ -305,7 +305,7 @@ func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature []
|
||||
// Send our info and receive theirs in tandem.
|
||||
var trs, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _, err1 = cdc.MarshalBinaryWriter(sc, authSigMessage{pubKey, signature})
|
||||
var _, err1 = cdc.MarshalBinaryLengthPrefixedWriter(sc, authSigMessage{pubKey, signature})
|
||||
if err1 != nil {
|
||||
return nil, err1, true // abort
|
||||
}
|
||||
@@ -313,7 +313,7 @@ func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature []
|
||||
},
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _recvMsg authSigMessage
|
||||
var _, err2 = cdc.UnmarshalBinaryReader(sc, &_recvMsg, 1024*1024) // TODO
|
||||
var _, err2 = cdc.UnmarshalBinaryLengthPrefixedReader(sc, &_recvMsg, 1024*1024) // TODO
|
||||
if err2 != nil {
|
||||
return nil, err2, true // abort
|
||||
}
|
||||
|
||||
@@ -78,3 +78,8 @@ func (p *peer) Get(key string) interface{} {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OriginalAddr always returns nil.
|
||||
func (p *peer) OriginalAddr() *p2p.NetAddress {
|
||||
return nil
|
||||
}
|
||||
|
||||
+1
-2
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
crypto "github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
@@ -17,7 +16,7 @@ type ID string
|
||||
|
||||
// IDByteLength is the length of a crypto.Address. Currently only 20.
|
||||
// TODO: support other length addresses ?
|
||||
const IDByteLength = tmhash.Size
|
||||
const IDByteLength = crypto.AddressSize
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Persistent peer ID
|
||||
|
||||
+16
-5
@@ -49,10 +49,21 @@ type ProtocolVersion struct {
|
||||
App version.Protocol `json:"app"`
|
||||
}
|
||||
|
||||
var InitProtocolVersion = ProtocolVersion{
|
||||
P2P: version.P2PProtocol,
|
||||
Block: version.BlockProtocol,
|
||||
App: 0,
|
||||
// defaultProtocolVersion populates the Block and P2P versions using
|
||||
// the global values, but not the App.
|
||||
var defaultProtocolVersion = NewProtocolVersion(
|
||||
version.P2PProtocol,
|
||||
version.BlockProtocol,
|
||||
0,
|
||||
)
|
||||
|
||||
// NewProtocolVersion returns a fully populated ProtocolVersion.
|
||||
func NewProtocolVersion(p2p, block, app version.Protocol) ProtocolVersion {
|
||||
return ProtocolVersion{
|
||||
P2P: p2p,
|
||||
Block: block,
|
||||
App: app,
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
@@ -148,7 +159,7 @@ func (info DefaultNodeInfo) ValidateBasic() error {
|
||||
switch txIndex {
|
||||
case "", "on", "off":
|
||||
default:
|
||||
return fmt.Errorf("info.Other.TxIndex should be either 'on' or 'off', got '%v'", txIndex)
|
||||
return fmt.Errorf("info.Other.TxIndex should be either 'on', 'off', or empty string, got '%v'", txIndex)
|
||||
}
|
||||
// XXX: Should we be more strict about address formats?
|
||||
rpcAddr := other.RPCAddress
|
||||
|
||||
+31
-3
@@ -26,6 +26,7 @@ type Peer interface {
|
||||
|
||||
NodeInfo() NodeInfo // peer's info
|
||||
Status() tmconn.ConnectionStatus
|
||||
OriginalAddr() *NetAddress
|
||||
|
||||
Send(byte, []byte) bool
|
||||
TrySend(byte, []byte) bool
|
||||
@@ -43,10 +44,28 @@ type peerConn struct {
|
||||
config *config.P2PConfig
|
||||
conn net.Conn // source connection
|
||||
|
||||
originalAddr *NetAddress // nil for inbound connections
|
||||
|
||||
// cached RemoteIP()
|
||||
ip net.IP
|
||||
}
|
||||
|
||||
func newPeerConn(
|
||||
outbound, persistent bool,
|
||||
config *config.P2PConfig,
|
||||
conn net.Conn,
|
||||
originalAddr *NetAddress,
|
||||
) peerConn {
|
||||
|
||||
return peerConn{
|
||||
outbound: outbound,
|
||||
persistent: persistent,
|
||||
config: config,
|
||||
conn: conn,
|
||||
originalAddr: originalAddr,
|
||||
}
|
||||
}
|
||||
|
||||
// ID only exists for SecretConnection.
|
||||
// NOTE: Will panic if conn is not *SecretConnection.
|
||||
func (pc peerConn) ID() ID {
|
||||
@@ -195,6 +214,15 @@ func (p *peer) NodeInfo() NodeInfo {
|
||||
return p.nodeInfo
|
||||
}
|
||||
|
||||
// OriginalAddr returns the original address, which was used to connect with
|
||||
// the peer. Returns nil for inbound peers.
|
||||
func (p *peer) OriginalAddr() *NetAddress {
|
||||
if p.peerConn.outbound {
|
||||
return p.peerConn.originalAddr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status returns the peer's ConnectionStatus.
|
||||
func (p *peer) Status() tmconn.ConnectionStatus {
|
||||
return p.mconn.Status()
|
||||
@@ -212,7 +240,7 @@ func (p *peer) Send(chID byte, msgBytes []byte) bool {
|
||||
}
|
||||
res := p.mconn.Send(chID, msgBytes)
|
||||
if res {
|
||||
p.metrics.PeerSendBytesTotal.With("peer-id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||
p.metrics.PeerSendBytesTotal.With("peer_id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -227,7 +255,7 @@ func (p *peer) TrySend(chID byte, msgBytes []byte) bool {
|
||||
}
|
||||
res := p.mconn.TrySend(chID, msgBytes)
|
||||
if res {
|
||||
p.metrics.PeerSendBytesTotal.With("peer-id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||
p.metrics.PeerSendBytesTotal.With("peer_id", string(p.ID())).Add(float64(len(msgBytes)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -302,7 +330,7 @@ func (p *peer) metricsReporter() {
|
||||
sendQueueSize += float64(chStatus.SendQueueSize)
|
||||
}
|
||||
|
||||
p.metrics.PeerPendingSendBytes.With("peer-id", string(p.ID())).Set(sendQueueSize)
|
||||
p.metrics.PeerPendingSendBytes.With("peer_id", string(p.ID())).Set(sendQueueSize)
|
||||
case <-p.Quit():
|
||||
return
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func (mp *mockPeer) IsPersistent() bool { return true }
|
||||
func (mp *mockPeer) Get(s string) interface{} { return s }
|
||||
func (mp *mockPeer) Set(string, interface{}) {}
|
||||
func (mp *mockPeer) RemoteIP() net.IP { return mp.ip }
|
||||
func (mp *mockPeer) OriginalAddr() *NetAddress { return nil }
|
||||
|
||||
// Returns a mock peer
|
||||
func newMockPeer(ip net.IP) *mockPeer {
|
||||
|
||||
+2
-2
@@ -114,7 +114,7 @@ func testOutboundPeerConn(
|
||||
return peerConn{}, cmn.ErrorWrap(err, "Error creating peer")
|
||||
}
|
||||
|
||||
pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey)
|
||||
pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr)
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
|
||||
@@ -207,7 +207,7 @@ func (rp *remotePeer) accept(l net.Listener) {
|
||||
|
||||
func (rp *remotePeer) nodeInfo(l net.Listener) NodeInfo {
|
||||
return DefaultNodeInfo{
|
||||
ProtocolVersion: InitProtocolVersion,
|
||||
ProtocolVersion: defaultProtocolVersion,
|
||||
ID_: rp.Addr().ID,
|
||||
ListenAddr: l.Addr().String(),
|
||||
Network: "testing",
|
||||
|
||||
@@ -648,6 +648,10 @@ func (a *addrBook) addAddress(addr, src *p2p.NetAddress) error {
|
||||
return ErrAddrBookNonRoutable{addr}
|
||||
}
|
||||
|
||||
if !addr.Valid() {
|
||||
return ErrAddrBookInvalidAddr{addr}
|
||||
}
|
||||
|
||||
// TODO: we should track ourAddrs by ID and by IP:PORT and refuse both.
|
||||
if _, ok := a.ourAddrs[addr.String()]; ok {
|
||||
return ErrAddrBookSelf{addr}
|
||||
|
||||
@@ -46,3 +46,11 @@ type ErrAddrBookNilAddr struct {
|
||||
func (err ErrAddrBookNilAddr) Error() string {
|
||||
return fmt.Sprintf("Cannot add a nil address. Got (addr, src) = (%v, %v)", err.Addr, err.Src)
|
||||
}
|
||||
|
||||
type ErrAddrBookInvalidAddr struct {
|
||||
Addr *p2p.NetAddress
|
||||
}
|
||||
|
||||
func (err ErrAddrBookInvalidAddr) Error() string {
|
||||
return fmt.Sprintf("Cannot add invalid address %v", err.Addr)
|
||||
}
|
||||
|
||||
+22
-6
@@ -288,21 +288,37 @@ func (r *PEXReactor) RequestAddrs(p Peer) {
|
||||
func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
|
||||
id := string(src.ID())
|
||||
if !r.requestsSent.Has(id) {
|
||||
return cmn.NewError("Received unsolicited pexAddrsMessage")
|
||||
return errors.New("Unsolicited pexAddrsMessage")
|
||||
}
|
||||
r.requestsSent.Delete(id)
|
||||
|
||||
srcAddr := src.NodeInfo().NetAddress()
|
||||
for _, netAddr := range addrs {
|
||||
// NOTE: GetSelection methods should never return nil addrs
|
||||
// Validate netAddr. Disconnect from a peer if it sends us invalid data.
|
||||
if netAddr == nil {
|
||||
return cmn.NewError("received nil addr")
|
||||
return errors.New("nil address in pexAddrsMessage")
|
||||
}
|
||||
// TODO: extract validating logic from NewNetAddressStringWithOptionalID
|
||||
// and put it in netAddr#Valid (#2722)
|
||||
na, err := p2p.NewNetAddressString(netAddr.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s address in pexAddrsMessage is invalid: %v",
|
||||
netAddr.String(),
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
err := r.book.AddAddress(netAddr, srcAddr)
|
||||
r.logErrAddrBook(err)
|
||||
// NOTE: we check netAddr validity and routability in book#AddAddress.
|
||||
err = r.book.AddAddress(na, srcAddr)
|
||||
if err != nil {
|
||||
r.logErrAddrBook(err)
|
||||
// XXX: should we be strict about incoming data and disconnect from a
|
||||
// peer here too?
|
||||
continue
|
||||
}
|
||||
|
||||
// If this address came from a seed node, try to connect to it without waiting.
|
||||
// If this address came from a seed node, try to connect to it without
|
||||
// waiting.
|
||||
for _, seedAddr := range r.seedAddrs {
|
||||
if seedAddr.Equals(srcAddr) {
|
||||
r.ensurePeers()
|
||||
|
||||
@@ -402,6 +402,7 @@ func (mockPeer) Send(byte, []byte) bool { return false }
|
||||
func (mockPeer) TrySend(byte, []byte) bool { return false }
|
||||
func (mockPeer) Set(string, interface{}) {}
|
||||
func (mockPeer) Get(string) interface{} { return nil }
|
||||
func (mockPeer) OriginalAddr() *p2p.NetAddress { return nil }
|
||||
|
||||
func assertPeersWithTimeout(
|
||||
t *testing.T,
|
||||
|
||||
+6
-3
@@ -280,9 +280,12 @@ func (sw *Switch) StopPeerForError(peer Peer, reason interface{}) {
|
||||
sw.stopAndRemovePeer(peer, reason)
|
||||
|
||||
if peer.IsPersistent() {
|
||||
// TODO: use the original address dialed, not the self reported one
|
||||
// See #2618.
|
||||
addr := peer.NodeInfo().NetAddress()
|
||||
addr := peer.OriginalAddr()
|
||||
if addr == nil {
|
||||
// FIXME: persistent peers can't be inbound right now.
|
||||
// self-reported address for inbound persistent peers
|
||||
addr = peer.NodeInfo().NetAddress()
|
||||
}
|
||||
go sw.reconnectToPeer(addr)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-6
@@ -206,7 +206,7 @@ func testInboundPeerConn(
|
||||
config *config.P2PConfig,
|
||||
ourNodePrivKey crypto.PrivKey,
|
||||
) (peerConn, error) {
|
||||
return testPeerConn(conn, config, false, false, ourNodePrivKey)
|
||||
return testPeerConn(conn, config, false, false, ourNodePrivKey, nil)
|
||||
}
|
||||
|
||||
func testPeerConn(
|
||||
@@ -214,6 +214,7 @@ func testPeerConn(
|
||||
cfg *config.P2PConfig,
|
||||
outbound, persistent bool,
|
||||
ourNodePrivKey crypto.PrivKey,
|
||||
originalAddr *NetAddress,
|
||||
) (pc peerConn, err error) {
|
||||
conn := rawConn
|
||||
|
||||
@@ -231,10 +232,11 @@ func testPeerConn(
|
||||
|
||||
// Only the information we already have
|
||||
return peerConn{
|
||||
config: cfg,
|
||||
outbound: outbound,
|
||||
persistent: persistent,
|
||||
conn: conn,
|
||||
config: cfg,
|
||||
outbound: outbound,
|
||||
persistent: persistent,
|
||||
conn: conn,
|
||||
originalAddr: originalAddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -247,7 +249,7 @@ func testNodeInfo(id ID, name string) NodeInfo {
|
||||
|
||||
func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
|
||||
return DefaultNodeInfo{
|
||||
ProtocolVersion: InitProtocolVersion,
|
||||
ProtocolVersion: defaultProtocolVersion,
|
||||
ID_: id,
|
||||
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
||||
Network: network,
|
||||
|
||||
+15
-10
@@ -171,7 +171,7 @@ func (mt *MultiplexTransport) Accept(cfg peerConfig) (Peer, error) {
|
||||
|
||||
cfg.outbound = false
|
||||
|
||||
return mt.wrapPeer(a.conn, a.nodeInfo, cfg), nil
|
||||
return mt.wrapPeer(a.conn, a.nodeInfo, cfg, nil), nil
|
||||
case <-mt.closec:
|
||||
return nil, &ErrTransportClosed{}
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func (mt *MultiplexTransport) Dial(
|
||||
|
||||
cfg.outbound = true
|
||||
|
||||
p := mt.wrapPeer(secretConn, nodeInfo, cfg)
|
||||
p := mt.wrapPeer(secretConn, nodeInfo, cfg, &addr)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
@@ -399,14 +399,19 @@ func (mt *MultiplexTransport) wrapPeer(
|
||||
c net.Conn,
|
||||
ni NodeInfo,
|
||||
cfg peerConfig,
|
||||
dialedAddr *NetAddress,
|
||||
) Peer {
|
||||
|
||||
peerConn := newPeerConn(
|
||||
cfg.outbound,
|
||||
cfg.persistent,
|
||||
&mt.p2pConfig,
|
||||
c,
|
||||
dialedAddr,
|
||||
)
|
||||
|
||||
p := newPeer(
|
||||
peerConn{
|
||||
conn: c,
|
||||
config: &mt.p2pConfig,
|
||||
outbound: cfg.outbound,
|
||||
persistent: cfg.persistent,
|
||||
},
|
||||
peerConn,
|
||||
mt.mConfig,
|
||||
ni,
|
||||
cfg.reactorsByCh,
|
||||
@@ -441,11 +446,11 @@ func handshake(
|
||||
)
|
||||
|
||||
go func(errc chan<- error, c net.Conn) {
|
||||
_, err := cdc.MarshalBinaryWriter(c, ourNodeInfo)
|
||||
_, err := cdc.MarshalBinaryLengthPrefixedWriter(c, ourNodeInfo)
|
||||
errc <- err
|
||||
}(errc, c)
|
||||
go func(errc chan<- error, c net.Conn) {
|
||||
_, err := cdc.UnmarshalBinaryReader(
|
||||
_, err := cdc.UnmarshalBinaryLengthPrefixedReader(
|
||||
c,
|
||||
&peerNodeInfo,
|
||||
int64(MaxNodeInfoSize()),
|
||||
|
||||
@@ -516,7 +516,7 @@ func TestTransportHandshake(t *testing.T) {
|
||||
}
|
||||
|
||||
go func(c net.Conn) {
|
||||
_, err := cdc.MarshalBinaryWriter(c, peerNodeInfo.(DefaultNodeInfo))
|
||||
_, err := cdc.MarshalBinaryLengthPrefixedWriter(c, peerNodeInfo.(DefaultNodeInfo))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -524,7 +524,7 @@ func TestTransportHandshake(t *testing.T) {
|
||||
go func(c net.Conn) {
|
||||
var ni DefaultNodeInfo
|
||||
|
||||
_, err := cdc.UnmarshalBinaryReader(
|
||||
_, err := cdc.UnmarshalBinaryLengthPrefixedReader(
|
||||
c,
|
||||
&ni,
|
||||
int64(MaxNodeInfoSize()),
|
||||
|
||||
@@ -314,10 +314,10 @@ func (pv *FilePV) String() string {
|
||||
// returns true if the only difference in the votes is their timestamp.
|
||||
func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
|
||||
var lastVote, newVote types.CanonicalVote
|
||||
if err := cdc.UnmarshalBinary(lastSignBytes, &lastVote); err != nil {
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(lastSignBytes, &lastVote); err != nil {
|
||||
panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
|
||||
}
|
||||
if err := cdc.UnmarshalBinary(newSignBytes, &newVote); err != nil {
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(newSignBytes, &newVote); err != nil {
|
||||
panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
|
||||
}
|
||||
|
||||
@@ -337,10 +337,10 @@ func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.T
|
||||
// returns true if the only difference in the proposals is their timestamp
|
||||
func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
|
||||
var lastProposal, newProposal types.CanonicalProposal
|
||||
if err := cdc.UnmarshalBinary(lastSignBytes, &lastProposal); err != nil {
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(lastSignBytes, &lastProposal); err != nil {
|
||||
panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err))
|
||||
}
|
||||
if err := cdc.UnmarshalBinary(newSignBytes, &newProposal); err != nil {
|
||||
if err := cdc.UnmarshalBinaryLengthPrefixed(newSignBytes, &newProposal); err != nil {
|
||||
panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err))
|
||||
}
|
||||
|
||||
@@ -349,8 +349,8 @@ func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (ti
|
||||
now := tmtime.Now()
|
||||
lastProposal.Timestamp = now
|
||||
newProposal.Timestamp = now
|
||||
lastProposalBytes, _ := cdc.MarshalBinary(lastProposal)
|
||||
newProposalBytes, _ := cdc.MarshalBinary(newProposal)
|
||||
lastProposalBytes, _ := cdc.MarshalBinaryLengthPrefixed(lastProposal)
|
||||
newProposalBytes, _ := cdc.MarshalBinaryLengthPrefixed(newProposal)
|
||||
|
||||
return lastTime, bytes.Equal(newProposalBytes, lastProposalBytes)
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ func TestSignProposal(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
privVal := GenFilePV(tempFile.Name())
|
||||
|
||||
block1 := types.PartSetHeader{5, []byte{1, 2, 3}}
|
||||
block2 := types.PartSetHeader{10, []byte{3, 2, 1}}
|
||||
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}}
|
||||
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{10, []byte{3, 2, 1}}}
|
||||
height, round := int64(10), 1
|
||||
|
||||
// sign a proposal for first time
|
||||
@@ -179,7 +179,7 @@ func TestDifferByTimestamp(t *testing.T) {
|
||||
require.Nil(t, err)
|
||||
privVal := GenFilePV(tempFile.Name())
|
||||
|
||||
block1 := types.PartSetHeader{5, []byte{1, 2, 3}}
|
||||
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{5, []byte{1, 2, 3}}}
|
||||
height, round := int64(10), 1
|
||||
chainID := "mychainid"
|
||||
|
||||
@@ -241,11 +241,11 @@ func newVote(addr types.Address, idx int, height int64, round int, typ byte, blo
|
||||
}
|
||||
}
|
||||
|
||||
func newProposal(height int64, round int, partsHeader types.PartSetHeader) *types.Proposal {
|
||||
func newProposal(height int64, round int, blockID types.BlockID) *types.Proposal {
|
||||
return &types.Proposal{
|
||||
Height: height,
|
||||
Round: round,
|
||||
BlockPartsHeader: partsHeader,
|
||||
Timestamp: tmtime.Now(),
|
||||
Height: height,
|
||||
Round: round,
|
||||
BlockID: blockID,
|
||||
Timestamp: tmtime.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ func (e *RemoteSignerError) Error() string {
|
||||
|
||||
func readMsg(r io.Reader) (msg RemoteSignerMsg, err error) {
|
||||
const maxRemoteSignerMsgSize = 1024 * 10
|
||||
_, err = cdc.UnmarshalBinaryReader(r, &msg, maxRemoteSignerMsgSize)
|
||||
_, err = cdc.UnmarshalBinaryLengthPrefixedReader(r, &msg, maxRemoteSignerMsgSize)
|
||||
if _, ok := err.(timeoutError); ok {
|
||||
err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
|
||||
}
|
||||
@@ -256,7 +256,7 @@ func readMsg(r io.Reader) (msg RemoteSignerMsg, err error) {
|
||||
}
|
||||
|
||||
func writeMsg(w io.Writer, msg interface{}) (err error) {
|
||||
_, err = cdc.MarshalBinaryWriter(w, msg)
|
||||
_, err = cdc.MarshalBinaryLengthPrefixedWriter(w, msg)
|
||||
if _, ok := err.(timeoutError); ok {
|
||||
err = cmn.ErrorWrap(ErrConnTimeout, err.Error())
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ func TestInfo(t *testing.T) {
|
||||
proxy := NewAppConnTest(cli)
|
||||
t.Log("Connected")
|
||||
|
||||
resInfo, err := proxy.InfoSync(types.RequestInfo{Version: ""})
|
||||
resInfo, err := proxy.InfoSync(RequestInfo)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
// RequestInfo contains all the information for sending
|
||||
// the abci.RequestInfo message during handshake with the app.
|
||||
// It contains only compile-time version information.
|
||||
var RequestInfo = abci.RequestInfo{
|
||||
Version: version.Version,
|
||||
BlockVersion: version.BlockProtocol.Uint64(),
|
||||
P2PVersion: version.P2PProtocol.Uint64(),
|
||||
}
|
||||
@@ -3,10 +3,10 @@ package mock
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
"github.com/tendermint/tendermint/rpc/client"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
// ABCIApp will send all abci related request to the named app,
|
||||
@@ -23,7 +23,7 @@ var (
|
||||
)
|
||||
|
||||
func (a ABCIApp) ABCIInfo() (*ctypes.ResultABCIInfo, error) {
|
||||
return &ctypes.ResultABCIInfo{a.App.Info(abci.RequestInfo{Version: version.Version})}, nil
|
||||
return &ctypes.ResultABCIInfo{a.App.Info(proxy.RequestInfo)}, nil
|
||||
}
|
||||
|
||||
func (a ABCIApp) ABCIQuery(path string, data cmn.HexBytes) (*ctypes.ResultABCIQuery, error) {
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@ package core
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
)
|
||||
|
||||
// Query the application for some information.
|
||||
@@ -87,7 +87,7 @@ func ABCIQuery(path string, data cmn.HexBytes, height int64, prove bool) (*ctype
|
||||
// }
|
||||
// ```
|
||||
func ABCIInfo() (*ctypes.ResultABCIInfo, error) {
|
||||
resInfo, err := proxyAppQuery.InfoSync(abci.RequestInfo{Version: version.Version})
|
||||
resInfo, err := proxyAppQuery.InfoSync(proxy.RequestInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -173,8 +173,7 @@ func RecoverAndLogHandler(handler http.Handler, logger log.Logger) http.Handler
|
||||
"Panic in RPC HTTP handler", "err", e, "stack",
|
||||
string(debug.Stack()),
|
||||
)
|
||||
rww.WriteHeader(http.StatusInternalServerError)
|
||||
WriteRPCResponseHTTP(rww, types.RPCInternalError("", e.(error)))
|
||||
WriteRPCResponseHTTPError(rww, http.StatusInternalServerError, types.RPCInternalError("", e.(error)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Usage:
|
||||
# `./authors.sh`
|
||||
# Print a list of all authors who have committed to develop since master.
|
||||
#
|
||||
# `./authors.sh <email address>`
|
||||
# Lookup the email address on Github and print the associated username
|
||||
|
||||
author=$1
|
||||
|
||||
if [[ "$author" == "" ]]; then
|
||||
git log master..develop | grep Author | sort | uniq
|
||||
else
|
||||
curl -s "https://api.github.com/search/users?q=$author+in%3Aemail&type=Users&utf8=%E2%9C%93" | jq .items[0].login
|
||||
fi
|
||||
+2
-2
@@ -4,9 +4,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ebuchman/fail-test"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/fail"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/mempool"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
@@ -186,7 +186,7 @@ func (blockExec *BlockExecutor) Commit(
|
||||
state.Validators.Size(),
|
||||
),
|
||||
),
|
||||
mempool.PostCheckMaxGas(state.ConsensusParams.MaxGas),
|
||||
mempool.PostCheckMaxGas(state.ConsensusParams.BlockSize.MaxGas),
|
||||
)
|
||||
|
||||
return res.Data, err
|
||||
|
||||
+18
-30
@@ -27,6 +27,10 @@ type Version struct {
|
||||
Software string
|
||||
}
|
||||
|
||||
// initStateVersion sets the Consensus.Block and Software versions,
|
||||
// but leaves the Consensus.App version blank.
|
||||
// The Consensus.App version will be set during the Handshake, once
|
||||
// we hear from the app what protocol version it is running.
|
||||
var initStateVersion = Version{
|
||||
Consensus: version.Consensus{
|
||||
Block: version.BlockProtocol,
|
||||
@@ -124,7 +128,7 @@ func (state State) IsEmpty() bool {
|
||||
|
||||
// MakeBlock builds a block from the current state with the given txs, commit,
|
||||
// and evidence. Note it also takes a proposerAddress because the state does not
|
||||
// track rounds, and hence doesn't know the correct proposer. TODO: alleviate this!
|
||||
// track rounds, and hence does not know the correct proposer. TODO: fix this!
|
||||
func (state State) MakeBlock(
|
||||
height int64,
|
||||
txs []types.Tx,
|
||||
@@ -136,29 +140,22 @@ func (state State) MakeBlock(
|
||||
// Build base block with block data.
|
||||
block := types.MakeBlock(height, txs, commit, evidence)
|
||||
|
||||
// Fill rest of header with state data.
|
||||
block.Version = state.Version.Consensus
|
||||
block.ChainID = state.ChainID
|
||||
|
||||
// Set time
|
||||
// Set time.
|
||||
var timestamp time.Time
|
||||
if height == 1 {
|
||||
block.Time = state.LastBlockTime // genesis time
|
||||
timestamp = state.LastBlockTime // genesis time
|
||||
} else {
|
||||
block.Time = MedianTime(commit, state.LastValidators)
|
||||
timestamp = MedianTime(commit, state.LastValidators)
|
||||
}
|
||||
|
||||
block.LastBlockID = state.LastBlockID
|
||||
block.TotalTxs = state.LastBlockTotalTx + block.NumTxs
|
||||
|
||||
block.ValidatorsHash = state.Validators.Hash()
|
||||
block.NextValidatorsHash = state.NextValidators.Hash()
|
||||
block.ConsensusHash = state.ConsensusParams.Hash()
|
||||
block.AppHash = state.AppHash
|
||||
block.LastResultsHash = state.LastResultsHash
|
||||
|
||||
// NOTE: we can't use the state.Validators because we don't
|
||||
// IncrementAccum for rounds there.
|
||||
block.ProposerAddress = proposerAddress
|
||||
// Fill rest of header with state data.
|
||||
block.Header.Populate(
|
||||
state.Version.Consensus, state.ChainID,
|
||||
timestamp, state.LastBlockID, state.LastBlockTotalTx+block.NumTxs,
|
||||
state.Validators.Hash(), state.NextValidators.Hash(),
|
||||
state.ConsensusParams.Hash(), state.AppHash, state.LastResultsHash,
|
||||
proposerAddress,
|
||||
)
|
||||
|
||||
return block, block.MakePartSet(types.BlockPartSizeBytes)
|
||||
}
|
||||
@@ -218,7 +215,6 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
|
||||
return State{}, fmt.Errorf("Error in genesis file: %v", err)
|
||||
}
|
||||
|
||||
// Make validators slice
|
||||
var validatorSet, nextValidatorSet *types.ValidatorSet
|
||||
if genDoc.Validators == nil {
|
||||
validatorSet = types.NewValidatorSet(nil)
|
||||
@@ -226,15 +222,7 @@ func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
|
||||
} else {
|
||||
validators := make([]*types.Validator, len(genDoc.Validators))
|
||||
for i, val := range genDoc.Validators {
|
||||
pubKey := val.PubKey
|
||||
address := pubKey.Address()
|
||||
|
||||
// Make validator
|
||||
validators[i] = &types.Validator{
|
||||
Address: address,
|
||||
PubKey: pubKey,
|
||||
VotingPower: val.Power,
|
||||
}
|
||||
validators[i] = types.NewValidator(val.PubKey, val.Power)
|
||||
}
|
||||
validatorSet = types.NewValidatorSet(validators)
|
||||
nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementAccum(1)
|
||||
|
||||
+4
-4
@@ -390,11 +390,11 @@ func TestConsensusParamsChangesSaveLoad(t *testing.T) {
|
||||
|
||||
func makeParams(blockBytes, blockGas, evidenceAge int64) types.ConsensusParams {
|
||||
return types.ConsensusParams{
|
||||
BlockSize: types.BlockSize{
|
||||
BlockSize: types.BlockSizeParams{
|
||||
MaxBytes: blockBytes,
|
||||
MaxGas: blockGas,
|
||||
},
|
||||
EvidenceParams: types.EvidenceParams{
|
||||
Evidence: types.EvidenceParams{
|
||||
MaxAge: evidenceAge,
|
||||
},
|
||||
}
|
||||
@@ -416,7 +416,7 @@ func TestApplyUpdates(t *testing.T) {
|
||||
1: {initParams, abci.ConsensusParams{}, initParams},
|
||||
2: {initParams,
|
||||
abci.ConsensusParams{
|
||||
BlockSize: &abci.BlockSize{
|
||||
BlockSize: &abci.BlockSizeParams{
|
||||
MaxBytes: 44,
|
||||
MaxGas: 55,
|
||||
},
|
||||
@@ -424,7 +424,7 @@ func TestApplyUpdates(t *testing.T) {
|
||||
makeParams(44, 55, 3)},
|
||||
3: {initParams,
|
||||
abci.ConsensusParams{
|
||||
EvidenceParams: &abci.EvidenceParams{
|
||||
Evidence: &abci.EvidenceParams{
|
||||
MaxAge: 66,
|
||||
},
|
||||
},
|
||||
|
||||
+1
-1
@@ -251,7 +251,7 @@ func LoadConsensusParams(db dbm.DB, height int64) (types.ConsensusParams, error)
|
||||
return empty, ErrNoConsensusParamsForHeight{height}
|
||||
}
|
||||
|
||||
if paramsInfo.ConsensusParams == empty {
|
||||
if paramsInfo.ConsensusParams.Equals(&empty) {
|
||||
paramsInfo2 := loadConsensusParamsInfo(db, paramsInfo.LastHeightChanged)
|
||||
if paramsInfo2 == nil {
|
||||
panic(
|
||||
|
||||
+23
-33
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
@@ -21,22 +21,19 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
|
||||
// Validate basic info.
|
||||
if block.Version != state.Version.Consensus {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.Version. Expected %v, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.Version. Expected %v, got %v",
|
||||
state.Version.Consensus,
|
||||
block.Version,
|
||||
)
|
||||
}
|
||||
if block.ChainID != state.ChainID {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.ChainID. Expected %v, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.ChainID. Expected %v, got %v",
|
||||
state.ChainID,
|
||||
block.ChainID,
|
||||
)
|
||||
}
|
||||
if block.Height != state.LastBlockHeight+1 {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.Height. Expected %v, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.Height. Expected %v, got %v",
|
||||
state.LastBlockHeight+1,
|
||||
block.Height,
|
||||
)
|
||||
@@ -44,16 +41,15 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
|
||||
// Validate prev block info.
|
||||
if !block.LastBlockID.Equals(state.LastBlockID) {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.LastBlockID. Expected %v, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v",
|
||||
state.LastBlockID,
|
||||
block.LastBlockID,
|
||||
)
|
||||
}
|
||||
|
||||
newTxs := int64(len(block.Data.Txs))
|
||||
if block.TotalTxs != state.LastBlockTotalTx+newTxs {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.TotalTxs. Expected %v, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v",
|
||||
state.LastBlockTotalTx+newTxs,
|
||||
block.TotalTxs,
|
||||
)
|
||||
@@ -61,46 +57,44 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
|
||||
// Validate app info
|
||||
if !bytes.Equal(block.AppHash, state.AppHash) {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.AppHash. Expected %X, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.AppHash. Expected %X, got %v",
|
||||
state.AppHash,
|
||||
block.AppHash,
|
||||
)
|
||||
}
|
||||
if !bytes.Equal(block.ConsensusHash, state.ConsensusParams.Hash()) {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.ConsensusHash. Expected %X, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.ConsensusHash. Expected %X, got %v",
|
||||
state.ConsensusParams.Hash(),
|
||||
block.ConsensusHash,
|
||||
)
|
||||
}
|
||||
if !bytes.Equal(block.LastResultsHash, state.LastResultsHash) {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.LastResultsHash. Expected %X, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.LastResultsHash. Expected %X, got %v",
|
||||
state.LastResultsHash,
|
||||
block.LastResultsHash,
|
||||
)
|
||||
}
|
||||
if !bytes.Equal(block.ValidatorsHash, state.Validators.Hash()) {
|
||||
return fmt.Errorf(
|
||||
"Wrong Block.Header.ValidatorsHash. Expected %X, got %v",
|
||||
return fmt.Errorf("Wrong Block.Header.ValidatorsHash. Expected %X, got %v",
|
||||
state.Validators.Hash(),
|
||||
block.ValidatorsHash,
|
||||
)
|
||||
}
|
||||
if !bytes.Equal(block.NextValidatorsHash, state.NextValidators.Hash()) {
|
||||
return fmt.Errorf("Wrong Block.Header.NextValidatorsHash. Expected %X, got %v", state.NextValidators.Hash(), block.NextValidatorsHash)
|
||||
return fmt.Errorf("Wrong Block.Header.NextValidatorsHash. Expected %X, got %v",
|
||||
state.NextValidators.Hash(),
|
||||
block.NextValidatorsHash,
|
||||
)
|
||||
}
|
||||
|
||||
// Validate block LastCommit.
|
||||
if block.Height == 1 {
|
||||
if len(block.LastCommit.Precommits) != 0 {
|
||||
return errors.New("Block at height 1 (first block) should have no LastCommit precommits")
|
||||
return errors.New("Block at height 1 can't have LastCommit precommits")
|
||||
}
|
||||
} else {
|
||||
if len(block.LastCommit.Precommits) != state.LastValidators.Size() {
|
||||
return fmt.Errorf(
|
||||
"Invalid block commit size. Expected %v, got %v",
|
||||
return fmt.Errorf("Invalid block commit size. Expected %v, got %v",
|
||||
state.LastValidators.Size(),
|
||||
len(block.LastCommit.Precommits),
|
||||
)
|
||||
@@ -115,8 +109,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
// Validate block Time
|
||||
if block.Height > 1 {
|
||||
if !block.Time.After(state.LastBlockTime) {
|
||||
return fmt.Errorf(
|
||||
"Block time %v not greater than last block time %v",
|
||||
return fmt.Errorf("Block time %v not greater than last block time %v",
|
||||
block.Time,
|
||||
state.LastBlockTime,
|
||||
)
|
||||
@@ -124,8 +117,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
|
||||
medianTime := MedianTime(block.LastCommit, state.LastValidators)
|
||||
if !block.Time.Equal(medianTime) {
|
||||
return fmt.Errorf(
|
||||
"Invalid block time. Expected %v, got %v",
|
||||
return fmt.Errorf("Invalid block time. Expected %v, got %v",
|
||||
medianTime,
|
||||
block.Time,
|
||||
)
|
||||
@@ -133,8 +125,7 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
} else if block.Height == 1 {
|
||||
genesisTime := state.LastBlockTime
|
||||
if !block.Time.Equal(genesisTime) {
|
||||
return fmt.Errorf(
|
||||
"Block time %v is not equal to genesis time %v",
|
||||
return fmt.Errorf("Block time %v is not equal to genesis time %v",
|
||||
block.Time,
|
||||
genesisTime,
|
||||
)
|
||||
@@ -158,10 +149,9 @@ func validateBlock(stateDB dbm.DB, state State, block *types.Block) error {
|
||||
// NOTE: We can't actually verify it's the right proposer because we dont
|
||||
// know what round the block was first proposed. So just check that it's
|
||||
// a legit address and a known validator.
|
||||
if len(block.ProposerAddress) != tmhash.Size ||
|
||||
if len(block.ProposerAddress) != crypto.AddressSize ||
|
||||
!state.Validators.HasAddress(block.ProposerAddress) {
|
||||
return fmt.Errorf(
|
||||
"Block.Header.ProposerAddress, %X, is not a validator",
|
||||
return fmt.Errorf("Block.Header.ProposerAddress, %X, is not a validator",
|
||||
block.ProposerAddress,
|
||||
)
|
||||
}
|
||||
@@ -178,7 +168,7 @@ func VerifyEvidence(stateDB dbm.DB, state State, evidence types.Evidence) error
|
||||
height := state.LastBlockHeight
|
||||
|
||||
evidenceAge := height - evidence.Height()
|
||||
maxAge := state.ConsensusParams.EvidenceParams.MaxAge
|
||||
maxAge := state.ConsensusParams.Evidence.MaxAge
|
||||
if evidenceAge > maxAge {
|
||||
return fmt.Errorf("Evidence from height %d is too old. Min height is %d",
|
||||
evidence.Height(), height-maxAge)
|
||||
|
||||
@@ -14,6 +14,7 @@ ENV GOBIN $GOPATH/bin
|
||||
WORKDIR $REPO
|
||||
|
||||
# Copy in the code
|
||||
# TODO: rewrite to only copy Makefile & other files?
|
||||
COPY . $REPO
|
||||
|
||||
# Install the vendored dependencies
|
||||
@@ -21,16 +22,18 @@ COPY . $REPO
|
||||
RUN make get_tools
|
||||
RUN make get_vendor_deps
|
||||
|
||||
# Now copy in the code
|
||||
# NOTE: this will overwrite whatever is in vendor/
|
||||
COPY . $REPO
|
||||
|
||||
# install ABCI CLI
|
||||
RUN make install_abci
|
||||
|
||||
# install Tendermint
|
||||
RUN make install
|
||||
|
||||
RUN tendermint testnet --node-dir-prefix="mach" --v=4 --populate-persistent-peers=false --o=$REPO/test/p2p/data
|
||||
|
||||
# Now copy in the code
|
||||
# NOTE: this will overwrite whatever is in vendor/
|
||||
COPY . $REPO
|
||||
|
||||
# expose the volume for debugging
|
||||
VOLUME $REPO
|
||||
|
||||
|
||||
+3
-6
@@ -19,7 +19,7 @@ docker network create --driver bridge --subnet 172.57.0.0/16 my_testnet
|
||||
```
|
||||
|
||||
This gives us a new network with IP addresses in the rage `172.57.0.0 - 172.57.255.255`.
|
||||
Peers on the network can have any IP address in this range.
|
||||
Peers on the network can have any IP address in this range.
|
||||
For our four node network, let's pick `172.57.0.101 - 172.57.0.104`.
|
||||
Since we use Tendermint's default listening port of 26656, our list of seed nodes will look like:
|
||||
|
||||
@@ -37,7 +37,7 @@ for i in $(seq 1 4); do
|
||||
--ip="172.57.0.$((100 + $i))" \
|
||||
--name local_testnet_$i \
|
||||
--entrypoint tendermint \
|
||||
-e TMHOME=/go/src/github.com/tendermint/tendermint/test/p2p/data/mach$i/core \
|
||||
-e TMHOME=/go/src/github.com/tendermint/tendermint/test/p2p/data/mach$((i-1)) \
|
||||
tendermint_tester node --p2p.persistent_peers 172.57.0.101:26656,172.57.0.102:26656,172.57.0.103:26656,172.57.0.104:26656 --proxy_app=kvstore
|
||||
done
|
||||
```
|
||||
@@ -47,8 +47,5 @@ If you now run `docker ps`, you'll see your containers!
|
||||
We can confirm they are making blocks by checking the `/status` message using `curl` and `jq` to pretty print the output json:
|
||||
|
||||
```
|
||||
curl 172.57.0.101:26657/status | jq .
|
||||
curl 172.57.0.101:26657/status | jq .
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"genesis_time": "2016-06-24T20:01:19.322Z",
|
||||
"chain_id": "chain-9ujDWI",
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "vokz3/FgDAJuNHGPF4Wkzeq5DDVpizlOOLaUeukd4RY="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach1"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "bcU0RlMjEmWH0qKpO1nWibcXBzsd6WiiWm7xPVlTGK0="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach2"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "rmesaX0TWqC0YB6lfqqz/r9Lqk8inEWlmMKYWxL80aE="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach3"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "nryPWM7UtG3NWrirpZHdJTzXy1A3Jz/aMrwLZGHE79k="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach4"
|
||||
}
|
||||
],
|
||||
"app_hash": ""
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "BpYtFp8xSrudBa5aBLRuSPD72PGDAUm0dJORDL3Kd5YJbluUzRefVFrjwoHZv1yeDj2P9xkEi2L3hJCUz/qFkQ=="
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"address": "AE47BBD4B3ACD80BFE17F6E0C66C5B8492A81AE4",
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "vokz3/FgDAJuNHGPF4Wkzeq5DDVpizlOOLaUeukd4RY="
|
||||
},
|
||||
"last_height": "0",
|
||||
"last_round": "0",
|
||||
"last_step": 0,
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "VHqgfHqM4WxcsqQMbCbRWwoylgQQqfHqblC2NvGrOJq+iTPf8WAMAm40cY8XhaTN6rkMNWmLOU44tpR66R3hFg=="
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"genesis_time": "2016-06-24T20:01:19.322Z",
|
||||
"chain_id": "chain-9ujDWI",
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "vokz3/FgDAJuNHGPF4Wkzeq5DDVpizlOOLaUeukd4RY="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach1"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "bcU0RlMjEmWH0qKpO1nWibcXBzsd6WiiWm7xPVlTGK0="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach2"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "rmesaX0TWqC0YB6lfqqz/r9Lqk8inEWlmMKYWxL80aE="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach3"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "nryPWM7UtG3NWrirpZHdJTzXy1A3Jz/aMrwLZGHE79k="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach4"
|
||||
}
|
||||
],
|
||||
"app_hash": ""
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "uM6LDVE4wQIIUmq9rc6RxzX8zEGG4G4Jcuw15klzQopF68YfJM4bkbPSavurEcJ4nvBMusKBg2GcARFrZqnFKA=="
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"address": "5D61EE46CCE91F579086522D7FD8CEC3F854E946",
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "bcU0RlMjEmWH0qKpO1nWibcXBzsd6WiiWm7xPVlTGK0="
|
||||
},
|
||||
"last_height": "0",
|
||||
"last_round": "0",
|
||||
"last_step": 0,
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "0EeInmBQL8MSnQq38zSxg47Z7R7Nmcu5a3GtWr9agUNtxTRGUyMSZYfSoqk7WdaJtxcHOx3paKJabvE9WVMYrQ=="
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"genesis_time": "2016-06-24T20:01:19.322Z",
|
||||
"chain_id": "chain-9ujDWI",
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "vokz3/FgDAJuNHGPF4Wkzeq5DDVpizlOOLaUeukd4RY="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach1"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "bcU0RlMjEmWH0qKpO1nWibcXBzsd6WiiWm7xPVlTGK0="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach2"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "rmesaX0TWqC0YB6lfqqz/r9Lqk8inEWlmMKYWxL80aE="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach3"
|
||||
},
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "tendermint/PubKeyEd25519",
|
||||
"value": "nryPWM7UtG3NWrirpZHdJTzXy1A3Jz/aMrwLZGHE79k="
|
||||
},
|
||||
"power": "1",
|
||||
"name": "mach4"
|
||||
}
|
||||
],
|
||||
"app_hash": ""
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"priv_key": {
|
||||
"type": "tendermint/PrivKeyEd25519",
|
||||
"value": "kT3orG0YkipT9rAZbvAjtGk/7Pu1ZeCE8LSUF2jz2uiSs1rdlUVi/gccRlvCRLKvrtSicOyEkmk0FHPOGS3mgg=="
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user