mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-14 08:42:48 +00:00
Compare commits
45 Commits
split_vali
...
show_valid
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ee32d3089 | ||
|
|
8a993c6486 | ||
|
|
3547ce2516 | ||
|
|
f7e463f6d3 | ||
|
|
bc2a9b20c0 | ||
|
|
9e075d8dd5 | ||
|
|
8003786c9a | ||
|
|
2594cec116 | ||
|
|
df32ea4be5 | ||
|
|
f69e2c6d6c | ||
|
|
d5d0d2bd77 | ||
|
|
3d5e06ff7c | ||
|
|
41eaf0e31d | ||
|
|
e33f256359 | ||
|
|
68b467886a | ||
|
|
5c09275691 | ||
|
|
094699f9bc | ||
|
|
c8ab062ce9 | ||
|
|
1765eb2cd2 | ||
|
|
2f64717bb5 | ||
|
|
c4a1cfc5c2 | ||
|
|
0f96bea41d | ||
|
|
9c236ffd6c | ||
|
|
9f8761d105 | ||
|
|
5413c11150 | ||
|
|
a14fd8eba0 | ||
|
|
1bb7e31d63 | ||
|
|
222b8978c8 | ||
|
|
d9a1aad5c5 | ||
|
|
8ef0c2681d | ||
|
|
df20323cd2 | ||
|
|
f17c04c892 | ||
|
|
50ac191f9d | ||
|
|
977a138b1f | ||
|
|
1c6ed0e7d0 | ||
|
|
80c464c9b4 | ||
|
|
5233ac154f | ||
|
|
db04ff4896 | ||
|
|
394edc9230 | ||
|
|
1fa463ecab | ||
|
|
d79d2093ff | ||
|
|
78b7a41319 | ||
|
|
c4d93fd27b | ||
|
|
dc2a338d96 | ||
|
|
417c30b9c1 |
@@ -7,6 +7,13 @@ defaults: &defaults
|
||||
environment:
|
||||
GOBIN: /tmp/workspace/bin
|
||||
|
||||
docs_update_config: &docs_update_config
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: tendermint/docs_deployment
|
||||
environment:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
jobs:
|
||||
setup_dependencies:
|
||||
<<: *defaults
|
||||
@@ -339,10 +346,25 @@ jobs:
|
||||
name: upload
|
||||
command: bash .circleci/codecov.sh -f coverage.txt
|
||||
|
||||
deploy_docs:
|
||||
<<: *docs_update_config
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Trigger website build
|
||||
command: |
|
||||
chamber exec tendermint -- start_website_build
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
test-suite:
|
||||
jobs:
|
||||
- deploy_docs:
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- setup_dependencies
|
||||
- lint:
|
||||
requires:
|
||||
|
||||
72
CHANGELOG.md
72
CHANGELOG.md
@@ -1,13 +1,79 @@
|
||||
# Changelog
|
||||
|
||||
## v0.27.0
|
||||
|
||||
*December 5th, 2018*
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
@danil-lashin, @srmo
|
||||
|
||||
Special thanks to @dlguddus for discovering a [major
|
||||
issue](https://github.com/tendermint/tendermint/issues/2718#issuecomment-440888677)
|
||||
in the proposer selection algorithm.
|
||||
|
||||
Friendly reminder, we have a [bug bounty
|
||||
program](https://hackerone.com/tendermint).
|
||||
|
||||
This release is primarily about fixes to the proposer selection algorithm
|
||||
in preparation for the [Cosmos Game of
|
||||
Stakes](https://blog.cosmos.network/the-game-of-stakes-is-open-for-registration-83a404746ee6).
|
||||
It also makes use of the `ConsensusParams.Validator.PubKeyTypes` to restrict the
|
||||
key types that can be used by validators, and removes the `Heartbeat` consensus
|
||||
message.
|
||||
|
||||
### BREAKING CHANGES:
|
||||
|
||||
* CLI/RPC/Config
|
||||
- [rpc] [\#2932](https://github.com/tendermint/tendermint/issues/2932) Rename `accum` to `proposer_priority`
|
||||
|
||||
* Go API
|
||||
- [db] [\#2913](https://github.com/tendermint/tendermint/pull/2913)
|
||||
ReverseIterator API change: start < end, and end is exclusive.
|
||||
- [types] [\#2932](https://github.com/tendermint/tendermint/issues/2932) Rename `Validator.Accum` to `Validator.ProposerPriority`
|
||||
|
||||
* Blockchain Protocol
|
||||
- [state] [\#2714](https://github.com/tendermint/tendermint/issues/2714) Validators can now only use pubkeys allowed within
|
||||
ConsensusParams.Validator.PubKeyTypes
|
||||
|
||||
* P2P Protocol
|
||||
- [consensus] [\#2871](https://github.com/tendermint/tendermint/issues/2871)
|
||||
Remove *ProposalHeartbeat* message as it serves no real purpose (@srmo)
|
||||
- [state] Fixes for proposer selection:
|
||||
- [\#2785](https://github.com/tendermint/tendermint/issues/2785) Accum for new validators is `-1.125*totalVotingPower` instead of 0
|
||||
- [\#2941](https://github.com/tendermint/tendermint/issues/2941) val.Accum is preserved during ValidatorSet.Update to avoid being
|
||||
reset to 0
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
- [state] [\#2929](https://github.com/tendermint/tendermint/issues/2929) Minor refactor of updateState logic (@danil-lashin)
|
||||
- [node] \#2959 Allow node to start even if software's BlockProtocol is
|
||||
different from state's BlockProtocol
|
||||
- [pex] \#2959 Pex reactor logger uses `module=pex`
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
- [p2p] \#2968 Panic on transport error rather than continuing to run but not
|
||||
accept new connections
|
||||
- [p2p] \#2969 Fix mismatch in peer count between `/net_info` and the prometheus
|
||||
metrics
|
||||
- [rpc] \#2408 `/broadcast_tx_commit`: Fix "interface conversion: interface {} in nil, not EventDataTx" panic (could happen if somebody sent a tx using `/broadcast_tx_commit` while Tendermint was being stopped)
|
||||
- [state] [\#2785](https://github.com/tendermint/tendermint/issues/2785) Fix accum for new validators to be `-1.125*totalVotingPower`
|
||||
instead of 0, forcing them to wait before becoming the proposer. Also:
|
||||
- do not batch clip
|
||||
- keep accums averaged near 0
|
||||
- [txindex/kv] [\#2925](https://github.com/tendermint/tendermint/issues/2925) Don't return false positives when range searching for a prefix of a tag value
|
||||
- [types] [\#2938](https://github.com/tendermint/tendermint/issues/2938) Fix regression in v0.26.4 where we panic on empty
|
||||
genDoc.Validators
|
||||
- [types] [\#2941](https://github.com/tendermint/tendermint/issues/2941) Preserve val.Accum during ValidatorSet.Update to avoid it being
|
||||
reset to 0 every time a validator is updated
|
||||
|
||||
## v0.26.4
|
||||
|
||||
*November 27th, 2018*
|
||||
|
||||
Special thanks to external contributors on this release:
|
||||
ackratos, goolAdapter, james-ray, joe-bowman, kostko,
|
||||
nagarajmanjunath, tomtau
|
||||
|
||||
@ackratos, @goolAdapter, @james-ray, @joe-bowman, @kostko,
|
||||
@nagarajmanjunath, @tomtau
|
||||
|
||||
Friendly reminder, we have a [bug bounty
|
||||
program](https://hackerone.com/tendermint).
|
||||
|
||||
@@ -1,48 +1,34 @@
|
||||
# Pending
|
||||
|
||||
## v0.27.0
|
||||
## v0.27.1
|
||||
|
||||
*TBD*
|
||||
|
||||
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
|
||||
- [rpc] \#2932 Rename `accum` to `proposer_priority`
|
||||
|
||||
- [privval] \#2926 split up `PubKeyMsg` into `PubKeyRequest` and `PubKeyResponse` to be consistent with other message types
|
||||
|
||||
* Apps
|
||||
|
||||
* Go API
|
||||
- [db] [\#2913](https://github.com/tendermint/tendermint/pull/2913)
|
||||
ReverseIterator API change -- start < end, and end is exclusive.
|
||||
- [types] \#2932 Rename `Validator.Accum` to `Validator.ProposerPriority`
|
||||
* Go API
|
||||
- [types] \#2926 memoize consensus public key on initialization of remote signer and return the memoized key on
|
||||
`PrivValidator.GetPubKey()` instead of requesting it again
|
||||
- [types] \#2981 Remove `PrivValidator.GetAddress()`
|
||||
|
||||
* Blockchain Protocol
|
||||
- [state] \#2714 Validators can now only use pubkeys allowed within
|
||||
ConsensusParams.ValidatorParams
|
||||
|
||||
* P2P Protocol
|
||||
- [consensus] [\#2871](https://github.com/tendermint/tendermint/issues/2871)
|
||||
Remove *ProposalHeartbeat* message as it serves no real purpose
|
||||
- [state] Fixes for proposer selection:
|
||||
- \#2785 Accum for new validators is `-1.125*totalVotingPower` instead of 0
|
||||
- \#2941 val.Accum is preserved during ValidatorSet.Update to avoid being
|
||||
reset to 0
|
||||
|
||||
### FEATURES:
|
||||
|
||||
### IMPROVEMENTS:
|
||||
- [rpc] Add `UnconfirmedTxs(limit)` and `NumUnconfirmedTxs()` methods to HTTP/Local clients (@danil-lashin)
|
||||
- [ci/cd] Updated CircleCI job to trigger website build when docs are updated
|
||||
|
||||
### BUG FIXES:
|
||||
- [types] \#2938 Fix regression in v0.26.4 where we panic on empty
|
||||
genDoc.Validators
|
||||
- [state] \#2785 Fix accum for new validators to be `-1.125*totalVotingPower`
|
||||
instead of 0, forcing them to wait before becoming the proposer. Also:
|
||||
- do not batch clip
|
||||
- keep accums averaged near 0
|
||||
- [types] \#2941 Preserve val.Accum during ValidatorSet.Update to avoid it being
|
||||
reset to 0 every time a validator is updated
|
||||
- [kv indexer] \#2912 don't ignore key when executing CONTAINS
|
||||
- [types] \#2926 do not panic if retrieving the private validator's public key fails
|
||||
- [mempool] \#2994 Don't allow txs with negative gas wanted
|
||||
- [p2p] \#2715 fix a bug where seeds don't disconnect from a peer after 3h
|
||||
|
||||
45
UPGRADING.md
45
UPGRADING.md
@@ -3,9 +3,50 @@
|
||||
This guide provides steps to be followed when you upgrade your applications to
|
||||
a newer version of Tendermint Core.
|
||||
|
||||
## v0.27.0
|
||||
|
||||
This release contains some breaking changes to the block and p2p protocols,
|
||||
but does not change any core data structures, so it should be compatible with
|
||||
existing blockchains from the v0.26 series that only used Ed25519 validator keys.
|
||||
Blockchains using Secp256k1 for validators will not be compatible. This is due
|
||||
to the fact that we now enforce which key types validators can use as a
|
||||
consensus param. The default is Ed25519, and Secp256k1 must be activated
|
||||
explicitly.
|
||||
|
||||
It is recommended to upgrade all nodes at once to avoid incompatibilities at the
|
||||
peer layer - namely, the heartbeat consensus message has been removed (only
|
||||
relevant if `create_empty_blocks=false` or `create_empty_blocks_interval > 0`),
|
||||
and the proposer selection algorithm has changed. Since proposer information is
|
||||
never included in the blockchain, this change only affects the peer layer.
|
||||
|
||||
### Go API Changes
|
||||
|
||||
#### libs/db
|
||||
|
||||
The ReverseIterator API has changed the meaning of `start` and `end`.
|
||||
Before, iteration was from `start` to `end`, where
|
||||
`start > end`. Now, iteration is from `end` to `start`, where `start < end`.
|
||||
The iterator also excludes `end`. This change allows a simplified and more
|
||||
intuitive logic, aligning the semantic meaning of `start` and `end` in the
|
||||
`Iterator` and `ReverseIterator`.
|
||||
|
||||
### Applications
|
||||
|
||||
This release enforces a new consensus parameter, the
|
||||
ValidatorParams.PubKeyTypes. Applications must ensure that they only return
|
||||
validator updates with the allowed PubKeyTypes. If a validator update includes a
|
||||
pubkey type that is not included in the ConsensusParams.Validator.PubKeyTypes,
|
||||
block execution will fail and the consensus will halt.
|
||||
|
||||
By default, only Ed25519 pubkeys may be used for validators. Enabling
|
||||
Secp256k1 requires explicit modification of the ConsensusParams.
|
||||
Please update your application accordingly (ie. restrict validators to only be
|
||||
able to use Ed25519 keys, or explicitly add additional key types to the genesis
|
||||
file).
|
||||
|
||||
## v0.26.0
|
||||
|
||||
New 0.26.0 release contains a lot of changes to core data types and protocols. It is not
|
||||
This 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.
|
||||
|
||||
@@ -67,7 +108,7 @@ For more information, see:
|
||||
|
||||
### Go API Changes
|
||||
|
||||
#### crypto.merkle
|
||||
#### 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
|
||||
|
||||
@@ -42,7 +42,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
||||
}
|
||||
|
||||
func makeVote(header *types.Header, blockID types.BlockID, valset *types.ValidatorSet, privVal types.PrivValidator) *types.Vote {
|
||||
addr := privVal.GetAddress()
|
||||
addr := privVal.GetPubKey().Address()
|
||||
idx, _ := valset.GetByAddress(addr)
|
||||
vote := &types.Vote{
|
||||
ValidatorAddress: addr,
|
||||
|
||||
@@ -57,9 +57,10 @@ func initFilesWithConfig(config *cfg.Config) error {
|
||||
GenesisTime: tmtime.Now(),
|
||||
ConsensusParams: types.DefaultConsensusParams(),
|
||||
}
|
||||
key := pv.GetPubKey()
|
||||
genDoc.Validators = []types.GenesisValidator{{
|
||||
Address: pv.GetPubKey().Address(),
|
||||
PubKey: pv.GetPubKey(),
|
||||
Address: key.Address(),
|
||||
PubKey: key,
|
||||
Power: 10,
|
||||
}}
|
||||
|
||||
|
||||
@@ -2,12 +2,20 @@ package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/node"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ShowValidatorCmd.Flags().String("priv_validator_laddr", config.PrivValidatorListenAddr, "Socket address to listen on for connections from external priv_validator process")
|
||||
}
|
||||
|
||||
// ShowValidatorCmd adds capabilities for showing the validator info.
|
||||
var ShowValidatorCmd = &cobra.Command{
|
||||
Use: "show_validator",
|
||||
@@ -16,7 +24,25 @@ var ShowValidatorCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func showValidator(cmd *cobra.Command, args []string) {
|
||||
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile())
|
||||
pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey())
|
||||
var pubKey crypto.PubKey
|
||||
if config.PrivValidatorListenAddr != "" {
|
||||
// If an address is provided, listen on the socket for a connection from an
|
||||
// external signing process and request the public key from there.
|
||||
privValidator, err := node.CreateAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, logger)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get private validator's public key: %v", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
if pvsc, ok := privValidator.(cmn.Service); ok {
|
||||
if err := pvsc.Stop(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get stop private validator client: %v", err)
|
||||
}
|
||||
}
|
||||
pubKey = privValidator.GetPubKey()
|
||||
} else {
|
||||
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile())
|
||||
pubKey = privValidator.GetPubKey()
|
||||
}
|
||||
pubKeyJSONBytes, _ := cdc.MarshalJSON(pubKey)
|
||||
fmt.Println(string(pubKeyJSONBytes))
|
||||
}
|
||||
|
||||
@@ -90,9 +90,10 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
|
||||
|
||||
pvFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidator)
|
||||
pv := privval.LoadFilePV(pvFile)
|
||||
pubKey := pv.GetPubKey()
|
||||
genVals[i] = types.GenesisValidator{
|
||||
Address: pv.GetPubKey().Address(),
|
||||
PubKey: pv.GetPubKey(),
|
||||
Address: pubKey.Address(),
|
||||
PubKey: pubKey,
|
||||
Power: 1,
|
||||
Name: nodeDirName,
|
||||
}
|
||||
@@ -127,14 +128,31 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Gather persistent peer addresses.
|
||||
var (
|
||||
persistentPeers string
|
||||
err error
|
||||
)
|
||||
if populatePersistentPeers {
|
||||
err := populatePersistentPeersInConfigAndWriteIt(config)
|
||||
persistentPeers, err = persistentPeersString(config)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite default config.
|
||||
for i := 0; i < nValidators+nNonValidators; i++ {
|
||||
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i))
|
||||
config.SetRoot(nodeDir)
|
||||
config.P2P.AddrBookStrict = false
|
||||
if populatePersistentPeers {
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(nodeDir, "config", "config.toml"), config)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully initialized %v node directories\n", nValidators+nNonValidators)
|
||||
return nil
|
||||
}
|
||||
@@ -157,28 +175,16 @@ func hostnameOrIP(i int) string {
|
||||
return fmt.Sprintf("%s%d", hostnamePrefix, i)
|
||||
}
|
||||
|
||||
func populatePersistentPeersInConfigAndWriteIt(config *cfg.Config) error {
|
||||
func persistentPeersString(config *cfg.Config) (string, error) {
|
||||
persistentPeers := make([]string, nValidators+nNonValidators)
|
||||
for i := 0; i < nValidators+nNonValidators; i++ {
|
||||
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i))
|
||||
config.SetRoot(nodeDir)
|
||||
nodeKey, err := p2p.LoadNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
return "", err
|
||||
}
|
||||
persistentPeers[i] = p2p.IDAddressString(nodeKey.ID(), fmt.Sprintf("%s:%d", hostnameOrIP(i), p2pPort))
|
||||
}
|
||||
persistentPeersList := strings.Join(persistentPeers, ",")
|
||||
|
||||
for i := 0; i < nValidators+nNonValidators; i++ {
|
||||
nodeDir := filepath.Join(outputDir, fmt.Sprintf("%s%d", nodeDirPrefix, i))
|
||||
config.SetRoot(nodeDir)
|
||||
config.P2P.PersistentPeers = persistentPeersList
|
||||
config.P2P.AddrBookStrict = false
|
||||
|
||||
// overwrite default config
|
||||
cfg.WriteConfigFile(filepath.Join(nodeDir, "config", "config.toml"), config)
|
||||
}
|
||||
|
||||
return nil
|
||||
return strings.Join(persistentPeers, ","), nil
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
abcicli "github.com/tendermint/tendermint/abci/client"
|
||||
"github.com/tendermint/tendermint/abci/client"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
bc "github.com/tendermint/tendermint/blockchain"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
@@ -72,9 +72,10 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato
|
||||
}
|
||||
|
||||
func (vs *validatorStub) signVote(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
||||
addr := vs.PrivValidator.GetPubKey().Address()
|
||||
vote := &types.Vote{
|
||||
ValidatorIndex: vs.Index,
|
||||
ValidatorAddress: vs.PrivValidator.GetAddress(),
|
||||
ValidatorAddress: addr,
|
||||
Height: vs.Height,
|
||||
Round: vs.Round,
|
||||
Timestamp: tmtime.Now(),
|
||||
@@ -151,8 +152,9 @@ func signAddVotes(to *ConsensusState, voteType types.SignedMsgType, hash []byte,
|
||||
|
||||
func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *validatorStub, blockHash []byte) {
|
||||
prevotes := cs.Votes.Prevotes(round)
|
||||
address := privVal.GetPubKey().Address()
|
||||
var vote *types.Vote
|
||||
if vote = prevotes.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
if vote = prevotes.GetByAddress(address); vote == nil {
|
||||
panic("Failed to find prevote from validator")
|
||||
}
|
||||
if blockHash == nil {
|
||||
@@ -168,8 +170,9 @@ func validatePrevote(t *testing.T, cs *ConsensusState, round int, privVal *valid
|
||||
|
||||
func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorStub, blockHash []byte) {
|
||||
votes := cs.LastCommit
|
||||
address := privVal.GetPubKey().Address()
|
||||
var vote *types.Vote
|
||||
if vote = votes.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
if vote = votes.GetByAddress(address); vote == nil {
|
||||
panic("Failed to find precommit from validator")
|
||||
}
|
||||
if !bytes.Equal(vote.BlockID.Hash, blockHash) {
|
||||
@@ -179,8 +182,9 @@ func validateLastPrecommit(t *testing.T, cs *ConsensusState, privVal *validatorS
|
||||
|
||||
func validatePrecommit(t *testing.T, cs *ConsensusState, thisRound, lockRound int, privVal *validatorStub, votedBlockHash, lockedBlockHash []byte) {
|
||||
precommits := cs.Votes.Precommits(thisRound)
|
||||
address := privVal.GetPubKey().Address()
|
||||
var vote *types.Vote
|
||||
if vote = precommits.GetByAddress(privVal.GetAddress()); vote == nil {
|
||||
if vote = precommits.GetByAddress(address); vote == nil {
|
||||
panic("Failed to find precommit from validator")
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,8 @@ func TestReactorWithEvidence(t *testing.T) {
|
||||
// mock the evidence pool
|
||||
// everyone includes evidence of another double signing
|
||||
vIdx := (i + 1) % nValidators
|
||||
evpool := newMockEvidencePool(privVals[vIdx].GetAddress())
|
||||
addr := privVals[vIdx].GetPubKey().Address()
|
||||
evpool := newMockEvidencePool(addr)
|
||||
|
||||
// Make ConsensusState
|
||||
blockExec := sm.NewBlockExecutor(stateDB, log.TestingLogger(), proxyAppConnCon, mempool, evpool)
|
||||
@@ -268,7 +269,8 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
||||
// map of active validators
|
||||
activeVals := make(map[string]struct{})
|
||||
for i := 0; i < nVals; i++ {
|
||||
activeVals[string(css[i].privValidator.GetAddress())] = struct{}{}
|
||||
addr := css[i].privValidator.GetPubKey().Address()
|
||||
activeVals[string(addr)] = struct{}{}
|
||||
}
|
||||
|
||||
// wait till everyone makes block 1
|
||||
@@ -279,7 +281,9 @@ func TestReactorVotingPowerChange(t *testing.T) {
|
||||
//---------------------------------------------------------------------------
|
||||
logger.Debug("---------------------------- Testing changing the voting power of one validator a few times")
|
||||
|
||||
val1PubKey := css[0].privValidator.GetPubKey()
|
||||
pubKey := css[0].privValidator.GetPubKey()
|
||||
|
||||
val1PubKey := pubKey
|
||||
val1PubKeyABCI := types.TM2PB.PubKey(val1PubKey)
|
||||
updateValidatorTx := kvstore.MakeValSetChangeTx(val1PubKeyABCI, 25)
|
||||
previousTotalVotingPower := css[0].GetRoundState().LastValidators.TotalVotingPower()
|
||||
@@ -331,7 +335,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
// map of active validators
|
||||
activeVals := make(map[string]struct{})
|
||||
for i := 0; i < nVals; i++ {
|
||||
activeVals[string(css[i].privValidator.GetAddress())] = struct{}{}
|
||||
addr := css[i].privValidator.GetPubKey().Address()
|
||||
activeVals[string(addr)] = struct{}{}
|
||||
}
|
||||
|
||||
// wait till everyone makes block 1
|
||||
@@ -342,7 +347,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
//---------------------------------------------------------------------------
|
||||
logger.Info("---------------------------- Testing adding one validator")
|
||||
|
||||
newValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||
pubKey := css[nVals].privValidator.GetPubKey()
|
||||
newValidatorPubKey1 := pubKey
|
||||
valPubKey1ABCI := types.TM2PB.PubKey(newValidatorPubKey1)
|
||||
newValidatorTx1 := kvstore.MakeValSetChangeTx(valPubKey1ABCI, testMinPower)
|
||||
|
||||
@@ -369,7 +375,8 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
//---------------------------------------------------------------------------
|
||||
logger.Info("---------------------------- Testing changing the voting power of one validator")
|
||||
|
||||
updateValidatorPubKey1 := css[nVals].privValidator.GetPubKey()
|
||||
pubKey = css[nVals].privValidator.GetPubKey()
|
||||
updateValidatorPubKey1 := pubKey
|
||||
updatePubKey1ABCI := types.TM2PB.PubKey(updateValidatorPubKey1)
|
||||
updateValidatorTx1 := kvstore.MakeValSetChangeTx(updatePubKey1ABCI, 25)
|
||||
previousTotalVotingPower := css[nVals].GetRoundState().LastValidators.TotalVotingPower()
|
||||
@@ -386,11 +393,13 @@ func TestReactorValidatorSetChanges(t *testing.T) {
|
||||
//---------------------------------------------------------------------------
|
||||
logger.Info("---------------------------- Testing adding two validators at once")
|
||||
|
||||
newValidatorPubKey2 := css[nVals+1].privValidator.GetPubKey()
|
||||
pubKey = css[nVals+1].privValidator.GetPubKey()
|
||||
newValidatorPubKey2 := pubKey
|
||||
newVal2ABCI := types.TM2PB.PubKey(newValidatorPubKey2)
|
||||
newValidatorTx2 := kvstore.MakeValSetChangeTx(newVal2ABCI, testMinPower)
|
||||
|
||||
newValidatorPubKey3 := css[nVals+2].privValidator.GetPubKey()
|
||||
pubKey = css[nVals+2].privValidator.GetPubKey()
|
||||
newValidatorPubKey3 := pubKey
|
||||
newVal3ABCI := types.TM2PB.PubKey(newValidatorPubKey3)
|
||||
newValidatorTx3 := kvstore.MakeValSetChangeTx(newVal3ABCI, testMinPower)
|
||||
|
||||
|
||||
@@ -303,7 +303,13 @@ func (h *Handshaker) ReplayBlocks(
|
||||
}
|
||||
state.Validators = types.NewValidatorSet(vals)
|
||||
state.NextValidators = types.NewValidatorSet(vals)
|
||||
} else {
|
||||
// If validator set is not set in genesis and still empty after InitChain, exit.
|
||||
if len(h.genDoc.Validators) == 0 {
|
||||
return nil, fmt.Errorf("Validator set is nil in genesis and still empty after InitChain")
|
||||
}
|
||||
}
|
||||
|
||||
if res.ConsensusParams != nil {
|
||||
state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams)
|
||||
}
|
||||
|
||||
@@ -331,7 +331,9 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
||||
chain, commits, err := makeBlockchainFromWAL(wal)
|
||||
require.NoError(t, err)
|
||||
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), kvstore.ProtocolVersion)
|
||||
pubKey := privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
stateDB, state, store := stateAndStore(config, pubKey, kvstore.ProtocolVersion)
|
||||
store.chain = chain
|
||||
store.commits = commits
|
||||
|
||||
@@ -346,7 +348,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(), kvstore.ProtocolVersion)
|
||||
stateDB, state, _ := stateAndStore(config, pubKey, kvstore.ProtocolVersion)
|
||||
buildAppStateFromChain(proxyApp, stateDB, state, chain, nBlocks, mode)
|
||||
}
|
||||
|
||||
@@ -634,7 +636,8 @@ func TestInitChainUpdateValidators(t *testing.T) {
|
||||
|
||||
config := ResetConfig("proxy_test_")
|
||||
privVal := privval.LoadFilePV(config.PrivValidatorFile())
|
||||
stateDB, state, store := stateAndStore(config, privVal.GetPubKey(), 0x0)
|
||||
pubKey := privVal.GetPubKey()
|
||||
stateDB, state, store := stateAndStore(config, pubKey, 0x0)
|
||||
|
||||
oldValAddr := state.Validators.Validators[0].Address
|
||||
|
||||
@@ -659,12 +662,6 @@ func TestInitChainUpdateValidators(t *testing.T) {
|
||||
assert.Equal(t, newValAddr, expectValAddr)
|
||||
}
|
||||
|
||||
func newInitChainApp(vals []abci.ValidatorUpdate) *initChainApp {
|
||||
return &initChainApp{
|
||||
vals: vals,
|
||||
}
|
||||
}
|
||||
|
||||
// returns the vals on InitChain
|
||||
type initChainApp struct {
|
||||
abci.BaseApplication
|
||||
|
||||
@@ -2,13 +2,14 @@ package consensus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/fail"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -829,13 +830,14 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
|
||||
}
|
||||
|
||||
// if not a validator, we're done
|
||||
if !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
|
||||
logger.Debug("This node is not a validator", "addr", cs.privValidator.GetAddress(), "vals", cs.Validators)
|
||||
address := cs.privValidator.GetPubKey().Address()
|
||||
if !cs.Validators.HasAddress(address) {
|
||||
logger.Debug("This node is not a validator", "addr", address, "vals", cs.Validators)
|
||||
return
|
||||
}
|
||||
logger.Debug("This node is a validator")
|
||||
|
||||
if cs.isProposer() {
|
||||
if cs.isProposer(address) {
|
||||
logger.Info("enterPropose: Our turn to propose", "proposer", cs.Validators.GetProposer().Address, "privValidator", cs.privValidator)
|
||||
cs.decideProposal(height, round)
|
||||
} else {
|
||||
@@ -843,8 +845,8 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) isProposer() bool {
|
||||
return bytes.Equal(cs.Validators.GetProposer().Address, cs.privValidator.GetAddress())
|
||||
func (cs *ConsensusState) isProposer(address []byte) bool {
|
||||
return bytes.Equal(cs.Validators.GetProposer().Address, address)
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) defaultDecideProposal(height int64, round int) {
|
||||
@@ -929,7 +931,7 @@ func (cs *ConsensusState) createProposalBlock() (block *types.Block, blockParts
|
||||
cs.state.Validators.Size(),
|
||||
len(evidence),
|
||||
), maxGas)
|
||||
proposerAddr := cs.privValidator.GetAddress()
|
||||
proposerAddr := cs.privValidator.GetPubKey().Address()
|
||||
block, parts := cs.state.MakeBlock(cs.Height, txs, commit, evidence, proposerAddr)
|
||||
|
||||
return block, parts
|
||||
@@ -1474,7 +1476,8 @@ func (cs *ConsensusState) tryAddVote(vote *types.Vote, peerID p2p.ID) (bool, err
|
||||
if err == ErrVoteHeightMismatch {
|
||||
return added, err
|
||||
} else if voteErr, ok := err.(*types.ErrVoteConflictingVotes); ok {
|
||||
if bytes.Equal(vote.ValidatorAddress, cs.privValidator.GetAddress()) {
|
||||
addr := cs.privValidator.GetPubKey().Address()
|
||||
if bytes.Equal(vote.ValidatorAddress, addr) {
|
||||
cs.Logger.Error("Found conflicting vote from ourselves. Did you unsafe_reset a validator?", "height", vote.Height, "round", vote.Round, "type", vote.Type)
|
||||
return added, err
|
||||
}
|
||||
@@ -1639,7 +1642,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
||||
}
|
||||
|
||||
func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
||||
addr := cs.privValidator.GetAddress()
|
||||
addr := cs.privValidator.GetPubKey().Address()
|
||||
valIndex, _ := cs.Validators.GetByAddress(addr)
|
||||
|
||||
vote := &types.Vote{
|
||||
@@ -1675,7 +1678,8 @@ func (cs *ConsensusState) voteTime() time.Time {
|
||||
// sign the vote and publish on internalMsgQueue
|
||||
func (cs *ConsensusState) signAddVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
|
||||
// if we don't have a key or we're not in the validator set, do nothing
|
||||
if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
|
||||
privValAddr := cs.privValidator.GetPubKey().Address()
|
||||
if cs.privValidator == nil || !cs.Validators.HasAddress(privValAddr) {
|
||||
return nil
|
||||
}
|
||||
vote, err := cs.signVote(type_, hash, header)
|
||||
|
||||
@@ -73,7 +73,8 @@ func TestStateProposerSelection0(t *testing.T) {
|
||||
|
||||
// Commit a block and ensure proposer for the next height is correct.
|
||||
prop := cs1.GetRoundState().Validators.GetProposer()
|
||||
if !bytes.Equal(prop.Address, cs1.privValidator.GetAddress()) {
|
||||
address := cs1.privValidator.GetPubKey().Address()
|
||||
if !bytes.Equal(prop.Address, address) {
|
||||
t.Fatalf("expected proposer to be validator %d. Got %X", 0, prop.Address)
|
||||
}
|
||||
|
||||
@@ -87,7 +88,8 @@ func TestStateProposerSelection0(t *testing.T) {
|
||||
ensureNewRound(newRoundCh, height+1, 0)
|
||||
|
||||
prop = cs1.GetRoundState().Validators.GetProposer()
|
||||
if !bytes.Equal(prop.Address, vss[1].GetAddress()) {
|
||||
addr := vss[1].GetPubKey().Address()
|
||||
if !bytes.Equal(prop.Address, addr) {
|
||||
panic(fmt.Sprintf("expected proposer to be validator %d. Got %X", 1, prop.Address))
|
||||
}
|
||||
}
|
||||
@@ -110,7 +112,8 @@ func TestStateProposerSelection2(t *testing.T) {
|
||||
// everyone just votes nil. we get a new proposer each round
|
||||
for i := 0; i < len(vss); i++ {
|
||||
prop := cs1.GetRoundState().Validators.GetProposer()
|
||||
correctProposer := vss[(i+round)%len(vss)].GetAddress()
|
||||
addr := vss[(i+round)%len(vss)].GetPubKey().Address()
|
||||
correctProposer := addr
|
||||
if !bytes.Equal(prop.Address, correctProposer) {
|
||||
panic(fmt.Sprintf("expected RoundState.Validators.GetProposer() to be validator %d. Got %X", (i+2)%len(vss), prop.Address))
|
||||
}
|
||||
@@ -505,7 +508,8 @@ func TestStateLockPOLRelock(t *testing.T) {
|
||||
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlockHeader)
|
||||
|
||||
@@ -596,7 +600,8 @@ func TestStateLockPOLUnlock(t *testing.T) {
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// everything done from perspective of cs1
|
||||
|
||||
@@ -689,7 +694,8 @@ func TestStateLockPOLSafety1(t *testing.T) {
|
||||
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round and wait for propose and prevote
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
@@ -805,7 +811,8 @@ func TestStateLockPOLSafety2(t *testing.T) {
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// the block for R0: gets polkad but we miss it
|
||||
// (even though we signed it, shhh)
|
||||
@@ -896,7 +903,8 @@ func TestProposeValidBlock(t *testing.T) {
|
||||
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
unlockCh := subscribe(cs1.eventBus, types.EventQueryUnlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round and wait for propose and prevote
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
@@ -982,7 +990,8 @@ func TestSetValidBlockOnDelayedPrevote(t *testing.T) {
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round and wait for propose and prevote
|
||||
startTestRound(cs1, cs1.Height, round)
|
||||
@@ -1041,7 +1050,8 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) {
|
||||
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
validBlockCh := subscribe(cs1.eventBus, types.EventQueryValidBlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
|
||||
|
||||
round = round + 1 // move to round in which P0 is not proposer
|
||||
@@ -1111,7 +1121,8 @@ func TestWaitingTimeoutProposeOnNewRound(t *testing.T) {
|
||||
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round
|
||||
startTestRound(cs1, height, round)
|
||||
@@ -1144,7 +1155,8 @@ func TestRoundSkipOnNilPolkaFromHigherRound(t *testing.T) {
|
||||
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round
|
||||
startTestRound(cs1, height, round)
|
||||
@@ -1177,7 +1189,8 @@ func TestWaitTimeoutProposeOnNilPolkaForTheCurrentRound(t *testing.T) {
|
||||
|
||||
timeoutProposeCh := subscribe(cs1.eventBus, types.EventQueryTimeoutPropose)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round in which PO is not proposer
|
||||
startTestRound(cs1, height, round)
|
||||
@@ -1361,7 +1374,8 @@ func TestStateHalt1(t *testing.T) {
|
||||
timeoutWaitCh := subscribe(cs1.eventBus, types.EventQueryTimeoutWait)
|
||||
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
|
||||
newBlockCh := subscribe(cs1.eventBus, types.EventQueryNewBlock)
|
||||
voteCh := subscribeToVoter(cs1, cs1.privValidator.GetAddress())
|
||||
addr := cs1.privValidator.GetPubKey().Address()
|
||||
voteCh := subscribeToVoter(cs1, addr)
|
||||
|
||||
// start round and wait for propose and prevote
|
||||
startTestRound(cs1, height, round)
|
||||
|
||||
@@ -50,8 +50,9 @@ func TestPeerCatchupRounds(t *testing.T) {
|
||||
|
||||
func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote {
|
||||
privVal := privVals[valIndex]
|
||||
addr := privVal.GetPubKey().Address()
|
||||
vote := &types.Vote{
|
||||
ValidatorAddress: privVal.GetAddress(),
|
||||
ValidatorAddress: addr,
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
|
||||
@@ -8,7 +8,12 @@ module.exports = {
|
||||
lineNumbers: true
|
||||
},
|
||||
themeConfig: {
|
||||
lastUpdated: "Last Updated",
|
||||
lastUpdated: true,
|
||||
algolia: {
|
||||
apiKey: '59f0e2deb984aa9cdf2b3a5fd24ac501',
|
||||
indexName: 'tendermint',
|
||||
debug: false
|
||||
},
|
||||
nav: [{ text: "Back to Tendermint", link: "https://tendermint.com" }],
|
||||
sidebar: [
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ Tendermint blockchain application.
|
||||
|
||||
The following diagram provides a superb example:
|
||||
|
||||
<https://drive.google.com/open?id=1yR2XpRi9YCY9H9uMfcw8-RMJpvDyvjz9>
|
||||

|
||||
|
||||
The end-user application here is the Cosmos Voyager, at the bottom left.
|
||||
Voyager communicates with a REST API exposed by a local Light-Client
|
||||
|
||||
@@ -181,5 +181,13 @@
|
||||
"language": "Javascript",
|
||||
"author": "Dennis McKinnon"
|
||||
}
|
||||
],
|
||||
"aminoLibraries": [
|
||||
{
|
||||
"name": "JS-Amino",
|
||||
"url": "https://github.com/TanNgocDo/Js-Amino",
|
||||
"language": "Javascript",
|
||||
"author": "TanNgocDo"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
# Ecosystem
|
||||
|
||||
The growing list of applications built using various pieces of the
|
||||
Tendermint stack can be found at:
|
||||
Tendermint stack can be found at the [ecosystem page](https://tendermint.com/ecosystem).
|
||||
|
||||
- https://tendermint.com/ecosystem
|
||||
|
||||
We thank the community for their contributions thus far and welcome the
|
||||
We thank the community for their contributions and welcome the
|
||||
addition of new projects. A pull request can be submitted to [this
|
||||
file](https://github.com/tendermint/tendermint/blob/master/docs/app-dev/ecosystem.json)
|
||||
to include your project.
|
||||
|
||||
BIN
docs/imgs/cosmos-tendermint-stack-4k.jpg
Normal file
BIN
docs/imgs/cosmos-tendermint-stack-4k.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 625 KiB |
@@ -70,10 +70,6 @@ Tendermint is in essence similar software, but with two key differences:
|
||||
the application logic that's right for them, from key-value store to
|
||||
cryptocurrency to e-voting platform and beyond.
|
||||
|
||||
The layout of this Tendermint website content is also ripped directly
|
||||
and without shame from [consul.io](https://www.consul.io/) and the other
|
||||
[Hashicorp sites](https://www.hashicorp.com/#tools).
|
||||
|
||||
### Bitcoin, Ethereum, etc.
|
||||
|
||||
Tendermint emerged in the tradition of cryptocurrencies like Bitcoin,
|
||||
|
||||
@@ -14,31 +14,31 @@ please submit them to our [bug bounty](https://tendermint.com/security)!
|
||||
|
||||
### Data Structures
|
||||
|
||||
- [Encoding and Digests](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md)
|
||||
- [Blockchain](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md)
|
||||
- [State](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/state.md)
|
||||
- [Encoding and Digests](./blockchain/encoding.md)
|
||||
- [Blockchain](./blockchain/blockchain.md)
|
||||
- [State](./blockchain/state.md)
|
||||
|
||||
### Consensus Protocol
|
||||
|
||||
- [Consensus Algorithm](/docs/spec/consensus/consensus.md)
|
||||
- [Creating a proposal](/docs/spec/consensus/creating-proposal.md)
|
||||
- [Time](/docs/spec/consensus/bft-time.md)
|
||||
- [Light-Client](/docs/spec/consensus/light-client.md)
|
||||
- [Consensus Algorithm](./consensus/consensus.md)
|
||||
- [Creating a proposal](./consensus/creating-proposal.md)
|
||||
- [Time](./consensus/bft-time.md)
|
||||
- [Light-Client](./consensus/light-client.md)
|
||||
|
||||
### P2P and Network Protocols
|
||||
|
||||
- [The Base P2P Layer](https://github.com/tendermint/tendermint/tree/master/docs/spec/p2p): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections
|
||||
- [Peer Exchange (PEX)](https://github.com/tendermint/tendermint/tree/master/docs/spec/reactors/pex): gossip known peer addresses so peers can find each other
|
||||
- [Block Sync](https://github.com/tendermint/tendermint/tree/master/docs/spec/reactors/block_sync): gossip blocks so peers can catch up quickly
|
||||
- [Consensus](https://github.com/tendermint/tendermint/tree/master/docs/spec/reactors/consensus): gossip votes and block parts so new blocks can be committed
|
||||
- [Mempool](https://github.com/tendermint/tendermint/tree/master/docs/spec/reactors/mempool): gossip transactions so they get included in blocks
|
||||
- Evidence: Forthcoming, see [this issue](https://github.com/tendermint/tendermint/issues/2329).
|
||||
- [The Base P2P Layer](./p2p/): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections
|
||||
- [Peer Exchange (PEX)](./reactors/pex/): gossip known peer addresses so peers can find each other
|
||||
- [Block Sync](./reactors/block_sync/): gossip blocks so peers can catch up quickly
|
||||
- [Consensus](./reactors/consensus/): gossip votes and block parts so new blocks can be committed
|
||||
- [Mempool](./reactors/mempool/): gossip transactions so they get included in blocks
|
||||
- [Evidence](./reactors/evidence/): sending invalid evidence will stop the peer
|
||||
|
||||
### Software
|
||||
|
||||
- [ABCI](/docs/spec/software/abci.md): Details about interactions between the
|
||||
- [ABCI](./software/abci.md): Details about interactions between the
|
||||
application and consensus engine over ABCI
|
||||
- [Write-Ahead Log](/docs/spec/software/wal.md): Details about how the consensus
|
||||
- [Write-Ahead Log](./software/wal.md): Details about how the consensus
|
||||
engine preserves data and recovers from crash failures
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@@ -19,12 +20,22 @@ var (
|
||||
// inside a test (not in the init func) because
|
||||
// verbose flag only set at the time of testing.
|
||||
func TestingLogger() Logger {
|
||||
return TestingLoggerWithOutput(os.Stdout)
|
||||
}
|
||||
|
||||
// TestingLoggerWOutput returns a TMLogger which writes to (w io.Writer) if testing being run
|
||||
// with the verbose (-v) flag, NopLogger otherwise.
|
||||
//
|
||||
// Note that the call to TestingLoggerWithOutput(w io.Writer) must be made
|
||||
// inside a test (not in the init func) because
|
||||
// verbose flag only set at the time of testing.
|
||||
func TestingLoggerWithOutput(w io.Writer) Logger {
|
||||
if _testingLogger != nil {
|
||||
return _testingLogger
|
||||
}
|
||||
|
||||
if testing.Verbose() {
|
||||
_testingLogger = NewTMLogger(NewSyncWriter(os.Stdout))
|
||||
_testingLogger = NewTMLogger(NewSyncWriter(w))
|
||||
} else {
|
||||
_testingLogger = NewNopLogger()
|
||||
}
|
||||
|
||||
@@ -108,6 +108,10 @@ func PostCheckMaxGas(maxGas int64) PostCheckFunc {
|
||||
if maxGas == -1 {
|
||||
return nil
|
||||
}
|
||||
if res.GasWanted < 0 {
|
||||
return fmt.Errorf("gas wanted %d is negative",
|
||||
res.GasWanted)
|
||||
}
|
||||
if res.GasWanted > maxGas {
|
||||
return fmt.Errorf("gas wanted %d is greater than max gas %d",
|
||||
res.GasWanted, maxGas)
|
||||
@@ -486,11 +490,15 @@ func (mem *Mempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs {
|
||||
return txs
|
||||
}
|
||||
totalBytes += int64(len(memTx.tx)) + aminoOverhead
|
||||
// Check total gas requirement
|
||||
if maxGas > -1 && totalGas+memTx.gasWanted > maxGas {
|
||||
// Check total gas requirement.
|
||||
// If maxGas is negative, skip this check.
|
||||
// Since newTotalGas < masGas, which
|
||||
// must be non-negative, it follows that this won't overflow.
|
||||
newTotalGas := totalGas + memTx.gasWanted
|
||||
if maxGas > -1 && newTotalGas > maxGas {
|
||||
return txs
|
||||
}
|
||||
totalGas += memTx.gasWanted
|
||||
totalGas = newTotalGas
|
||||
txs = append(txs, memTx.tx)
|
||||
}
|
||||
return txs
|
||||
|
||||
37
node/node.go
37
node/node.go
@@ -210,13 +210,18 @@ func NewNode(config *cfg.Config,
|
||||
// what happened during block replay).
|
||||
state = sm.LoadState(stateDB)
|
||||
|
||||
// Ensure the state's block version matches that of the software.
|
||||
// Log the version info.
|
||||
logger.Info("Version info",
|
||||
"software", version.TMCoreSemVer,
|
||||
"block", version.BlockProtocol,
|
||||
"p2p", version.P2PProtocol,
|
||||
)
|
||||
|
||||
// If the state and software differ in block version, at least log it.
|
||||
if state.Version.Consensus.Block != version.BlockProtocol {
|
||||
return nil, fmt.Errorf(
|
||||
"Block version of the software does not match that of the state.\n"+
|
||||
"Got version.BlockProtocol=%v, state.Version.Consensus.Block=%v",
|
||||
version.BlockProtocol,
|
||||
state.Version.Consensus.Block,
|
||||
logger.Info("Software and state have different block protocols",
|
||||
"software", version.BlockProtocol,
|
||||
"state", state.Version.Consensus.Block,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -224,7 +229,7 @@ func NewNode(config *cfg.Config,
|
||||
// If an address is provided, listen on the socket for a connection from an
|
||||
// external signing process.
|
||||
// FIXME: we should start services inside OnStart
|
||||
privValidator, err = createAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, logger)
|
||||
privValidator, err = CreateAndStartPrivValidatorSocketClient(config.PrivValidatorListenAddr, logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error with private validator socket client")
|
||||
}
|
||||
@@ -235,16 +240,19 @@ func NewNode(config *cfg.Config,
|
||||
fastSync := config.FastSync
|
||||
if state.Validators.Size() == 1 {
|
||||
addr, _ := state.Validators.GetByIndex(0)
|
||||
if bytes.Equal(privValidator.GetAddress(), addr) {
|
||||
privValAddr := privValidator.GetPubKey().Address()
|
||||
if bytes.Equal(privValAddr, addr) {
|
||||
fastSync = false
|
||||
}
|
||||
}
|
||||
|
||||
pubKey := privValidator.GetPubKey()
|
||||
addr := pubKey.Address()
|
||||
// Log whether this node is a validator or an observer
|
||||
if state.Validators.HasAddress(privValidator.GetAddress()) {
|
||||
consensusLogger.Info("This node is a validator", "addr", privValidator.GetAddress(), "pubKey", privValidator.GetPubKey())
|
||||
if state.Validators.HasAddress(addr) {
|
||||
consensusLogger.Info("This node is a validator", "addr", addr, "pubKey", pubKey)
|
||||
} else {
|
||||
consensusLogger.Info("This node is not a validator", "addr", privValidator.GetAddress(), "pubKey", privValidator.GetPubKey())
|
||||
consensusLogger.Info("This node is not a validator", "addr", addr, "pubKey", pubKey)
|
||||
}
|
||||
|
||||
csMetrics, p2pMetrics, memplMetrics, smMetrics := metricsProvider()
|
||||
@@ -454,7 +462,7 @@ func NewNode(config *cfg.Config,
|
||||
Seeds: splitAndTrimEmpty(config.P2P.Seeds, ",", " "),
|
||||
SeedMode: config.P2P.SeedMode,
|
||||
})
|
||||
pexReactor.SetLogger(p2pLogger)
|
||||
pexReactor.SetLogger(logger.With("module", "pex"))
|
||||
sw.AddReactor("PEX", pexReactor)
|
||||
}
|
||||
|
||||
@@ -611,7 +619,8 @@ func (n *Node) ConfigureRPC() {
|
||||
rpccore.SetEvidencePool(n.evidencePool)
|
||||
rpccore.SetP2PPeers(n.sw)
|
||||
rpccore.SetP2PTransport(n)
|
||||
rpccore.SetPubKey(n.privValidator.GetPubKey())
|
||||
pubKey := n.privValidator.GetPubKey()
|
||||
rpccore.SetPubKey(pubKey)
|
||||
rpccore.SetGenesisDoc(n.genesisDoc)
|
||||
rpccore.SetAddrBook(n.addrBook)
|
||||
rpccore.SetProxyAppQuery(n.proxyApp.Query())
|
||||
@@ -844,7 +853,7 @@ func saveGenesisDoc(db dbm.DB, genDoc *types.GenesisDoc) {
|
||||
db.SetSync(genesisDocKey, bytes)
|
||||
}
|
||||
|
||||
func createAndStartPrivValidatorSocketClient(
|
||||
func CreateAndStartPrivValidatorSocketClient(
|
||||
listenAddr string,
|
||||
logger log.Logger,
|
||||
) (types.PrivValidator, error) {
|
||||
|
||||
@@ -160,6 +160,7 @@ func NewMConnectionWithConfig(conn net.Conn, chDescs []*ChannelDescriptor, onRec
|
||||
onReceive: onReceive,
|
||||
onError: onError,
|
||||
config: config,
|
||||
created: time.Now(),
|
||||
}
|
||||
|
||||
// Create channels
|
||||
|
||||
@@ -98,13 +98,15 @@ func (ps *PeerSet) Get(peerKey ID) Peer {
|
||||
}
|
||||
|
||||
// Remove discards peer by its Key, if the peer was previously memoized.
|
||||
func (ps *PeerSet) Remove(peer Peer) {
|
||||
// Returns true if the peer was removed, and false if it was not found.
|
||||
// in the set.
|
||||
func (ps *PeerSet) Remove(peer Peer) bool {
|
||||
ps.mtx.Lock()
|
||||
defer ps.mtx.Unlock()
|
||||
|
||||
item := ps.lookup[peer.ID()]
|
||||
if item == nil {
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
index := item.index
|
||||
@@ -116,7 +118,7 @@ func (ps *PeerSet) Remove(peer Peer) {
|
||||
if index == len(ps.list)-1 {
|
||||
ps.list = newList
|
||||
delete(ps.lookup, peer.ID())
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
// Replace the popped item with the last item in the old list.
|
||||
@@ -127,6 +129,7 @@ func (ps *PeerSet) Remove(peer Peer) {
|
||||
lastPeerItem.index = index
|
||||
ps.list = newList
|
||||
delete(ps.lookup, peer.ID())
|
||||
return true
|
||||
}
|
||||
|
||||
// Size returns the number of unique items in the peerSet.
|
||||
|
||||
@@ -60,13 +60,15 @@ func TestPeerSetAddRemoveOne(t *testing.T) {
|
||||
n := len(peerList)
|
||||
// 1. Test removing from the front
|
||||
for i, peerAtFront := range peerList {
|
||||
peerSet.Remove(peerAtFront)
|
||||
removed := peerSet.Remove(peerAtFront)
|
||||
assert.True(t, removed)
|
||||
wantSize := n - i - 1
|
||||
for j := 0; j < 2; j++ {
|
||||
assert.Equal(t, false, peerSet.Has(peerAtFront.ID()), "#%d Run #%d: failed to remove peer", i, j)
|
||||
assert.Equal(t, wantSize, peerSet.Size(), "#%d Run #%d: failed to remove peer and decrement size", i, j)
|
||||
// Test the route of removing the now non-existent element
|
||||
peerSet.Remove(peerAtFront)
|
||||
removed := peerSet.Remove(peerAtFront)
|
||||
assert.False(t, removed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +83,8 @@ func TestPeerSetAddRemoveOne(t *testing.T) {
|
||||
// b) In reverse, remove each element
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
peerAtEnd := peerList[i]
|
||||
peerSet.Remove(peerAtEnd)
|
||||
removed := peerSet.Remove(peerAtEnd)
|
||||
assert.True(t, removed)
|
||||
assert.Equal(t, false, peerSet.Has(peerAtEnd.ID()), "#%d: failed to remove item at end", i)
|
||||
assert.Equal(t, i, peerSet.Size(), "#%d: differing sizes after peerSet.Remove(atEndPeer)", i)
|
||||
}
|
||||
@@ -105,7 +108,8 @@ func TestPeerSetAddRemoveMany(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, peer := range peers {
|
||||
peerSet.Remove(peer)
|
||||
removed := peerSet.Remove(peer)
|
||||
assert.True(t, removed)
|
||||
if peerSet.Has(peer.ID()) {
|
||||
t.Errorf("Failed to remove peer")
|
||||
}
|
||||
|
||||
@@ -211,7 +211,9 @@ func (sw *Switch) OnStop() {
|
||||
// Stop peers
|
||||
for _, p := range sw.peers.List() {
|
||||
p.Stop()
|
||||
sw.peers.Remove(p)
|
||||
if sw.peers.Remove(p) {
|
||||
sw.metrics.Peers.Add(float64(-1))
|
||||
}
|
||||
}
|
||||
|
||||
// Stop reactors
|
||||
@@ -299,8 +301,9 @@ func (sw *Switch) StopPeerGracefully(peer Peer) {
|
||||
}
|
||||
|
||||
func (sw *Switch) stopAndRemovePeer(peer Peer, reason interface{}) {
|
||||
sw.peers.Remove(peer)
|
||||
sw.metrics.Peers.Add(float64(-1))
|
||||
if sw.peers.Remove(peer) {
|
||||
sw.metrics.Peers.Add(float64(-1))
|
||||
}
|
||||
peer.Stop()
|
||||
for _, reactor := range sw.reactors {
|
||||
reactor.RemovePeer(peer, reason)
|
||||
@@ -505,6 +508,12 @@ func (sw *Switch) acceptRoutine() {
|
||||
"err", err,
|
||||
"numPeers", sw.peers.Size(),
|
||||
)
|
||||
// We could instead have a retry loop around the acceptRoutine,
|
||||
// but that would need to stop and let the node shutdown eventually.
|
||||
// So might as well panic and let process managers restart the node.
|
||||
// There's no point in letting the node run without the acceptRoutine,
|
||||
// since it won't be able to accept new connections.
|
||||
panic(fmt.Errorf("accept routine exited: %v", err))
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
@@ -3,10 +3,17 @@ package p2p
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -335,6 +342,54 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
|
||||
assert.False(p.IsRunning())
|
||||
}
|
||||
|
||||
func TestSwitchStopPeerForError(t *testing.T) {
|
||||
s := httptest.NewServer(stdprometheus.UninstrumentedHandler())
|
||||
defer s.Close()
|
||||
|
||||
scrapeMetrics := func() string {
|
||||
resp, _ := http.Get(s.URL)
|
||||
buf, _ := ioutil.ReadAll(resp.Body)
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
namespace, subsystem, name := config.TestInstrumentationConfig().Namespace, MetricsSubsystem, "peers"
|
||||
re := regexp.MustCompile(namespace + `_` + subsystem + `_` + name + ` ([0-9\.]+)`)
|
||||
peersMetricValue := func() float64 {
|
||||
matches := re.FindStringSubmatch(scrapeMetrics())
|
||||
f, _ := strconv.ParseFloat(matches[1], 64)
|
||||
return f
|
||||
}
|
||||
|
||||
p2pMetrics := PrometheusMetrics(namespace)
|
||||
|
||||
// make two connected switches
|
||||
sw1, sw2 := MakeSwitchPair(t, func(i int, sw *Switch) *Switch {
|
||||
// set metrics on sw1
|
||||
if i == 0 {
|
||||
opt := WithMetrics(p2pMetrics)
|
||||
opt(sw)
|
||||
}
|
||||
return initSwitchFunc(i, sw)
|
||||
})
|
||||
|
||||
assert.Equal(t, len(sw1.Peers().List()), 1)
|
||||
assert.EqualValues(t, 1, peersMetricValue())
|
||||
|
||||
// send messages to the peer from sw1
|
||||
p := sw1.Peers().List()[0]
|
||||
p.Send(0x1, []byte("here's a message to send"))
|
||||
|
||||
// stop sw2. this should cause the p to fail,
|
||||
// which results in calling StopPeerForError internally
|
||||
sw2.Stop()
|
||||
|
||||
// now call StopPeerForError explicitly, eg. from a reactor
|
||||
sw1.StopPeerForError(p, fmt.Errorf("some err"))
|
||||
|
||||
assert.Equal(t, len(sw1.Peers().List()), 0)
|
||||
assert.EqualValues(t, 0, peersMetricValue())
|
||||
}
|
||||
|
||||
func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ func MakeSwitch(
|
||||
|
||||
// TODO: let the config be passed in?
|
||||
sw := initSwitch(i, NewSwitch(cfg, t, opts...))
|
||||
sw.SetLogger(log.TestingLogger())
|
||||
sw.SetLogger(log.TestingLogger().With("switch", i))
|
||||
sw.SetNodeKey(&nodeKey)
|
||||
|
||||
ni := nodeInfo.(DefaultNodeInfo)
|
||||
|
||||
@@ -67,7 +67,10 @@ func (sc *IPCVal) OnStart() error {
|
||||
return err
|
||||
}
|
||||
|
||||
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn)
|
||||
sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start a routine to keep the connection alive
|
||||
sc.cancelPing = make(chan struct{}, 1)
|
||||
|
||||
@@ -56,12 +56,6 @@ type FilePV struct {
|
||||
mtx sync.Mutex
|
||||
}
|
||||
|
||||
// GetAddress returns the address of the validator.
|
||||
// Implements PrivValidator.
|
||||
func (pv *FilePV) GetAddress() types.Address {
|
||||
return pv.Address
|
||||
}
|
||||
|
||||
// GetPubKey returns the public key of the validator.
|
||||
// Implements PrivValidator.
|
||||
func (pv *FilePV) GetPubKey() crypto.PubKey {
|
||||
@@ -292,7 +286,9 @@ func (pv *FilePV) saveSigned(height int64, round int, step int8,
|
||||
|
||||
// String returns a string representation of the FilePV.
|
||||
func (pv *FilePV) String() string {
|
||||
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep)
|
||||
// does not error in FilePV:
|
||||
addr := pv.GetPubKey().Address()
|
||||
return fmt.Sprintf("PrivValidator{%v LH:%v, LR:%v, LS:%v}", addr, pv.LastHeight, pv.LastRound, pv.LastStep)
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
@@ -25,10 +25,11 @@ func TestGenLoadValidator(t *testing.T) {
|
||||
height := int64(100)
|
||||
privVal.LastHeight = height
|
||||
privVal.Save()
|
||||
addr := privVal.GetAddress()
|
||||
addr := privVal.GetPubKey().Address()
|
||||
|
||||
privVal = LoadFilePV(tempFile.Name())
|
||||
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
|
||||
loadedAddr := privVal.GetPubKey().Address()
|
||||
assert.Equal(addr, loadedAddr)
|
||||
assert.Equal(height, privVal.LastHeight, "expected privval.LastHeight to have been saved")
|
||||
}
|
||||
|
||||
@@ -42,9 +43,10 @@ func TestLoadOrGenValidator(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
privVal := LoadOrGenFilePV(tempFilePath)
|
||||
addr := privVal.GetAddress()
|
||||
addr := privVal.GetPubKey().Address()
|
||||
privVal = LoadOrGenFilePV(tempFilePath)
|
||||
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
|
||||
loadedAddr := privVal.GetPubKey().Address()
|
||||
assert.Equal(addr, loadedAddr)
|
||||
}
|
||||
|
||||
func TestUnmarshalValidator(t *testing.T) {
|
||||
@@ -81,8 +83,10 @@ func TestUnmarshalValidator(t *testing.T) {
|
||||
require.Nil(err, "%+v", err)
|
||||
|
||||
// make sure the values match
|
||||
assert.EqualValues(addr, val.GetAddress())
|
||||
assert.EqualValues(pubKey, val.GetPubKey())
|
||||
loadedAddr := val.GetPubKey().Address()
|
||||
assert.EqualValues(addr, loadedAddr)
|
||||
loadedKey := val.GetPubKey()
|
||||
assert.EqualValues(pubKey, loadedKey)
|
||||
assert.EqualValues(privKey, val.PrivKey)
|
||||
|
||||
// export it and make sure it is the same
|
||||
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
@@ -15,8 +17,9 @@ import (
|
||||
// RemoteSignerClient implements PrivValidator, it uses a socket to request signatures
|
||||
// from an external process.
|
||||
type RemoteSignerClient struct {
|
||||
conn net.Conn
|
||||
lock sync.Mutex
|
||||
conn net.Conn
|
||||
consensusPubKey crypto.PubKey
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// Check that RemoteSignerClient implements PrivValidator.
|
||||
@@ -25,38 +28,29 @@ var _ types.PrivValidator = (*RemoteSignerClient)(nil)
|
||||
// NewRemoteSignerClient returns an instance of RemoteSignerClient.
|
||||
func NewRemoteSignerClient(
|
||||
conn net.Conn,
|
||||
) *RemoteSignerClient {
|
||||
) (*RemoteSignerClient, error) {
|
||||
sc := &RemoteSignerClient{
|
||||
conn: conn,
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// GetAddress implements PrivValidator.
|
||||
func (sc *RemoteSignerClient) GetAddress() types.Address {
|
||||
pubKey, err := sc.getPubKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, cmn.ErrorWrap(err, "error while retrieving public key for remote signer")
|
||||
}
|
||||
|
||||
return pubKey.Address()
|
||||
// retrieve and memoize the consensus public key once:
|
||||
sc.consensusPubKey = pubKey
|
||||
return sc, nil
|
||||
}
|
||||
|
||||
// GetPubKey implements PrivValidator.
|
||||
func (sc *RemoteSignerClient) GetPubKey() crypto.PubKey {
|
||||
pubKey, err := sc.getPubKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return pubKey
|
||||
return sc.consensusPubKey
|
||||
}
|
||||
|
||||
func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
|
||||
sc.lock.Lock()
|
||||
defer sc.lock.Unlock()
|
||||
|
||||
err := writeMsg(sc.conn, &PubKeyMsg{})
|
||||
err := writeMsg(sc.conn, &PubKeyRequest{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -65,8 +59,16 @@ func (sc *RemoteSignerClient) getPubKey() (crypto.PubKey, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pubKeyResp, ok := res.(*PubKeyResponse)
|
||||
if !ok {
|
||||
return nil, errors.Wrap(ErrUnexpectedResponse, "response is not PubKeyResponse")
|
||||
}
|
||||
|
||||
return res.(*PubKeyMsg).PubKey, nil
|
||||
if pubKeyResp.Error != nil {
|
||||
return nil, errors.Wrap(pubKeyResp.Error, "failed to get private validator's public key")
|
||||
}
|
||||
|
||||
return pubKeyResp.PubKey, nil
|
||||
}
|
||||
|
||||
// SignVote implements PrivValidator.
|
||||
@@ -152,7 +154,8 @@ type RemoteSignerMsg interface{}
|
||||
|
||||
func RegisterRemoteSignerMsg(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*RemoteSignerMsg)(nil), nil)
|
||||
cdc.RegisterConcrete(&PubKeyMsg{}, "tendermint/remotesigner/PubKeyMsg", nil)
|
||||
cdc.RegisterConcrete(&PubKeyRequest{}, "tendermint/remotesigner/PubKeyRequest", nil)
|
||||
cdc.RegisterConcrete(&PubKeyResponse{}, "tendermint/remotesigner/PubKeyResponse", nil)
|
||||
cdc.RegisterConcrete(&SignVoteRequest{}, "tendermint/remotesigner/SignVoteRequest", nil)
|
||||
cdc.RegisterConcrete(&SignedVoteResponse{}, "tendermint/remotesigner/SignedVoteResponse", nil)
|
||||
cdc.RegisterConcrete(&SignProposalRequest{}, "tendermint/remotesigner/SignProposalRequest", nil)
|
||||
@@ -161,9 +164,13 @@ func RegisterRemoteSignerMsg(cdc *amino.Codec) {
|
||||
cdc.RegisterConcrete(&PingResponse{}, "tendermint/remotesigner/PingResponse", nil)
|
||||
}
|
||||
|
||||
// PubKeyMsg is a PrivValidatorSocket message containing the public key.
|
||||
type PubKeyMsg struct {
|
||||
// PubKeyRequest requests the consensus public key from the remote signer.
|
||||
type PubKeyRequest struct{}
|
||||
|
||||
// PubKeyResponse is a PrivValidatorSocket message containing the public key.
|
||||
type PubKeyResponse struct {
|
||||
PubKey crypto.PubKey
|
||||
Error *RemoteSignerError
|
||||
}
|
||||
|
||||
// SignVoteRequest is a PrivValidatorSocket message containing a vote.
|
||||
@@ -223,14 +230,15 @@ func writeMsg(w io.Writer, msg interface{}) (err error) {
|
||||
}
|
||||
|
||||
func handleRequest(req RemoteSignerMsg, chainID string, privVal types.PrivValidator) (RemoteSignerMsg, error) {
|
||||
fmt.Println("handle req", req)
|
||||
var res RemoteSignerMsg
|
||||
var err error
|
||||
|
||||
switch r := req.(type) {
|
||||
case *PubKeyMsg:
|
||||
case *PubKeyRequest:
|
||||
var p crypto.PubKey
|
||||
p = privVal.GetPubKey()
|
||||
res = &PubKeyMsg{p}
|
||||
res = &PubKeyResponse{p, nil}
|
||||
case *SignVoteRequest:
|
||||
err = privVal.SignVote(chainID, r.Vote)
|
||||
if err != nil {
|
||||
|
||||
@@ -107,16 +107,21 @@ func (sc *TCPVal) OnStart() error {
|
||||
}
|
||||
|
||||
sc.conn = conn
|
||||
|
||||
sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn)
|
||||
sc.RemoteSignerClient, err = NewRemoteSignerClient(sc.conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start a routine to keep the connection alive
|
||||
sc.cancelPing = make(chan struct{}, 1)
|
||||
sc.pingTicker = time.NewTicker(sc.connHeartbeat)
|
||||
go func() {
|
||||
/*go func() {
|
||||
for {
|
||||
select {
|
||||
case <-sc.pingTicker.C:
|
||||
sc.Logger.Error(
|
||||
"Pinging",
|
||||
)
|
||||
err := sc.Ping()
|
||||
if err != nil {
|
||||
sc.Logger.Error(
|
||||
@@ -125,11 +130,14 @@ func (sc *TCPVal) OnStart() error {
|
||||
)
|
||||
}
|
||||
case <-sc.cancelPing:
|
||||
sc.Logger.Error(
|
||||
"Pinging Stopped",
|
||||
)
|
||||
sc.pingTicker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}()*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package privval
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
@@ -63,13 +64,7 @@ func NewRemoteSigner(
|
||||
|
||||
// OnStart implements cmn.Service.
|
||||
func (rs *RemoteSigner) OnStart() error {
|
||||
conn, err := rs.connect()
|
||||
if err != nil {
|
||||
rs.Logger.Error("OnStart", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
go rs.handleConnection(conn)
|
||||
go rs.handleConnection()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -86,75 +81,86 @@ func (rs *RemoteSigner) OnStop() {
|
||||
}
|
||||
|
||||
func (rs *RemoteSigner) connect() (net.Conn, error) {
|
||||
for retries := rs.connRetries; retries > 0; retries-- {
|
||||
// Don't sleep if it is the first retry.
|
||||
if retries != rs.connRetries {
|
||||
time.Sleep(rs.connDeadline)
|
||||
}
|
||||
//for retries := rs.connRetries; retries > 0; retries-- {
|
||||
// Don't sleep if it is the first retry.
|
||||
//if retries != rs.connRetries {
|
||||
// time.Sleep(rs.connDeadline)
|
||||
//}
|
||||
|
||||
conn, err := cmn.Connect(rs.addr)
|
||||
if err != nil {
|
||||
rs.Logger.Error(
|
||||
"connect",
|
||||
"addr", rs.addr,
|
||||
"err", err,
|
||||
)
|
||||
conn, err := cmn.Connect(rs.addr)
|
||||
if err != nil {
|
||||
rs.Logger.Error(
|
||||
"connect",
|
||||
"addr", rs.addr,
|
||||
"err", err,
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
|
||||
rs.Logger.Error(
|
||||
"connect",
|
||||
"err", err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
conn, err = p2pconn.MakeSecretConnection(conn, rs.privKey)
|
||||
if err != nil {
|
||||
rs.Logger.Error(
|
||||
"connect",
|
||||
"err", err,
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
|
||||
// rs.Logger.Error(
|
||||
// "connect",
|
||||
// "err", err,
|
||||
// )
|
||||
// //continue
|
||||
// return nil, err
|
||||
//}
|
||||
|
||||
conn, err = p2pconn.MakeSecretConnection(conn, rs.privKey)
|
||||
if err != nil {
|
||||
rs.Logger.Error(
|
||||
"connect",
|
||||
"err", err,
|
||||
)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println("connected", conn.RemoteAddr())
|
||||
return conn, nil
|
||||
//}
|
||||
|
||||
return nil, ErrDialRetryMax
|
||||
}
|
||||
|
||||
func (rs *RemoteSigner) handleConnection(conn net.Conn) {
|
||||
for {
|
||||
func (rs *RemoteSigner) handleConnection() {
|
||||
for { // establish connection loop:
|
||||
if !rs.IsRunning() {
|
||||
return // Ignore error from listener closing.
|
||||
}
|
||||
|
||||
fmt.Println("Connecting again ...")
|
||||
conn, err := rs.connect()
|
||||
if err != nil {
|
||||
rs.Logger.Error("OnStart", "err", err)
|
||||
fmt.Println("failed to connect", err)
|
||||
time.Sleep(rs.connDeadline)
|
||||
continue
|
||||
}
|
||||
// Reset the connection deadline
|
||||
conn.SetDeadline(time.Now().Add(rs.connDeadline))
|
||||
//conn.SetDeadline(time.Now().Add(rs.connDeadline*10))
|
||||
|
||||
req, err := readMsg(conn)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
rs.Logger.Error("handleConnection", "err", err)
|
||||
for { // handle request loop
|
||||
req, err := readMsg(conn)
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
rs.Logger.Error("handleConnection readMsg", "err", err)
|
||||
}
|
||||
conn.Close()
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
res, err := handleRequest(req, rs.chainID, rs.privVal)
|
||||
res, err := handleRequest(req, rs.chainID, rs.privVal)
|
||||
|
||||
if err != nil {
|
||||
// only log the error; we'll reply with an error in res
|
||||
rs.Logger.Error("handleConnection", "err", err)
|
||||
}
|
||||
if err != nil {
|
||||
// only log the error; we'll reply with an error in res
|
||||
rs.Logger.Error("handleConnection handleRequest", "err", err)
|
||||
}
|
||||
|
||||
err = writeMsg(conn, res)
|
||||
if err != nil {
|
||||
rs.Logger.Error("handleConnection", "err", err)
|
||||
return
|
||||
err = writeMsg(conn, res)
|
||||
if err != nil {
|
||||
rs.Logger.Error("handleConnection writeMsg", "err", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,10 @@ func TestSocketPVAddress(t *testing.T) {
|
||||
defer sc.Stop()
|
||||
defer rs.Stop()
|
||||
|
||||
serverAddr := rs.privVal.GetAddress()
|
||||
|
||||
clientAddr := sc.GetAddress()
|
||||
serverAddr := rs.privVal.GetPubKey().Address()
|
||||
clientAddr := sc.GetPubKey().Address()
|
||||
|
||||
assert.Equal(t, serverAddr, clientAddr)
|
||||
|
||||
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
|
||||
assert.Equal(t, serverAddr, sc.GetAddress())
|
||||
|
||||
}
|
||||
|
||||
func TestSocketPVPubKey(t *testing.T) {
|
||||
@@ -47,12 +42,10 @@ func TestSocketPVPubKey(t *testing.T) {
|
||||
clientKey, err := sc.getPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
privKey := rs.privVal.GetPubKey()
|
||||
privvalPubKey := rs.privVal.GetPubKey()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, privKey, clientKey)
|
||||
|
||||
// TODO(xla): Remove when PrivValidator2 replaced PrivValidator.
|
||||
assert.Equal(t, privKey, sc.GetPubKey())
|
||||
assert.Equal(t, privvalPubKey, clientKey)
|
||||
}
|
||||
|
||||
func TestSocketPVProposal(t *testing.T) {
|
||||
@@ -153,9 +146,9 @@ func TestSocketPVDeadline(t *testing.T) {
|
||||
go func(sc *TCPVal) {
|
||||
defer close(listenc)
|
||||
|
||||
require.NoError(t, sc.Start())
|
||||
assert.Equal(t, sc.Start().(cmn.Error).Data(), ErrConnTimeout)
|
||||
|
||||
assert.True(t, sc.IsRunning())
|
||||
assert.False(t, sc.IsRunning())
|
||||
}(sc)
|
||||
|
||||
for {
|
||||
@@ -174,9 +167,6 @@ func TestSocketPVDeadline(t *testing.T) {
|
||||
}
|
||||
|
||||
<-listenc
|
||||
|
||||
_, err := sc.getPubKey()
|
||||
assert.Equal(t, err.(cmn.Error).Data(), ErrConnTimeout)
|
||||
}
|
||||
|
||||
func TestRemoteSignerRetry(t *testing.T) {
|
||||
@@ -310,14 +300,15 @@ func TestErrUnexpectedResponse(t *testing.T) {
|
||||
testStartSocketPV(t, readyc, sc)
|
||||
defer sc.Stop()
|
||||
RemoteSignerConnDeadline(time.Millisecond)(rs)
|
||||
RemoteSignerConnRetries(1e6)(rs)
|
||||
|
||||
RemoteSignerConnRetries(100)(rs)
|
||||
// we do not want to Start() the remote signer here and instead use the connection to
|
||||
// reply with intentionally wrong replies below:
|
||||
rsConn, err := rs.connect()
|
||||
defer rsConn.Close()
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, rsConn)
|
||||
// send over public key to get the remote signer running:
|
||||
go testReadWriteResponse(t, &PubKeyResponse{}, rsConn)
|
||||
<-readyc
|
||||
|
||||
// Proposal:
|
||||
|
||||
@@ -109,6 +109,24 @@ func (c *HTTP) broadcastTX(route string, tx types.Tx) (*ctypes.ResultBroadcastTx
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *HTTP) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
result := new(ctypes.ResultUnconfirmedTxs)
|
||||
_, err := c.rpc.Call("unconfirmed_txs", map[string]interface{}{"limit": limit}, result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unconfirmed_txs")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *HTTP) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
result := new(ctypes.ResultUnconfirmedTxs)
|
||||
_, err := c.rpc.Call("num_unconfirmed_txs", map[string]interface{}{}, result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "num_unconfirmed_txs")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *HTTP) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
result := new(ctypes.ResultNetInfo)
|
||||
_, err := c.rpc.Call("net_info", map[string]interface{}{}, result)
|
||||
|
||||
@@ -93,3 +93,9 @@ type NetworkClient interface {
|
||||
type EventsClient interface {
|
||||
types.EventBusSubscriber
|
||||
}
|
||||
|
||||
// MempoolClient shows us data about current mempool state.
|
||||
type MempoolClient interface {
|
||||
UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error)
|
||||
NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error)
|
||||
}
|
||||
|
||||
@@ -76,6 +76,14 @@ func (Local) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
|
||||
return core.BroadcastTxSync(tx)
|
||||
}
|
||||
|
||||
func (Local) UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
return core.UnconfirmedTxs(limit)
|
||||
}
|
||||
|
||||
func (Local) NumUnconfirmedTxs() (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
return core.NumUnconfirmedTxs()
|
||||
}
|
||||
|
||||
func (Local) NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
return core.NetInfo()
|
||||
}
|
||||
|
||||
@@ -281,6 +281,42 @@ func TestBroadcastTxCommit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnconfirmedTxs(t *testing.T) {
|
||||
_, _, tx := MakeTxKV()
|
||||
|
||||
mempool := node.MempoolReactor().Mempool
|
||||
_ = mempool.CheckTx(tx, nil)
|
||||
|
||||
for i, c := range GetClients() {
|
||||
mc, ok := c.(client.MempoolClient)
|
||||
require.True(t, ok, "%d", i)
|
||||
txs, err := mc.UnconfirmedTxs(1)
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
assert.Exactly(t, types.Txs{tx}, types.Txs(txs.Txs))
|
||||
}
|
||||
|
||||
mempool.Flush()
|
||||
}
|
||||
|
||||
func TestNumUnconfirmedTxs(t *testing.T) {
|
||||
_, _, tx := MakeTxKV()
|
||||
|
||||
mempool := node.MempoolReactor().Mempool
|
||||
_ = mempool.CheckTx(tx, nil)
|
||||
mempoolSize := mempool.Size()
|
||||
|
||||
for i, c := range GetClients() {
|
||||
mc, ok := c.(client.MempoolClient)
|
||||
require.True(t, ok, "%d", i)
|
||||
res, err := mc.NumUnconfirmedTxs()
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
|
||||
assert.Equal(t, mempoolSize, res.N)
|
||||
}
|
||||
|
||||
mempool.Flush()
|
||||
}
|
||||
|
||||
func TestTx(t *testing.T) {
|
||||
// first we broadcast a tx
|
||||
c := getHTTPClient()
|
||||
|
||||
@@ -15,6 +15,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.ABCIQuery("", "abcd", true)
|
||||
// ```
|
||||
//
|
||||
@@ -69,6 +74,11 @@ func ABCIQuery(path string, data cmn.HexBytes, height int64, prove bool) (*ctype
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.ABCIInfo()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -18,6 +18,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.BlockchainInfo(10, 10)
|
||||
// ```
|
||||
//
|
||||
@@ -123,6 +128,11 @@ func filterMinMax(height, min, max, limit int64) (int64, int64, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.Block(10)
|
||||
// ```
|
||||
//
|
||||
@@ -235,6 +245,11 @@ func Block(heightPtr *int64) (*ctypes.ResultBlock, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.Commit(11)
|
||||
// ```
|
||||
//
|
||||
@@ -329,6 +344,11 @@ func Commit(heightPtr *int64) (*ctypes.ResultCommit, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.BlockResults(10)
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -16,6 +16,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// state, err := client.Validators()
|
||||
// ```
|
||||
//
|
||||
@@ -67,6 +72,11 @@ func Validators(heightPtr *int64) (*ctypes.ResultValidators, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// state, err := client.DumpConsensusState()
|
||||
// ```
|
||||
//
|
||||
@@ -225,6 +235,11 @@ func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// state, err := client.ConsensusState()
|
||||
// ```
|
||||
//
|
||||
@@ -273,6 +288,11 @@ func ConsensusState() (*ctypes.ResultConsensusState, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// state, err := client.ConsensusParams()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -55,6 +55,10 @@ import (
|
||||
//
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
// defer cancel()
|
||||
// query := query.MustParse("tm.event = 'Tx' AND tx.height = 3")
|
||||
@@ -118,6 +122,10 @@ func Subscribe(wsCtx rpctypes.WSRPCContext, query string) (*ctypes.ResultSubscri
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// err = client.Unsubscribe("test-client", query)
|
||||
// ```
|
||||
//
|
||||
@@ -158,6 +166,10 @@ func Unsubscribe(wsCtx rpctypes.WSRPCContext, query string) (*ctypes.ResultUnsub
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// err = client.UnsubscribeAll("test-client")
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -13,6 +13,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.Health()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -24,6 +24,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.BroadcastTxAsync("123")
|
||||
// ```
|
||||
//
|
||||
@@ -64,6 +69,11 @@ func BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.BroadcastTxSync("456")
|
||||
// ```
|
||||
//
|
||||
@@ -118,6 +128,11 @@ func BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.BroadcastTxCommit("789")
|
||||
// ```
|
||||
//
|
||||
@@ -198,7 +213,10 @@ func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
// TODO: configurable?
|
||||
var deliverTxTimeout = rpcserver.WriteTimeout / 2
|
||||
select {
|
||||
case deliverTxResMsg := <-deliverTxResCh: // The tx was included in a block.
|
||||
case deliverTxResMsg, ok := <-deliverTxResCh: // The tx was included in a block.
|
||||
if !ok {
|
||||
return nil, errors.New("Error on broadcastTxCommit: expected DeliverTxResult, got nil. Did the Tendermint stop?")
|
||||
}
|
||||
deliverTxRes := deliverTxResMsg.(types.EventDataTx)
|
||||
return &ctypes.ResultBroadcastTxCommit{
|
||||
CheckTx: *checkTxRes,
|
||||
@@ -225,6 +243,11 @@ func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.UnconfirmedTxs()
|
||||
// ```
|
||||
//
|
||||
@@ -263,6 +286,11 @@ func UnconfirmedTxs(limit int) (*ctypes.ResultUnconfirmedTxs, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.UnconfirmedTxs()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -17,6 +17,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// info, err := client.NetInfo()
|
||||
// ```
|
||||
//
|
||||
@@ -95,6 +100,11 @@ func UnsafeDialPeers(peers []string, persistent bool) (*ctypes.ResultDialPeers,
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// genesis, err := client.Genesis()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -20,6 +20,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// result, err := client.Status()
|
||||
// ```
|
||||
//
|
||||
|
||||
@@ -21,6 +21,11 @@ import (
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// tx, err := client.Tx([]byte("2B8EC32BA2579B3B8606E42C06DE2F7AFA2556EF"), true)
|
||||
// ```
|
||||
//
|
||||
@@ -115,6 +120,11 @@ func Tx(hash []byte, prove bool) (*ctypes.ResultTx, error) {
|
||||
//
|
||||
// ```go
|
||||
// client := client.NewHTTP("tcp://0.0.0.0:26657", "/websocket")
|
||||
// err := client.Start()
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// defer client.Stop()
|
||||
// q, err := tmquery.New("account.owner='Ivan'")
|
||||
// tx, err := client.TxSearch(q, true)
|
||||
// ```
|
||||
|
||||
@@ -172,10 +172,10 @@ func (txi *TxIndex) Search(q *query.Query) ([]*types.TxResult, error) {
|
||||
|
||||
for _, r := range ranges {
|
||||
if !hashesInitialized {
|
||||
hashes = txi.matchRange(r, []byte(r.key))
|
||||
hashes = txi.matchRange(r, startKey(r.key))
|
||||
hashesInitialized = true
|
||||
} else {
|
||||
hashes = intersect(hashes, txi.matchRange(r, []byte(r.key)))
|
||||
hashes = intersect(hashes, txi.matchRange(r, startKey(r.key)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,10 +190,10 @@ func (txi *TxIndex) Search(q *query.Query) ([]*types.TxResult, error) {
|
||||
}
|
||||
|
||||
if !hashesInitialized {
|
||||
hashes = txi.match(c, startKey(c, height))
|
||||
hashes = txi.match(c, startKeyForCondition(c, height))
|
||||
hashesInitialized = true
|
||||
} else {
|
||||
hashes = intersect(hashes, txi.match(c, startKey(c, height)))
|
||||
hashes = intersect(hashes, txi.match(c, startKeyForCondition(c, height)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,18 +332,18 @@ func isRangeOperation(op query.Operator) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (txi *TxIndex) match(c query.Condition, startKey []byte) (hashes [][]byte) {
|
||||
func (txi *TxIndex) match(c query.Condition, startKeyBz []byte) (hashes [][]byte) {
|
||||
if c.Op == query.OpEqual {
|
||||
it := dbm.IteratePrefix(txi.store, startKey)
|
||||
it := dbm.IteratePrefix(txi.store, startKeyBz)
|
||||
defer it.Close()
|
||||
for ; it.Valid(); it.Next() {
|
||||
hashes = append(hashes, it.Value())
|
||||
}
|
||||
} else if c.Op == query.OpContains {
|
||||
// XXX: doing full scan because startKey does not apply here
|
||||
// For example, if startKey = "account.owner=an" and search query = "accoutn.owner CONSISTS an"
|
||||
// we can't iterate with prefix "account.owner=an" because we might miss keys like "account.owner=Ulan"
|
||||
it := txi.store.Iterator(nil, nil)
|
||||
// XXX: startKey does not apply here.
|
||||
// For example, if startKey = "account.owner/an/" and search query = "accoutn.owner CONTAINS an"
|
||||
// we can't iterate with prefix "account.owner/an/" because we might miss keys like "account.owner/Ulan/"
|
||||
it := dbm.IteratePrefix(txi.store, startKey(c.Tag))
|
||||
defer it.Close()
|
||||
for ; it.Valid(); it.Next() {
|
||||
if !isTagKey(it.Key()) {
|
||||
@@ -359,14 +359,14 @@ func (txi *TxIndex) match(c query.Condition, startKey []byte) (hashes [][]byte)
|
||||
return
|
||||
}
|
||||
|
||||
func (txi *TxIndex) matchRange(r queryRange, prefix []byte) (hashes [][]byte) {
|
||||
func (txi *TxIndex) matchRange(r queryRange, startKey []byte) (hashes [][]byte) {
|
||||
// create a map to prevent duplicates
|
||||
hashesMap := make(map[string][]byte)
|
||||
|
||||
lowerBound := r.lowerBoundValue()
|
||||
upperBound := r.upperBoundValue()
|
||||
|
||||
it := dbm.IteratePrefix(txi.store, prefix)
|
||||
it := dbm.IteratePrefix(txi.store, startKey)
|
||||
defer it.Close()
|
||||
LOOP:
|
||||
for ; it.Valid(); it.Next() {
|
||||
@@ -409,16 +409,6 @@ LOOP:
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Keys
|
||||
|
||||
func startKey(c query.Condition, height int64) []byte {
|
||||
var key string
|
||||
if height > 0 {
|
||||
key = fmt.Sprintf("%s/%v/%d/", c.Tag, c.Operand, height)
|
||||
} else {
|
||||
key = fmt.Sprintf("%s/%v/", c.Tag, c.Operand)
|
||||
}
|
||||
return []byte(key)
|
||||
}
|
||||
|
||||
func isTagKey(key []byte) bool {
|
||||
return strings.Count(string(key), tagKeySeparator) == 3
|
||||
}
|
||||
@@ -429,11 +419,36 @@ func extractValueFromKey(key []byte) string {
|
||||
}
|
||||
|
||||
func keyForTag(tag cmn.KVPair, result *types.TxResult) []byte {
|
||||
return []byte(fmt.Sprintf("%s/%s/%d/%d", tag.Key, tag.Value, result.Height, result.Index))
|
||||
return []byte(fmt.Sprintf("%s/%s/%d/%d",
|
||||
tag.Key,
|
||||
tag.Value,
|
||||
result.Height,
|
||||
result.Index,
|
||||
))
|
||||
}
|
||||
|
||||
func keyForHeight(result *types.TxResult) []byte {
|
||||
return []byte(fmt.Sprintf("%s/%d/%d/%d", types.TxHeightKey, result.Height, result.Height, result.Index))
|
||||
return []byte(fmt.Sprintf("%s/%d/%d/%d",
|
||||
types.TxHeightKey,
|
||||
result.Height,
|
||||
result.Height,
|
||||
result.Index,
|
||||
))
|
||||
}
|
||||
|
||||
func startKeyForCondition(c query.Condition, height int64) []byte {
|
||||
if height > 0 {
|
||||
return startKey(c.Tag, c.Operand, height)
|
||||
}
|
||||
return startKey(c.Tag, c.Operand)
|
||||
}
|
||||
|
||||
func startKey(fields ...interface{}) []byte {
|
||||
var b bytes.Buffer
|
||||
for _, f := range fields {
|
||||
b.Write([]byte(fmt.Sprintf("%v", f) + tagKeySeparator))
|
||||
}
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -89,8 +89,10 @@ func TestTxSearch(t *testing.T) {
|
||||
{"account.date >= TIME 2013-05-03T14:45:00Z", 0},
|
||||
// search using CONTAINS
|
||||
{"account.owner CONTAINS 'an'", 1},
|
||||
// search using CONTAINS
|
||||
// search for non existing value using CONTAINS
|
||||
{"account.owner CONTAINS 'Vlad'", 0},
|
||||
// search using the wrong tag (of numeric type) using CONTAINS
|
||||
{"account.number CONTAINS 'Iv'", 0},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -126,7 +128,7 @@ func TestTxSearchOneTxWithMultipleSameTagsButDifferentValues(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTxSearchMultipleTxs(t *testing.T) {
|
||||
allowedTags := []string{"account.number"}
|
||||
allowedTags := []string{"account.number", "account.number.id"}
|
||||
indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
|
||||
|
||||
// indexed first, but bigger height (to test the order of transactions)
|
||||
@@ -160,6 +162,17 @@ func TestTxSearchMultipleTxs(t *testing.T) {
|
||||
err = indexer.Index(txResult3)
|
||||
require.NoError(t, err)
|
||||
|
||||
// indexed fourth (to test we don't include txs with similar tags)
|
||||
// https://github.com/tendermint/tendermint/issues/2908
|
||||
txResult4 := txResultWithTags([]cmn.KVPair{
|
||||
{Key: []byte("account.number.id"), Value: []byte("1")},
|
||||
})
|
||||
txResult4.Tx = types.Tx("Mike's account")
|
||||
txResult4.Height = 2
|
||||
txResult4.Index = 2
|
||||
err = indexer.Index(txResult4)
|
||||
require.NoError(t, err)
|
||||
|
||||
results, err := indexer.Search(query.MustParse("account.number >= 1"))
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@ type voteData struct {
|
||||
}
|
||||
|
||||
func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote {
|
||||
addr := val.GetPubKey().Address()
|
||||
v := &Vote{
|
||||
ValidatorAddress: val.GetAddress(),
|
||||
ValidatorAddress: addr,
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
// PrivValidator defines the functionality of a local Tendermint validator
|
||||
// that signs votes and proposals, and never double signs.
|
||||
type PrivValidator interface {
|
||||
GetAddress() Address // redundant since .PubKey().Address()
|
||||
GetPubKey() crypto.PubKey
|
||||
|
||||
SignVote(chainID string, vote *Vote) error
|
||||
@@ -29,7 +28,7 @@ func (pvs PrivValidatorsByAddress) Len() int {
|
||||
}
|
||||
|
||||
func (pvs PrivValidatorsByAddress) Less(i, j int) bool {
|
||||
return bytes.Compare(pvs[i].GetAddress(), pvs[j].GetAddress()) == -1
|
||||
return bytes.Compare(pvs[i].GetPubKey().Address(), pvs[j].GetPubKey().Address()) == -1
|
||||
}
|
||||
|
||||
func (pvs PrivValidatorsByAddress) Swap(i, j int) {
|
||||
@@ -51,11 +50,6 @@ func NewMockPV() *MockPV {
|
||||
return &MockPV{ed25519.GenPrivKey()}
|
||||
}
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv *MockPV) GetAddress() Address {
|
||||
return pv.privKey.PubKey().Address()
|
||||
}
|
||||
|
||||
// Implements PrivValidator.
|
||||
func (pv *MockPV) GetPubKey() crypto.PubKey {
|
||||
return pv.privKey.PubKey()
|
||||
@@ -85,7 +79,8 @@ func (pv *MockPV) SignProposal(chainID string, proposal *Proposal) error {
|
||||
|
||||
// String returns a string representation of the MockPV.
|
||||
func (pv *MockPV) String() string {
|
||||
return fmt.Sprintf("MockPV{%v}", pv.GetAddress())
|
||||
addr := pv.GetPubKey().Address()
|
||||
return fmt.Sprintf("MockPV{%v}", addr)
|
||||
}
|
||||
|
||||
// XXX: Implement.
|
||||
|
||||
@@ -142,14 +142,15 @@ func TestABCIEvidence(t *testing.T) {
|
||||
blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
|
||||
blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
|
||||
const chainID = "mychain"
|
||||
pubKey := val.GetPubKey()
|
||||
ev := &DuplicateVoteEvidence{
|
||||
PubKey: val.GetPubKey(),
|
||||
PubKey: pubKey,
|
||||
VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID),
|
||||
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
|
||||
}
|
||||
abciEv := TM2PB.Evidence(
|
||||
ev,
|
||||
NewValidatorSet([]*Validator{NewValidator(val.GetPubKey(), 10)}),
|
||||
NewValidatorSet([]*Validator{NewValidator(pubKey, 10)}),
|
||||
time.Now(),
|
||||
)
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ func MakeCommit(blockID BlockID, height int64, round int,
|
||||
|
||||
// all sign
|
||||
for i := 0; i < len(validators); i++ {
|
||||
|
||||
addr := validators[i].GetPubKey().Address()
|
||||
vote := &Vote{
|
||||
ValidatorAddress: validators[i].GetAddress(),
|
||||
ValidatorAddress: addr,
|
||||
ValidatorIndex: i,
|
||||
Height: height,
|
||||
Round: round,
|
||||
|
||||
@@ -101,6 +101,7 @@ func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) {
|
||||
if randPower {
|
||||
votePower += int64(cmn.RandUint32())
|
||||
}
|
||||
val := NewValidator(privVal.GetPubKey(), votePower)
|
||||
pubKey := privVal.GetPubKey()
|
||||
val := NewValidator(pubKey, votePower)
|
||||
return val, privVal
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
// x + (x >> 3) = x + x/8 = x * (1 + 0.125).
|
||||
// MaxTotalVotingPower is the largest int64 `x` with the property that `x + (x >> 3)` is
|
||||
// still in the bounds of int64.
|
||||
const MaxTotalVotingPower = 8198552921648689607
|
||||
const MaxTotalVotingPower = int64(8198552921648689607)
|
||||
|
||||
// ValidatorSet represent a set of *Validator at a given height.
|
||||
// The validators can be fetched by address or index.
|
||||
|
||||
@@ -66,7 +66,8 @@ func TestAddVote(t *testing.T) {
|
||||
|
||||
// t.Logf(">> %v", voteSet)
|
||||
|
||||
if voteSet.GetByAddress(val0.GetAddress()) != nil {
|
||||
val0Addr := val0.GetPubKey().Address()
|
||||
if voteSet.GetByAddress(val0Addr) != nil {
|
||||
t.Errorf("Expected GetByAddress(val0.Address) to be nil")
|
||||
}
|
||||
if voteSet.BitArray().GetIndex(0) {
|
||||
@@ -78,7 +79,7 @@ func TestAddVote(t *testing.T) {
|
||||
}
|
||||
|
||||
vote := &Vote{
|
||||
ValidatorAddress: val0.GetAddress(),
|
||||
ValidatorAddress: val0Addr,
|
||||
ValidatorIndex: 0, // since privValidators are in order
|
||||
Height: height,
|
||||
Round: round,
|
||||
@@ -91,7 +92,7 @@ func TestAddVote(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if voteSet.GetByAddress(val0.GetAddress()) == nil {
|
||||
if voteSet.GetByAddress(val0Addr) == nil {
|
||||
t.Errorf("Expected GetByAddress(val0.Address) to be present")
|
||||
}
|
||||
if !voteSet.BitArray().GetIndex(0) {
|
||||
@@ -118,7 +119,8 @@ func Test2_3Majority(t *testing.T) {
|
||||
}
|
||||
// 6 out of 10 voted for nil.
|
||||
for i := 0; i < 6; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
addr := privValidators[i].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, i)
|
||||
_, err := signAddVote(privValidators[i], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -131,7 +133,8 @@ func Test2_3Majority(t *testing.T) {
|
||||
|
||||
// 7th validator voted for some blockhash
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6)
|
||||
addr := privValidators[6].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 6)
|
||||
_, err := signAddVote(privValidators[6], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -144,7 +147,8 @@ func Test2_3Majority(t *testing.T) {
|
||||
|
||||
// 8th validator voted for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7)
|
||||
addr := privValidators[7].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 7)
|
||||
_, err := signAddVote(privValidators[7], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -176,7 +180,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 66 out of 100 voted for nil.
|
||||
for i := 0; i < 66; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
addr := privValidators[i].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, i)
|
||||
_, err := signAddVote(privValidators[i], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -189,7 +194,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 67th validator voted for nil
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[66].GetAddress(), 66)
|
||||
adrr := privValidators[66].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, adrr, 66)
|
||||
_, err := signAddVote(privValidators[66], withBlockHash(vote, nil), voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -202,7 +208,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 68th validator voted for a different BlockParts PartSetHeader
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[67].GetAddress(), 67)
|
||||
addr := privValidators[67].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 67)
|
||||
blockPartsHeader := PartSetHeader{blockPartsTotal, crypto.CRandBytes(32)}
|
||||
_, err := signAddVote(privValidators[67], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
||||
if err != nil {
|
||||
@@ -216,7 +223,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 69th validator voted for different BlockParts Total
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[68].GetAddress(), 68)
|
||||
addr := privValidators[68].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 68)
|
||||
blockPartsHeader := PartSetHeader{blockPartsTotal + 1, blockPartsHeader.Hash}
|
||||
_, err := signAddVote(privValidators[68], withBlockPartsHeader(vote, blockPartsHeader), voteSet)
|
||||
if err != nil {
|
||||
@@ -230,7 +238,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 70th validator voted for different BlockHash
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[69].GetAddress(), 69)
|
||||
addr := privValidators[69].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 69)
|
||||
_, err := signAddVote(privValidators[69], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -243,7 +252,8 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
// 71st validator voted for the right BlockHash & BlockPartsHeader
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[70].GetAddress(), 70)
|
||||
addr := privValidators[70].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 70)
|
||||
_, err := signAddVote(privValidators[70], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -271,7 +281,8 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
// val0 votes for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
addr := privValidators[0].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 0)
|
||||
added, err := signAddVote(privValidators[0], vote, voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
@@ -280,7 +291,8 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
// val0 votes again for some block.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
addr := privValidators[0].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, cmn.RandBytes(32)), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
|
||||
@@ -289,7 +301,8 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
// val1 votes on another height
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1)
|
||||
addr := privValidators[1].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 1)
|
||||
added, err := signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong height")
|
||||
@@ -298,7 +311,8 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
// val2 votes on another round
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
addr := privValidators[2].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 2)
|
||||
added, err := signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong round")
|
||||
@@ -307,7 +321,8 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
// val3 votes of another type.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[3].GetAddress(), 3)
|
||||
addr := privValidators[3].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 3)
|
||||
added, err := signAddVote(privValidators[3], withType(vote, byte(PrecommitType)), voteSet)
|
||||
if added || err == nil {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
||||
@@ -331,9 +346,10 @@ func TestConflicts(t *testing.T) {
|
||||
BlockID: BlockID{nil, PartSetHeader{}},
|
||||
}
|
||||
|
||||
val0Addr := privValidators[0].GetPubKey().Address()
|
||||
// val0 votes for nil.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
vote := withValidator(voteProto, val0Addr, 0)
|
||||
added, err := signAddVote(privValidators[0], vote, voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
@@ -342,7 +358,7 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
vote := withValidator(voteProto, val0Addr, 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
|
||||
if added {
|
||||
t.Errorf("Expected VoteSet.Add to fail, conflicting vote.")
|
||||
@@ -357,7 +373,7 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
vote := withValidator(voteProto, val0Addr, 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added {
|
||||
t.Errorf("Expected VoteSet.Add to succeed, called SetPeerMaj23().")
|
||||
@@ -372,7 +388,7 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val0 votes again for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[0].GetAddress(), 0)
|
||||
vote := withValidator(voteProto, val0Addr, 0)
|
||||
added, err := signAddVote(privValidators[0], withBlockHash(vote, blockHash2), voteSet)
|
||||
if added {
|
||||
t.Errorf("Expected VoteSet.Add to fail, duplicate SetPeerMaj23() from peerA")
|
||||
@@ -384,7 +400,8 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val1 votes for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[1].GetAddress(), 1)
|
||||
addr := privValidators[1].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 1)
|
||||
added, err := signAddVote(privValidators[1], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
@@ -401,7 +418,8 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val2 votes for blockHash2.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
addr := privValidators[2].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 2)
|
||||
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash2), voteSet)
|
||||
if !added || err != nil {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
@@ -421,7 +439,8 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
// val2 votes for blockHash1.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[2].GetAddress(), 2)
|
||||
addr := privValidators[2].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 2)
|
||||
added, err := signAddVote(privValidators[2], withBlockHash(vote, blockHash1), voteSet)
|
||||
if !added {
|
||||
t.Errorf("Expected VoteSet.Add to succeed")
|
||||
@@ -462,7 +481,8 @@ func TestMakeCommit(t *testing.T) {
|
||||
|
||||
// 6 out of 10 voted for some block.
|
||||
for i := 0; i < 6; i++ {
|
||||
vote := withValidator(voteProto, privValidators[i].GetAddress(), i)
|
||||
addr := privValidators[i].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, i)
|
||||
_, err := signAddVote(privValidators[i], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -474,7 +494,8 @@ func TestMakeCommit(t *testing.T) {
|
||||
|
||||
// 7th voted for some other block.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[6].GetAddress(), 6)
|
||||
addr := privValidators[6].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 6)
|
||||
vote = withBlockHash(vote, cmn.RandBytes(32))
|
||||
vote = withBlockPartsHeader(vote, PartSetHeader{123, cmn.RandBytes(32)})
|
||||
|
||||
@@ -486,7 +507,8 @@ func TestMakeCommit(t *testing.T) {
|
||||
|
||||
// The 8th voted like everyone else.
|
||||
{
|
||||
vote := withValidator(voteProto, privValidators[7].GetAddress(), 7)
|
||||
addr := privValidators[7].GetPubKey().Address()
|
||||
vote := withValidator(voteProto, addr, 7)
|
||||
_, err := signAddVote(privValidators[7], vote, voteSet)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -18,7 +18,7 @@ const (
|
||||
// TMCoreSemVer is the current version of Tendermint Core.
|
||||
// It's the Semantic Version of the software.
|
||||
// Must be a string because scripts like dist.sh read this file.
|
||||
TMCoreSemVer = "0.26.4"
|
||||
TMCoreSemVer = "0.27.0"
|
||||
|
||||
// ABCISemVer is the semantic version of the ABCI library
|
||||
ABCISemVer = "0.15.0"
|
||||
@@ -36,10 +36,10 @@ func (p Protocol) Uint64() uint64 {
|
||||
|
||||
var (
|
||||
// P2PProtocol versions all p2p behaviour and msgs.
|
||||
P2PProtocol Protocol = 4
|
||||
P2PProtocol Protocol = 5
|
||||
|
||||
// BlockProtocol versions all block data structures and processing.
|
||||
BlockProtocol Protocol = 7
|
||||
BlockProtocol Protocol = 8
|
||||
)
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user