mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-19 06:11:59 +00:00
Compare commits
6 Commits
dont_panic
...
v0.26.0-de
Author | SHA1 | Date | |
---|---|---|---|
|
37928cb990 | ||
|
0790223518 | ||
|
0baa7588c2 | ||
|
8888595b94 | ||
|
1b51cf3f46 | ||
|
2363d88979 |
@@ -24,11 +24,16 @@ BREAKING CHANGES:
|
|||||||
* [types] \#2298 Remove `Index` and `Total` fields from `TxProof`.
|
* [types] \#2298 Remove `Index` and `Total` fields from `TxProof`.
|
||||||
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
|
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
|
||||||
* [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices
|
* [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices
|
||||||
|
* [types] \#2598 `VoteTypeXxx` are now
|
||||||
|
|
||||||
* Blockchain Protocol
|
* Blockchain Protocol
|
||||||
* [types] \#2459 `Vote`/`Proposal`/`Heartbeat` use amino encoding instead of JSON in `SignBytes`.
|
* [types] Update SignBytes for `Vote`/`Proposal`/`Heartbeat`:
|
||||||
|
* \#2459 Use amino encoding instead of JSON in `SignBytes`.
|
||||||
|
* \#2598 Reorder fields and use fixed sized encoding.
|
||||||
|
* \#2598 Change `Type` field fromt `string` to `byte` and use new
|
||||||
|
`SignedMsgType` to enumerate.
|
||||||
* [types] \#2512 Remove the pubkey field from the validator hash
|
* [types] \#2512 Remove the pubkey field from the validator hash
|
||||||
* [state] \#2587 require block.Time of the fist block to be genesis time
|
* [state] \#2587 Require block.Time of the fist block to be genesis time
|
||||||
|
|
||||||
* P2P Protocol
|
* P2P Protocol
|
||||||
|
|
||||||
@@ -37,9 +42,10 @@ FEATURES:
|
|||||||
- [abci] \#2557 Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
|
- [abci] \#2557 Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
- Additional Metrics
|
||||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||||
- [config] \#2232 added ValidateBasic method, which performs basic checks
|
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||||
|
- [config] \#2232 Added ValidateBasic method, which performs basic checks
|
||||||
- [crypto/ed25519] \#2558 Switch to use latest `golang.org/x/crypto` through our fork at
|
- [crypto/ed25519] \#2558 Switch to use latest `golang.org/x/crypto` through our fork at
|
||||||
github.com/tendermint/crypto
|
github.com/tendermint/crypto
|
||||||
- [tools] \#2238 Binary dependencies are now locked to a specific git commit
|
- [tools] \#2238 Binary dependencies are now locked to a specific git commit
|
||||||
@@ -50,6 +56,8 @@ BUG FIXES:
|
|||||||
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
||||||
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) wait for
|
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) wait for
|
||||||
timeoutPrecommit before starting next round
|
timeoutPrecommit before starting next round
|
||||||
|
- [consensus] [\#1745](https://github.com/tendermint/tendermint/issues/1745) wait for
|
||||||
|
Proposal or timeoutProposal before entering prevote
|
||||||
- [evidence] \#2515 fix db iter leak (@goolAdapter)
|
- [evidence] \#2515 fix db iter leak (@goolAdapter)
|
||||||
- [common/bit_array] Fixed a bug in the `Or` function
|
- [common/bit_array] Fixed a bug in the `Or` function
|
||||||
- [common/bit_array] Fixed a bug in the `Sub` function (@james-ray)
|
- [common/bit_array] Fixed a bug in the `Sub` function (@james-ray)
|
||||||
|
@@ -12,23 +12,27 @@ import (
|
|||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testNodeInfo(id p2p.ID) p2p.DefaultNodeInfo {
|
||||||
|
return p2p.DefaultNodeInfo{
|
||||||
|
ID_: id,
|
||||||
|
Moniker: "SOMENAME",
|
||||||
|
Network: "SOMENAME",
|
||||||
|
ListenAddr: "SOMEADDR",
|
||||||
|
Version: "SOMEVER",
|
||||||
|
Other: p2p.DefaultNodeInfoOther{
|
||||||
|
AminoVersion: "SOMESTRING",
|
||||||
|
P2PVersion: "OTHERSTRING",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkEncodeStatusWire(b *testing.B) {
|
func BenchmarkEncodeStatusWire(b *testing.B) {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
cdc := amino.NewCodec()
|
cdc := amino.NewCodec()
|
||||||
ctypes.RegisterAmino(cdc)
|
ctypes.RegisterAmino(cdc)
|
||||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
status := &ctypes.ResultStatus{
|
status := &ctypes.ResultStatus{
|
||||||
NodeInfo: p2p.NodeInfo{
|
NodeInfo: testNodeInfo(nodeKey.ID()),
|
||||||
ID: nodeKey.ID(),
|
|
||||||
Moniker: "SOMENAME",
|
|
||||||
Network: "SOMENAME",
|
|
||||||
ListenAddr: "SOMEADDR",
|
|
||||||
Version: "SOMEVER",
|
|
||||||
Other: p2p.NodeInfoOther{
|
|
||||||
AminoVersion: "SOMESTRING",
|
|
||||||
P2PVersion: "OTHERSTRING",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SyncInfo: ctypes.SyncInfo{
|
SyncInfo: ctypes.SyncInfo{
|
||||||
LatestBlockHash: []byte("SOMEBYTES"),
|
LatestBlockHash: []byte("SOMEBYTES"),
|
||||||
LatestBlockHeight: 123,
|
LatestBlockHeight: 123,
|
||||||
@@ -56,17 +60,7 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) {
|
|||||||
cdc := amino.NewCodec()
|
cdc := amino.NewCodec()
|
||||||
ctypes.RegisterAmino(cdc)
|
ctypes.RegisterAmino(cdc)
|
||||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
nodeInfo := p2p.NodeInfo{
|
nodeInfo := testNodeInfo(nodeKey.ID())
|
||||||
ID: nodeKey.ID(),
|
|
||||||
Moniker: "SOMENAME",
|
|
||||||
Network: "SOMENAME",
|
|
||||||
ListenAddr: "SOMEADDR",
|
|
||||||
Version: "SOMEVER",
|
|
||||||
Other: p2p.NodeInfoOther{
|
|
||||||
AminoVersion: "SOMESTRING",
|
|
||||||
P2PVersion: "OTHERSTRING",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
|
|
||||||
counter := 0
|
counter := 0
|
||||||
@@ -84,17 +78,7 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
|
|||||||
cdc := amino.NewCodec()
|
cdc := amino.NewCodec()
|
||||||
ctypes.RegisterAmino(cdc)
|
ctypes.RegisterAmino(cdc)
|
||||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
nodeInfo := p2p.NodeInfo{
|
nodeInfo := testNodeInfo(nodeKey.ID())
|
||||||
ID: nodeKey.ID(),
|
|
||||||
Moniker: "SOMENAME",
|
|
||||||
Network: "SOMENAME",
|
|
||||||
ListenAddr: "SOMEADDR",
|
|
||||||
Version: "SOMEVER",
|
|
||||||
Other: p2p.NodeInfoOther{
|
|
||||||
AminoVersion: "SOMESTRING",
|
|
||||||
P2PVersion: "OTHERSTRING",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
|
|
||||||
counter := 0
|
counter := 0
|
||||||
|
@@ -198,7 +198,7 @@ func (tp *bcrTestPeer) TrySend(chID byte, msgBytes []byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tp *bcrTestPeer) Send(chID byte, msgBytes []byte) bool { return tp.TrySend(chID, msgBytes) }
|
func (tp *bcrTestPeer) Send(chID byte, msgBytes []byte) bool { return tp.TrySend(chID, msgBytes) }
|
||||||
func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.NodeInfo{} }
|
func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.DefaultNodeInfo{} }
|
||||||
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
|
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
|
||||||
func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
|
func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
|
||||||
func (tp *bcrTestPeer) IsOutbound() bool { return false }
|
func (tp *bcrTestPeer) IsOutbound() bool { return false }
|
||||||
@@ -206,4 +206,3 @@ func (tp *bcrTestPeer) IsPersistent() bool { return true }
|
|||||||
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
|
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
|
||||||
func (tp *bcrTestPeer) Set(string, interface{}) {}
|
func (tp *bcrTestPeer) Set(string, interface{}) {}
|
||||||
func (tp *bcrTestPeer) RemoteIP() net.IP { return []byte{127, 0, 0, 1} }
|
func (tp *bcrTestPeer) RemoteIP() net.IP { return []byte{127, 0, 0, 1} }
|
||||||
func (tp *bcrTestPeer) OriginalAddr() *p2p.NetAddress { return nil }
|
|
||||||
|
@@ -565,7 +565,7 @@ func DefaultConsensusConfig() *ConsensusConfig {
|
|||||||
// TestConsensusConfig returns a configuration for testing the consensus service
|
// TestConsensusConfig returns a configuration for testing the consensus service
|
||||||
func TestConsensusConfig() *ConsensusConfig {
|
func TestConsensusConfig() *ConsensusConfig {
|
||||||
cfg := DefaultConsensusConfig()
|
cfg := DefaultConsensusConfig()
|
||||||
cfg.TimeoutPropose = 100 * time.Millisecond
|
cfg.TimeoutPropose = 40 * time.Millisecond
|
||||||
cfg.TimeoutProposeDelta = 1 * time.Millisecond
|
cfg.TimeoutProposeDelta = 1 * time.Millisecond
|
||||||
cfg.TimeoutPrevote = 10 * time.Millisecond
|
cfg.TimeoutPrevote = 10 * time.Millisecond
|
||||||
cfg.TimeoutPrevoteDelta = 1 * time.Millisecond
|
cfg.TimeoutPrevoteDelta = 1 * time.Millisecond
|
||||||
|
@@ -226,8 +226,8 @@ func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.
|
|||||||
|
|
||||||
// votes
|
// votes
|
||||||
cs.mtx.Lock()
|
cs.mtx.Lock()
|
||||||
prevote, _ := cs.signVote(types.VoteTypePrevote, blockHash, parts.Header())
|
prevote, _ := cs.signVote(types.PrevoteType, blockHash, parts.Header())
|
||||||
precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, parts.Header())
|
precommit, _ := cs.signVote(types.PrecommitType, blockHash, parts.Header())
|
||||||
cs.mtx.Unlock()
|
cs.mtx.Unlock()
|
||||||
|
|
||||||
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
|
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
|
||||||
|
@@ -40,7 +40,7 @@ const (
|
|||||||
|
|
||||||
// genesis, chain_id, priv_val
|
// genesis, chain_id, priv_val
|
||||||
var config *cfg.Config // NOTE: must be reset for each _test.go file
|
var config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||||
var ensureTimeout = time.Second * 1 // must be in seconds because CreateEmptyBlocksInterval is
|
var ensureTimeout = time.Millisecond * 100
|
||||||
|
|
||||||
func ensureDir(dir string, mode os.FileMode) {
|
func ensureDir(dir string, mode os.FileMode) {
|
||||||
if err := cmn.EnsureDir(dir, mode); err != nil {
|
if err := cmn.EnsureDir(dir, mode); err != nil {
|
||||||
@@ -71,7 +71,7 @@ func NewValidatorStub(privValidator types.PrivValidator, valIndex int) *validato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
func (vs *validatorStub) signVote(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
||||||
vote := &types.Vote{
|
vote := &types.Vote{
|
||||||
ValidatorIndex: vs.Index,
|
ValidatorIndex: vs.Index,
|
||||||
ValidatorAddress: vs.PrivValidator.GetAddress(),
|
ValidatorAddress: vs.PrivValidator.GetAddress(),
|
||||||
@@ -86,7 +86,7 @@ func (vs *validatorStub) signVote(voteType byte, hash []byte, header types.PartS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign vote for type/hash/header
|
// Sign vote for type/hash/header
|
||||||
func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSetHeader) *types.Vote {
|
func signVote(vs *validatorStub, voteType types.SignedMsgType, hash []byte, header types.PartSetHeader) *types.Vote {
|
||||||
v, err := vs.signVote(voteType, hash, header)
|
v, err := vs.signVote(voteType, hash, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("failed to sign vote: %v", err))
|
panic(fmt.Errorf("failed to sign vote: %v", err))
|
||||||
@@ -94,7 +94,7 @@ func signVote(vs *validatorStub, voteType byte, hash []byte, header types.PartSe
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func signVotes(voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
|
func signVotes(voteType types.SignedMsgType, hash []byte, header types.PartSetHeader, vss ...*validatorStub) []*types.Vote {
|
||||||
votes := make([]*types.Vote, len(vss))
|
votes := make([]*types.Vote, len(vss))
|
||||||
for i, vs := range vss {
|
for i, vs := range vss {
|
||||||
votes[i] = signVote(vs, voteType, hash, header)
|
votes[i] = signVote(vs, voteType, hash, header)
|
||||||
@@ -144,7 +144,7 @@ func addVotes(to *ConsensusState, votes ...*types.Vote) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func signAddVotes(to *ConsensusState, voteType byte, hash []byte, header types.PartSetHeader, vss ...*validatorStub) {
|
func signAddVotes(to *ConsensusState, voteType types.SignedMsgType, hash []byte, header types.PartSetHeader, vss ...*validatorStub) {
|
||||||
votes := signVotes(voteType, hash, header, vss...)
|
votes := signVotes(voteType, hash, header, vss...)
|
||||||
addVotes(to, votes...)
|
addVotes(to, votes...)
|
||||||
}
|
}
|
||||||
@@ -317,67 +317,156 @@ func ensureNoNewEvent(ch <-chan interface{}, timeout time.Duration,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureNoNewStep(stepCh <-chan interface{}) {
|
func ensureNoNewEventOnChannel(ch <-chan interface{}) {
|
||||||
ensureNoNewEvent(stepCh, ensureTimeout, "We should be stuck waiting, "+
|
ensureNoNewEvent(
|
||||||
"not moving to the next step")
|
ch,
|
||||||
|
ensureTimeout,
|
||||||
|
"We should be stuck waiting, not receiving new event on the channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNoNewRoundStep(stepCh <-chan interface{}) {
|
||||||
|
ensureNoNewEvent(
|
||||||
|
stepCh,
|
||||||
|
ensureTimeout,
|
||||||
|
"We should be stuck waiting, not receiving NewRoundStep event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNoNewUnlock(unlockCh <-chan interface{}) {
|
||||||
|
ensureNoNewEvent(
|
||||||
|
unlockCh,
|
||||||
|
ensureTimeout,
|
||||||
|
"We should be stuck waiting, not receiving Unlock event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureNoNewTimeout(stepCh <-chan interface{}, timeout int64) {
|
func ensureNoNewTimeout(stepCh <-chan interface{}, timeout int64) {
|
||||||
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
|
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
|
||||||
ensureNoNewEvent(stepCh, timeoutDuration, "We should be stuck waiting, "+
|
ensureNoNewEvent(
|
||||||
"not moving to the next step")
|
stepCh,
|
||||||
|
timeoutDuration,
|
||||||
|
"We should be stuck waiting, not receiving NewTimeout event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureNewEvent(ch <-chan interface{}, timeout time.Duration, errorMessage string) {
|
func ensureNewEvent(
|
||||||
|
ch <-chan interface{},
|
||||||
|
height int64,
|
||||||
|
round int,
|
||||||
|
timeout time.Duration,
|
||||||
|
errorMessage string) {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
panic(errorMessage)
|
panic(errorMessage)
|
||||||
case <-ch:
|
case ev := <-ch:
|
||||||
break
|
rs, ok := ev.(types.EventDataRoundState)
|
||||||
|
if !ok {
|
||||||
|
panic(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"expected a EventDataRoundState, got %v.Wrong subscription channel?",
|
||||||
|
reflect.TypeOf(rs)))
|
||||||
|
}
|
||||||
|
if rs.Height != height {
|
||||||
|
panic(fmt.Sprintf("expected height %v, got %v", height, rs.Height))
|
||||||
|
}
|
||||||
|
if rs.Round != round {
|
||||||
|
panic(fmt.Sprintf("expected round %v, got %v", round, rs.Round))
|
||||||
|
}
|
||||||
|
// TODO: We could check also for a step at this point!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureNewStep(stepCh <-chan interface{}) {
|
func ensureNewRoundStep(stepCh <-chan interface{}, height int64, round int) {
|
||||||
ensureNewEvent(stepCh, ensureTimeout,
|
ensureNewEvent(
|
||||||
|
stepCh,
|
||||||
|
height,
|
||||||
|
round,
|
||||||
|
ensureTimeout,
|
||||||
"Timeout expired while waiting for NewStep event")
|
"Timeout expired while waiting for NewStep event")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureNewRound(roundCh <-chan interface{}) {
|
func ensureNewVote(voteCh <-chan interface{}, height int64, round int) {
|
||||||
ensureNewEvent(roundCh, ensureTimeout,
|
|
||||||
"Timeout expired while waiting for NewRound event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureNewTimeout(timeoutCh <-chan interface{}, timeout int64) {
|
|
||||||
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
|
|
||||||
ensureNewEvent(timeoutCh, timeoutDuration,
|
|
||||||
"Timeout expired while waiting for NewTimeout event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureNewProposal(proposalCh <-chan interface{}) {
|
|
||||||
ensureNewEvent(proposalCh, ensureTimeout,
|
|
||||||
"Timeout expired while waiting for NewProposal event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureNewBlock(blockCh <-chan interface{}) {
|
|
||||||
ensureNewEvent(blockCh, ensureTimeout,
|
|
||||||
"Timeout expired while waiting for NewBlock event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureNewVote(voteCh <-chan interface{}) {
|
|
||||||
ensureNewEvent(voteCh, ensureTimeout,
|
|
||||||
"Timeout expired while waiting for NewVote event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureNewUnlock(unlockCh <-chan interface{}) {
|
|
||||||
ensureNewEvent(unlockCh, ensureTimeout,
|
|
||||||
"Timeout expired while waiting for NewUnlock event")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ensureVote(voteCh chan interface{}, height int64, round int,
|
|
||||||
voteType byte) {
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(ensureTimeout):
|
case <-time.After(ensureTimeout):
|
||||||
break
|
break
|
||||||
|
case v := <-voteCh:
|
||||||
|
edv, ok := v.(types.EventDataVote)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("expected a *types.Vote, "+
|
||||||
|
"got %v. wrong subscription channel?",
|
||||||
|
reflect.TypeOf(v)))
|
||||||
|
}
|
||||||
|
vote := edv.Vote
|
||||||
|
if vote.Height != height {
|
||||||
|
panic(fmt.Sprintf("expected height %v, got %v", height, vote.Height))
|
||||||
|
}
|
||||||
|
if vote.Round != round {
|
||||||
|
panic(fmt.Sprintf("expected round %v, got %v", round, vote.Round))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewRound(roundCh <-chan interface{}, height int64, round int) {
|
||||||
|
ensureNewEvent(roundCh, height, round, ensureTimeout,
|
||||||
|
"Timeout expired while waiting for NewRound event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewTimeout(timeoutCh <-chan interface{}, height int64, round int, timeout int64) {
|
||||||
|
timeoutDuration := time.Duration(timeout*3) * time.Nanosecond
|
||||||
|
ensureNewEvent(timeoutCh, height, round, timeoutDuration,
|
||||||
|
"Timeout expired while waiting for NewTimeout event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewProposal(proposalCh <-chan interface{}, height int64, round int) {
|
||||||
|
ensureNewEvent(proposalCh, height, round, ensureTimeout,
|
||||||
|
"Timeout expired while waiting for NewProposal event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewBlock(blockCh <-chan interface{}, height int64) {
|
||||||
|
select {
|
||||||
|
case <-time.After(ensureTimeout):
|
||||||
|
panic("Timeout expired while waiting for NewBlock event")
|
||||||
|
case ev := <-blockCh:
|
||||||
|
block, ok := ev.(types.EventDataNewBlock)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("expected a *types.EventDataNewBlock, "+
|
||||||
|
"got %v. wrong subscription channel?",
|
||||||
|
reflect.TypeOf(block)))
|
||||||
|
}
|
||||||
|
if block.Block.Height != height {
|
||||||
|
panic(fmt.Sprintf("expected height %v, got %v", height, block.Block.Height))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewBlockHeader(blockCh <-chan interface{}, height int64, blockHash cmn.HexBytes) {
|
||||||
|
select {
|
||||||
|
case <-time.After(ensureTimeout):
|
||||||
|
panic("Timeout expired while waiting for NewBlockHeader event")
|
||||||
|
case ev := <-blockCh:
|
||||||
|
blockHeader, ok := ev.(types.EventDataNewBlockHeader)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("expected a *types.EventDataNewBlockHeader, "+
|
||||||
|
"got %v. wrong subscription channel?",
|
||||||
|
reflect.TypeOf(blockHeader)))
|
||||||
|
}
|
||||||
|
if blockHeader.Header.Height != height {
|
||||||
|
panic(fmt.Sprintf("expected height %v, got %v", height, blockHeader.Header.Height))
|
||||||
|
}
|
||||||
|
if !bytes.Equal(blockHeader.Header.Hash(), blockHash) {
|
||||||
|
panic(fmt.Sprintf("expected header %X, got %X", blockHash, blockHeader.Header.Hash()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureNewUnlock(unlockCh <-chan interface{}, height int64, round int) {
|
||||||
|
ensureNewEvent(unlockCh, height, round, ensureTimeout,
|
||||||
|
"Timeout expired while waiting for NewUnlock event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureVote(voteCh <-chan interface{}, height int64, round int,
|
||||||
|
voteType types.SignedMsgType) {
|
||||||
|
select {
|
||||||
|
case <-time.After(ensureTimeout):
|
||||||
|
panic("Timeout expired while waiting for NewVote event")
|
||||||
case v := <-voteCh:
|
case v := <-voteCh:
|
||||||
edv, ok := v.(types.EventDataVote)
|
edv, ok := v.(types.EventDataVote)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -398,6 +487,14 @@ func ensureVote(voteCh chan interface{}, height int64, round int,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ensureNewEventOnChannel(ch <-chan interface{}) {
|
||||||
|
select {
|
||||||
|
case <-time.After(ensureTimeout):
|
||||||
|
panic("Timeout expired while waiting for new activity on the channel")
|
||||||
|
case <-ch:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
// consensus nets
|
// consensus nets
|
||||||
|
|
||||||
@@ -471,7 +568,7 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
|
|||||||
|
|
||||||
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
||||||
for i, s := range switches {
|
for i, s := range switches {
|
||||||
if peer.NodeInfo().ID == s.NodeInfo().ID {
|
if peer.NodeInfo().ID() == s.NodeInfo().ID() {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,12 +28,12 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
|
|||||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||||
startTestRound(cs, height, round)
|
startTestRound(cs, height, round)
|
||||||
|
|
||||||
ensureNewStep(newBlockCh) // first block gets committed
|
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||||
ensureNoNewStep(newBlockCh)
|
ensureNoNewEventOnChannel(newBlockCh)
|
||||||
deliverTxsRange(cs, 0, 1)
|
deliverTxsRange(cs, 0, 1)
|
||||||
ensureNewStep(newBlockCh) // commit txs
|
ensureNewEventOnChannel(newBlockCh) // commit txs
|
||||||
ensureNewStep(newBlockCh) // commit updated app hash
|
ensureNewEventOnChannel(newBlockCh) // commit updated app hash
|
||||||
ensureNoNewStep(newBlockCh)
|
ensureNoNewEventOnChannel(newBlockCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
||||||
@@ -46,9 +46,9 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
|||||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||||
startTestRound(cs, height, round)
|
startTestRound(cs, height, round)
|
||||||
|
|
||||||
ensureNewStep(newBlockCh) // first block gets committed
|
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||||
ensureNoNewStep(newBlockCh) // then we dont make a block ...
|
ensureNoNewEventOnChannel(newBlockCh) // then we dont make a block ...
|
||||||
ensureNewStep(newBlockCh) // until the CreateEmptyBlocksInterval has passed
|
ensureNewEventOnChannel(newBlockCh) // until the CreateEmptyBlocksInterval has passed
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMempoolProgressInHigherRound(t *testing.T) {
|
func TestMempoolProgressInHigherRound(t *testing.T) {
|
||||||
@@ -72,13 +72,19 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
startTestRound(cs, height, round)
|
startTestRound(cs, height, round)
|
||||||
|
|
||||||
ensureNewStep(newRoundCh) // first round at first height
|
ensureNewRoundStep(newRoundCh, height, round) // first round at first height
|
||||||
ensureNewStep(newBlockCh) // first block gets committed
|
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||||
ensureNewStep(newRoundCh) // first round at next height
|
|
||||||
|
height = height + 1 // moving to the next height
|
||||||
|
round = 0
|
||||||
|
|
||||||
|
ensureNewRoundStep(newRoundCh, height, round) // first round at next height
|
||||||
deliverTxsRange(cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
|
deliverTxsRange(cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
|
||||||
<-timeoutCh
|
ensureNewTimeout(timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
|
||||||
ensureNewStep(newRoundCh) // wait for the next round
|
|
||||||
ensureNewStep(newBlockCh) // now we can commit the block
|
round = round + 1 // moving to the next round
|
||||||
|
ensureNewRoundStep(newRoundCh, height, round) // wait for the next round
|
||||||
|
ensureNewEventOnChannel(newBlockCh) // now we can commit the block
|
||||||
}
|
}
|
||||||
|
|
||||||
func deliverTxsRange(cs *ConsensusState, start, end int) {
|
func deliverTxsRange(cs *ConsensusState, start, end int) {
|
||||||
|
@@ -237,9 +237,9 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
|||||||
// (and consequently shows which we don't have)
|
// (and consequently shows which we don't have)
|
||||||
var ourVotes *cmn.BitArray
|
var ourVotes *cmn.BitArray
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||||
default:
|
default:
|
||||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||||
@@ -317,9 +317,9 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
|||||||
if height == msg.Height {
|
if height == msg.Height {
|
||||||
var ourVotes *cmn.BitArray
|
var ourVotes *cmn.BitArray
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||||
default:
|
default:
|
||||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||||
@@ -739,7 +739,7 @@ OUTER_LOOP:
|
|||||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||||
Height: prs.Height,
|
Height: prs.Height,
|
||||||
Round: prs.Round,
|
Round: prs.Round,
|
||||||
Type: types.VoteTypePrevote,
|
Type: types.PrevoteType,
|
||||||
BlockID: maj23,
|
BlockID: maj23,
|
||||||
}))
|
}))
|
||||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||||
@@ -756,7 +756,7 @@ OUTER_LOOP:
|
|||||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||||
Height: prs.Height,
|
Height: prs.Height,
|
||||||
Round: prs.Round,
|
Round: prs.Round,
|
||||||
Type: types.VoteTypePrecommit,
|
Type: types.PrecommitType,
|
||||||
BlockID: maj23,
|
BlockID: maj23,
|
||||||
}))
|
}))
|
||||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||||
@@ -773,7 +773,7 @@ OUTER_LOOP:
|
|||||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||||
Height: prs.Height,
|
Height: prs.Height,
|
||||||
Round: prs.ProposalPOLRound,
|
Round: prs.ProposalPOLRound,
|
||||||
Type: types.VoteTypePrevote,
|
Type: types.PrevoteType,
|
||||||
BlockID: maj23,
|
BlockID: maj23,
|
||||||
}))
|
}))
|
||||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||||
@@ -792,7 +792,7 @@ OUTER_LOOP:
|
|||||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||||
Height: prs.Height,
|
Height: prs.Height,
|
||||||
Round: commit.Round(),
|
Round: commit.Round(),
|
||||||
Type: types.VoteTypePrecommit,
|
Type: types.PrecommitType,
|
||||||
BlockID: commit.BlockID,
|
BlockID: commit.BlockID,
|
||||||
}))
|
}))
|
||||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||||
@@ -1022,7 +1022,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
height, round, type_, size := votes.Height(), votes.Round(), votes.Type(), votes.Size()
|
height, round, type_, size := votes.Height(), votes.Round(), types.SignedMsgType(votes.Type()), votes.Size()
|
||||||
|
|
||||||
// Lazily set data using 'votes'.
|
// Lazily set data using 'votes'.
|
||||||
if votes.IsCommit() {
|
if votes.IsCommit() {
|
||||||
@@ -1041,7 +1041,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) getVoteBitArray(height int64, round int, type_ byte) *cmn.BitArray {
|
func (ps *PeerState) getVoteBitArray(height int64, round int, type_ types.SignedMsgType) *cmn.BitArray {
|
||||||
if !types.IsVoteTypeValid(type_) {
|
if !types.IsVoteTypeValid(type_) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1049,25 +1049,25 @@ func (ps *PeerState) getVoteBitArray(height int64, round int, type_ byte) *cmn.B
|
|||||||
if ps.PRS.Height == height {
|
if ps.PRS.Height == height {
|
||||||
if ps.PRS.Round == round {
|
if ps.PRS.Round == round {
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return ps.PRS.Prevotes
|
return ps.PRS.Prevotes
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return ps.PRS.Precommits
|
return ps.PRS.Precommits
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ps.PRS.CatchupCommitRound == round {
|
if ps.PRS.CatchupCommitRound == round {
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return nil
|
return nil
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return ps.PRS.CatchupCommit
|
return ps.PRS.CatchupCommit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ps.PRS.ProposalPOLRound == round {
|
if ps.PRS.ProposalPOLRound == round {
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return ps.PRS.ProposalPOL
|
return ps.PRS.ProposalPOL
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1076,9 +1076,9 @@ func (ps *PeerState) getVoteBitArray(height int64, round int, type_ byte) *cmn.B
|
|||||||
if ps.PRS.Height == height+1 {
|
if ps.PRS.Height == height+1 {
|
||||||
if ps.PRS.LastCommitRound == round {
|
if ps.PRS.LastCommitRound == round {
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return nil
|
return nil
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return ps.PRS.LastCommit
|
return ps.PRS.LastCommit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1187,7 +1187,7 @@ func (ps *PeerState) SetHasVote(vote *types.Vote) {
|
|||||||
ps.setHasVote(vote.Height, vote.Round, vote.Type, vote.ValidatorIndex)
|
ps.setHasVote(vote.Height, vote.Round, vote.Type, vote.ValidatorIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) setHasVote(height int64, round int, type_ byte, index int) {
|
func (ps *PeerState) setHasVote(height int64, round int, type_ types.SignedMsgType, index int) {
|
||||||
logger := ps.logger.With("peerH/R", fmt.Sprintf("%d/%d", ps.PRS.Height, ps.PRS.Round), "H/R", fmt.Sprintf("%d/%d", height, round))
|
logger := ps.logger.With("peerH/R", fmt.Sprintf("%d/%d", ps.PRS.Height, ps.PRS.Round), "H/R", fmt.Sprintf("%d/%d", height, round))
|
||||||
logger.Debug("setHasVote", "type", type_, "index", index)
|
logger.Debug("setHasVote", "type", type_, "index", index)
|
||||||
|
|
||||||
@@ -1453,7 +1453,7 @@ func (m *VoteMessage) String() string {
|
|||||||
type HasVoteMessage struct {
|
type HasVoteMessage struct {
|
||||||
Height int64
|
Height int64
|
||||||
Round int
|
Round int
|
||||||
Type byte
|
Type types.SignedMsgType
|
||||||
Index int
|
Index int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1468,7 +1468,7 @@ func (m *HasVoteMessage) String() string {
|
|||||||
type VoteSetMaj23Message struct {
|
type VoteSetMaj23Message struct {
|
||||||
Height int64
|
Height int64
|
||||||
Round int
|
Round int
|
||||||
Type byte
|
Type types.SignedMsgType
|
||||||
BlockID types.BlockID
|
BlockID types.BlockID
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1483,7 +1483,7 @@ func (m *VoteSetMaj23Message) String() string {
|
|||||||
type VoteSetBitsMessage struct {
|
type VoteSetBitsMessage struct {
|
||||||
Height int64
|
Height int64
|
||||||
Round int
|
Round int
|
||||||
Type byte
|
Type types.SignedMsgType
|
||||||
BlockID types.BlockID
|
BlockID types.BlockID
|
||||||
Votes *cmn.BitArray
|
Votes *cmn.BitArray
|
||||||
}
|
}
|
||||||
|
@@ -287,6 +287,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
state.Validators = types.NewValidatorSet(vals)
|
state.Validators = types.NewValidatorSet(vals)
|
||||||
|
state.NextValidators = types.NewValidatorSet(vals)
|
||||||
}
|
}
|
||||||
if res.ConsensusParams != nil {
|
if res.ConsensusParams != nil {
|
||||||
state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams)
|
state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams)
|
||||||
|
@@ -542,7 +542,7 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
case *types.Vote:
|
case *types.Vote:
|
||||||
if p.Type == types.VoteTypePrecommit {
|
if p.Type == types.PrecommitType {
|
||||||
thisBlockCommit = &types.Commit{
|
thisBlockCommit = &types.Commit{
|
||||||
BlockID: p.BlockID,
|
BlockID: p.BlockID,
|
||||||
Precommits: []*types.Vote{p},
|
Precommits: []*types.Vote{p},
|
||||||
|
@@ -83,6 +83,7 @@ type ConsensusState struct {
|
|||||||
// internal state
|
// internal state
|
||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
cstypes.RoundState
|
cstypes.RoundState
|
||||||
|
triggeredTimeoutPrecommit bool
|
||||||
state sm.State // State until height-1.
|
state sm.State // State until height-1.
|
||||||
|
|
||||||
// state changes may be triggered by: msgs from peers,
|
// state changes may be triggered by: msgs from peers,
|
||||||
@@ -459,7 +460,7 @@ func (cs *ConsensusState) reconstructLastCommit(state sm.State) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
seenCommit := cs.blockStore.LoadSeenCommit(state.LastBlockHeight)
|
seenCommit := cs.blockStore.LoadSeenCommit(state.LastBlockHeight)
|
||||||
lastPrecommits := types.NewVoteSet(state.ChainID, state.LastBlockHeight, seenCommit.Round(), types.VoteTypePrecommit, state.LastValidators)
|
lastPrecommits := types.NewVoteSet(state.ChainID, state.LastBlockHeight, seenCommit.Round(), types.PrecommitType, state.LastValidators)
|
||||||
for _, precommit := range seenCommit.Precommits {
|
for _, precommit := range seenCommit.Precommits {
|
||||||
if precommit == nil {
|
if precommit == nil {
|
||||||
continue
|
continue
|
||||||
@@ -711,6 +712,7 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) {
|
|||||||
cs.enterPrecommit(ti.Height, ti.Round)
|
cs.enterPrecommit(ti.Height, ti.Round)
|
||||||
case cstypes.RoundStepPrecommitWait:
|
case cstypes.RoundStepPrecommitWait:
|
||||||
cs.eventBus.PublishEventTimeoutWait(cs.RoundStateEvent())
|
cs.eventBus.PublishEventTimeoutWait(cs.RoundStateEvent())
|
||||||
|
cs.enterPrecommit(ti.Height, ti.Round)
|
||||||
cs.enterNewRound(ti.Height, ti.Round+1)
|
cs.enterNewRound(ti.Height, ti.Round+1)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Invalid timeout step: %v", ti.Step))
|
panic(fmt.Sprintf("Invalid timeout step: %v", ti.Step))
|
||||||
@@ -772,6 +774,7 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
|
|||||||
cs.ProposalBlockParts = nil
|
cs.ProposalBlockParts = nil
|
||||||
}
|
}
|
||||||
cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
|
cs.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
|
||||||
|
cs.triggeredTimeoutPrecommit = false
|
||||||
|
|
||||||
cs.eventBus.PublishEventNewRound(cs.RoundStateEvent())
|
cs.eventBus.PublishEventNewRound(cs.RoundStateEvent())
|
||||||
cs.metrics.Rounds.Set(float64(round))
|
cs.metrics.Rounds.Set(float64(round))
|
||||||
@@ -782,7 +785,8 @@ func (cs *ConsensusState) enterNewRound(height int64, round int) {
|
|||||||
waitForTxs := cs.config.WaitForTxs() && round == 0 && !cs.needProofBlock(height)
|
waitForTxs := cs.config.WaitForTxs() && round == 0 && !cs.needProofBlock(height)
|
||||||
if waitForTxs {
|
if waitForTxs {
|
||||||
if cs.config.CreateEmptyBlocksInterval > 0 {
|
if cs.config.CreateEmptyBlocksInterval > 0 {
|
||||||
cs.scheduleTimeout(cs.config.CreateEmptyBlocksInterval, height, round, cstypes.RoundStepNewRound)
|
cs.scheduleTimeout(cs.config.CreateEmptyBlocksInterval, height, round,
|
||||||
|
cstypes.RoundStepNewRound)
|
||||||
}
|
}
|
||||||
go cs.proposalHeartbeat(height, round)
|
go cs.proposalHeartbeat(height, round)
|
||||||
} else {
|
} else {
|
||||||
@@ -1013,17 +1017,18 @@ func (cs *ConsensusState) enterPrevote(height int64, round int) {
|
|||||||
|
|
||||||
func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
||||||
logger := cs.Logger.With("height", height, "round", round)
|
logger := cs.Logger.With("height", height, "round", round)
|
||||||
|
|
||||||
// If a block is locked, prevote that.
|
// If a block is locked, prevote that.
|
||||||
if cs.LockedBlock != nil {
|
if cs.LockedBlock != nil {
|
||||||
logger.Info("enterPrevote: Block was locked")
|
logger.Info("enterPrevote: Block was locked")
|
||||||
cs.signAddVote(types.VoteTypePrevote, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header())
|
cs.signAddVote(types.PrevoteType, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If ProposalBlock is nil, prevote nil.
|
// If ProposalBlock is nil, prevote nil.
|
||||||
if cs.ProposalBlock == nil {
|
if cs.ProposalBlock == nil {
|
||||||
logger.Info("enterPrevote: ProposalBlock is nil")
|
logger.Info("enterPrevote: ProposalBlock is nil")
|
||||||
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,7 +1037,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// ProposalBlock is invalid, prevote nil.
|
// ProposalBlock is invalid, prevote nil.
|
||||||
logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
|
logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
|
||||||
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,7 +1045,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
|||||||
// NOTE: the proposal signature is validated when it is received,
|
// NOTE: the proposal signature is validated when it is received,
|
||||||
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
|
// and the proposal block parts are validated as they are received (against the merkle hash in the proposal)
|
||||||
logger.Info("enterPrevote: ProposalBlock is valid")
|
logger.Info("enterPrevote: ProposalBlock is valid")
|
||||||
cs.signAddVote(types.VoteTypePrevote, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
|
cs.signAddVote(types.PrevoteType, cs.ProposalBlock.Hash(), cs.ProposalBlockParts.Header())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter: any +2/3 prevotes at next round.
|
// Enter: any +2/3 prevotes at next round.
|
||||||
@@ -1098,7 +1103,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
|||||||
} else {
|
} else {
|
||||||
logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit. Precommitting nil.")
|
logger.Info("enterPrecommit: No +2/3 prevotes during enterPrecommit. Precommitting nil.")
|
||||||
}
|
}
|
||||||
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
|
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1122,7 +1127,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
|||||||
cs.LockedBlockParts = nil
|
cs.LockedBlockParts = nil
|
||||||
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
|
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
|
||||||
}
|
}
|
||||||
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
|
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,7 +1138,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
|||||||
logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
|
logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
|
||||||
cs.LockedRound = round
|
cs.LockedRound = round
|
||||||
cs.eventBus.PublishEventRelock(cs.RoundStateEvent())
|
cs.eventBus.PublishEventRelock(cs.RoundStateEvent())
|
||||||
cs.signAddVote(types.VoteTypePrecommit, blockID.Hash, blockID.PartsHeader)
|
cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1148,7 +1153,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
|||||||
cs.LockedBlock = cs.ProposalBlock
|
cs.LockedBlock = cs.ProposalBlock
|
||||||
cs.LockedBlockParts = cs.ProposalBlockParts
|
cs.LockedBlockParts = cs.ProposalBlockParts
|
||||||
cs.eventBus.PublishEventLock(cs.RoundStateEvent())
|
cs.eventBus.PublishEventLock(cs.RoundStateEvent())
|
||||||
cs.signAddVote(types.VoteTypePrecommit, blockID.Hash, blockID.PartsHeader)
|
cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1164,15 +1169,19 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
|||||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
|
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
|
||||||
}
|
}
|
||||||
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
|
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
|
||||||
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
|
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter: any +2/3 precommits for next round.
|
// Enter: any +2/3 precommits for next round.
|
||||||
func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
|
func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
|
||||||
logger := cs.Logger.With("height", height, "round", round)
|
logger := cs.Logger.With("height", height, "round", round)
|
||||||
|
|
||||||
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommitWait <= cs.Step) {
|
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.triggeredTimeoutPrecommit) {
|
||||||
logger.Debug(fmt.Sprintf("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
logger.Debug(
|
||||||
|
fmt.Sprintf(
|
||||||
|
"enterPrecommitWait(%v/%v): Invalid args. "+
|
||||||
|
"Current state is Height/Round: %v/%v/, triggeredTimeoutPrecommit:%v",
|
||||||
|
height, round, cs.Height, cs.Round, cs.triggeredTimeoutPrecommit))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
|
if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
|
||||||
@@ -1182,7 +1191,7 @@ func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Done enterPrecommitWait:
|
// Done enterPrecommitWait:
|
||||||
cs.updateRoundStep(round, cstypes.RoundStepPrecommitWait)
|
cs.triggeredTimeoutPrecommit = true
|
||||||
cs.newStep()
|
cs.newStep()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -1495,6 +1504,9 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p
|
|||||||
if cs.Step <= cstypes.RoundStepPropose && cs.isProposalComplete() {
|
if cs.Step <= cstypes.RoundStepPropose && cs.isProposalComplete() {
|
||||||
// Move onto the next step
|
// Move onto the next step
|
||||||
cs.enterPrevote(height, cs.Round)
|
cs.enterPrevote(height, cs.Round)
|
||||||
|
if hasTwoThirds { // this is optimisation as this will be triggered when prevote is added
|
||||||
|
cs.enterPrecommit(height, cs.Round)
|
||||||
|
}
|
||||||
} else if cs.Step == cstypes.RoundStepCommit {
|
} else if cs.Step == cstypes.RoundStepCommit {
|
||||||
// If we're waiting on the proposal block...
|
// If we're waiting on the proposal block...
|
||||||
cs.tryFinalizeCommit(height)
|
cs.tryFinalizeCommit(height)
|
||||||
@@ -1538,7 +1550,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
// A precommit for the previous height?
|
// A precommit for the previous height?
|
||||||
// These come in while we wait timeoutCommit
|
// These come in while we wait timeoutCommit
|
||||||
if vote.Height+1 == cs.Height {
|
if vote.Height+1 == cs.Height {
|
||||||
if !(cs.Step == cstypes.RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
|
if !(cs.Step == cstypes.RoundStepNewHeight && vote.Type == types.PrecommitType) {
|
||||||
// TODO: give the reason ..
|
// TODO: give the reason ..
|
||||||
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
|
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
|
||||||
return added, ErrVoteHeightMismatch
|
return added, ErrVoteHeightMismatch
|
||||||
@@ -1581,7 +1593,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
cs.evsw.FireEvent(types.EventVote, vote)
|
cs.evsw.FireEvent(types.EventVote, vote)
|
||||||
|
|
||||||
switch vote.Type {
|
switch vote.Type {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
prevotes := cs.Votes.Prevotes(vote.Round)
|
prevotes := cs.Votes.Prevotes(vote.Round)
|
||||||
cs.Logger.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())
|
cs.Logger.Info("Added to prevote", "vote", vote, "prevotes", prevotes.StringShort())
|
||||||
|
|
||||||
@@ -1609,7 +1621,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
// Update Valid* if we can.
|
// Update Valid* if we can.
|
||||||
// NOTE: our proposal block may be nil or not what received a polka..
|
// NOTE: our proposal block may be nil or not what received a polka..
|
||||||
// TODO: we may want to still update the ValidBlock and obtain it via gossipping
|
// TODO: we may want to still update the ValidBlock and obtain it via gossipping
|
||||||
if !blockID.IsZero() &&
|
if len(blockID.Hash) != 0 &&
|
||||||
(cs.ValidRound < vote.Round) &&
|
(cs.ValidRound < vote.Round) &&
|
||||||
(vote.Round <= cs.Round) &&
|
(vote.Round <= cs.Round) &&
|
||||||
cs.ProposalBlock.HashesTo(blockID.Hash) {
|
cs.ProposalBlock.HashesTo(blockID.Hash) {
|
||||||
@@ -1621,14 +1633,14 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If +2/3 prevotes for *anything* for this or future round:
|
// If +2/3 prevotes for *anything* for future round:
|
||||||
if cs.Round <= vote.Round && prevotes.HasTwoThirdsAny() {
|
if cs.Round < vote.Round && prevotes.HasTwoThirdsAny() {
|
||||||
// Round-skip over to PrevoteWait or goto Precommit.
|
// Round-skip if there is any 2/3+ of votes ahead of us
|
||||||
cs.enterNewRound(height, vote.Round) // if the vote is ahead of us
|
cs.enterNewRound(height, vote.Round)
|
||||||
|
} else if cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step { // current round
|
||||||
if prevotes.HasTwoThirdsMajority() {
|
if prevotes.HasTwoThirdsMajority() {
|
||||||
cs.enterPrecommit(height, vote.Round)
|
cs.enterPrecommit(height, vote.Round)
|
||||||
} else {
|
} else if prevotes.HasTwoThirdsAny() {
|
||||||
cs.enterPrevote(height, vote.Round) // if the vote is ahead of us
|
|
||||||
cs.enterPrevoteWait(height, vote.Round)
|
cs.enterPrevoteWait(height, vote.Round)
|
||||||
}
|
}
|
||||||
} else if cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round {
|
} else if cs.Proposal != nil && 0 <= cs.Proposal.POLRound && cs.Proposal.POLRound == vote.Round {
|
||||||
@@ -1638,24 +1650,28 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
precommits := cs.Votes.Precommits(vote.Round)
|
precommits := cs.Votes.Precommits(vote.Round)
|
||||||
cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())
|
cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())
|
||||||
|
|
||||||
blockID, ok := precommits.TwoThirdsMajority()
|
blockID, ok := precommits.TwoThirdsMajority()
|
||||||
if ok && len(blockID.Hash) != 0 {
|
if ok {
|
||||||
// Executed as TwoThirdsMajority could be from a higher round
|
// Executed as TwoThirdsMajority could be from a higher round
|
||||||
cs.enterNewRound(height, vote.Round)
|
cs.enterNewRound(height, vote.Round)
|
||||||
cs.enterPrecommit(height, vote.Round)
|
cs.enterPrecommit(height, vote.Round)
|
||||||
|
if len(blockID.Hash) != 0 {
|
||||||
cs.enterCommit(height, vote.Round)
|
cs.enterCommit(height, vote.Round)
|
||||||
|
|
||||||
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
||||||
cs.enterNewRound(cs.Height, 0)
|
cs.enterNewRound(cs.Height, 0)
|
||||||
}
|
}
|
||||||
} else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() {
|
} else {
|
||||||
cs.enterNewRound(height, vote.Round)
|
|
||||||
cs.enterPrecommit(height, vote.Round)
|
|
||||||
cs.enterPrecommitWait(height, vote.Round)
|
cs.enterPrecommitWait(height, vote.Round)
|
||||||
}
|
}
|
||||||
|
} else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() {
|
||||||
|
cs.enterNewRound(height, vote.Round)
|
||||||
|
cs.enterPrecommitWait(height, vote.Round)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("Unexpected vote type %X", vote.Type)) // go-wire should prevent this.
|
panic(fmt.Sprintf("Unexpected vote type %X", vote.Type)) // go-wire should prevent this.
|
||||||
}
|
}
|
||||||
@@ -1663,7 +1679,7 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
func (cs *ConsensusState) signVote(type_ types.SignedMsgType, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
|
||||||
addr := cs.privValidator.GetAddress()
|
addr := cs.privValidator.GetAddress()
|
||||||
valIndex, _ := cs.Validators.GetByAddress(addr)
|
valIndex, _ := cs.Validators.GetByAddress(addr)
|
||||||
|
|
||||||
@@ -1698,7 +1714,7 @@ func (cs *ConsensusState) voteTime() time.Time {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sign the vote and publish on internalMsgQueue
|
// sign the vote and publish on internalMsgQueue
|
||||||
func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote {
|
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 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()) {
|
if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
|
||||||
return nil
|
return nil
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -99,8 +99,8 @@ func (hvs *HeightVoteSet) addRound(round int) {
|
|||||||
cmn.PanicSanity("addRound() for an existing round")
|
cmn.PanicSanity("addRound() for an existing round")
|
||||||
}
|
}
|
||||||
// log.Debug("addRound(round)", "round", round)
|
// log.Debug("addRound(round)", "round", round)
|
||||||
prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrevote, hvs.valSet)
|
prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.PrevoteType, hvs.valSet)
|
||||||
precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrecommit, hvs.valSet)
|
precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, types.PrecommitType, hvs.valSet)
|
||||||
hvs.roundVoteSets[round] = RoundVoteSet{
|
hvs.roundVoteSets[round] = RoundVoteSet{
|
||||||
Prevotes: prevotes,
|
Prevotes: prevotes,
|
||||||
Precommits: precommits,
|
Precommits: precommits,
|
||||||
@@ -134,13 +134,13 @@ func (hvs *HeightVoteSet) AddVote(vote *types.Vote, peerID p2p.ID) (added bool,
|
|||||||
func (hvs *HeightVoteSet) Prevotes(round int) *types.VoteSet {
|
func (hvs *HeightVoteSet) Prevotes(round int) *types.VoteSet {
|
||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
return hvs.getVoteSet(round, types.VoteTypePrevote)
|
return hvs.getVoteSet(round, types.PrevoteType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hvs *HeightVoteSet) Precommits(round int) *types.VoteSet {
|
func (hvs *HeightVoteSet) Precommits(round int) *types.VoteSet {
|
||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
return hvs.getVoteSet(round, types.VoteTypePrecommit)
|
return hvs.getVoteSet(round, types.PrecommitType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Last round and blockID that has +2/3 prevotes for a particular block or nil.
|
// Last round and blockID that has +2/3 prevotes for a particular block or nil.
|
||||||
@@ -149,7 +149,7 @@ func (hvs *HeightVoteSet) POLInfo() (polRound int, polBlockID types.BlockID) {
|
|||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
for r := hvs.round; r >= 0; r-- {
|
for r := hvs.round; r >= 0; r-- {
|
||||||
rvs := hvs.getVoteSet(r, types.VoteTypePrevote)
|
rvs := hvs.getVoteSet(r, types.PrevoteType)
|
||||||
polBlockID, ok := rvs.TwoThirdsMajority()
|
polBlockID, ok := rvs.TwoThirdsMajority()
|
||||||
if ok {
|
if ok {
|
||||||
return r, polBlockID
|
return r, polBlockID
|
||||||
@@ -158,15 +158,15 @@ func (hvs *HeightVoteSet) POLInfo() (polRound int, polBlockID types.BlockID) {
|
|||||||
return -1, types.BlockID{}
|
return -1, types.BlockID{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
|
func (hvs *HeightVoteSet) getVoteSet(round int, type_ types.SignedMsgType) *types.VoteSet {
|
||||||
rvs, ok := hvs.roundVoteSets[round]
|
rvs, ok := hvs.roundVoteSets[round]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return rvs.Prevotes
|
return rvs.Prevotes
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return rvs.Precommits
|
return rvs.Precommits
|
||||||
default:
|
default:
|
||||||
cmn.PanicSanity(fmt.Sprintf("Unexpected vote type %X", type_))
|
cmn.PanicSanity(fmt.Sprintf("Unexpected vote type %X", type_))
|
||||||
@@ -178,7 +178,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *types.VoteSet {
|
|||||||
// NOTE: if there are too many peers, or too much peer churn,
|
// NOTE: if there are too many peers, or too much peer churn,
|
||||||
// this can cause memory issues.
|
// this can cause memory issues.
|
||||||
// TODO: implement ability to remove peers too
|
// TODO: implement ability to remove peers too
|
||||||
func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ byte, peerID p2p.ID, blockID types.BlockID) error {
|
func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ types.SignedMsgType, peerID p2p.ID, blockID types.BlockID) error {
|
||||||
hvs.mtx.Lock()
|
hvs.mtx.Lock()
|
||||||
defer hvs.mtx.Unlock()
|
defer hvs.mtx.Unlock()
|
||||||
if !types.IsVoteTypeValid(type_) {
|
if !types.IsVoteTypeValid(type_) {
|
||||||
|
@@ -56,7 +56,7 @@ func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivVali
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: types.VoteTypePrecommit,
|
Type: types.PrecommitType,
|
||||||
BlockID: types.BlockID{[]byte("fakehash"), types.PartSetHeader{}},
|
BlockID: types.BlockID{[]byte("fakehash"), types.PartSetHeader{}},
|
||||||
}
|
}
|
||||||
chainID := config.ChainID()
|
chainID := config.ChainID()
|
||||||
|
@@ -46,6 +46,12 @@ func (privKey PrivKeyEd25519) Bytes() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign produces a signature on the provided message.
|
// Sign produces a signature on the provided message.
|
||||||
|
// This assumes the privkey is wellformed in the golang format.
|
||||||
|
// The first 32 bytes should be random,
|
||||||
|
// corresponding to the normal ed25519 private key.
|
||||||
|
// The latter 32 bytes should be the compressed public key.
|
||||||
|
// If these conditions aren't met, Sign will panic or produce an
|
||||||
|
// incorrect signature.
|
||||||
func (privKey PrivKeyEd25519) Sign(msg []byte) ([]byte, error) {
|
func (privKey PrivKeyEd25519) Sign(msg []byte) ([]byte, error) {
|
||||||
signatureBytes := ed25519.Sign(privKey[:], msg)
|
signatureBytes := ed25519.Sign(privKey[:], msg)
|
||||||
return signatureBytes[:], nil
|
return signatureBytes[:], nil
|
||||||
|
@@ -21,12 +21,16 @@ func SimpleHashFromTwoHashes(left, right []byte) []byte {
|
|||||||
// SimpleHashFromByteSlices computes a Merkle tree where the leaves are the byte slice,
|
// SimpleHashFromByteSlices computes a Merkle tree where the leaves are the byte slice,
|
||||||
// in the provided order.
|
// in the provided order.
|
||||||
func SimpleHashFromByteSlices(items [][]byte) []byte {
|
func SimpleHashFromByteSlices(items [][]byte) []byte {
|
||||||
hashes := make([][]byte, len(items))
|
switch len(items) {
|
||||||
for i, item := range items {
|
case 0:
|
||||||
hash := tmhash.Sum(item)
|
return nil
|
||||||
hashes[i] = hash
|
case 1:
|
||||||
|
return tmhash.Sum(items[0])
|
||||||
|
default:
|
||||||
|
left := SimpleHashFromByteSlices(items[:(len(items)+1)/2])
|
||||||
|
right := SimpleHashFromByteSlices(items[(len(items)+1)/2:])
|
||||||
|
return SimpleHashFromTwoHashes(left, right)
|
||||||
}
|
}
|
||||||
return simpleHashFromHashes(hashes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimpleHashFromMap computes a Merkle tree from sorted map.
|
// SimpleHashFromMap computes a Merkle tree from sorted map.
|
||||||
@@ -40,20 +44,3 @@ func SimpleHashFromMap(m map[string][]byte) []byte {
|
|||||||
}
|
}
|
||||||
return sm.Hash()
|
return sm.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
|
|
||||||
// Expects hashes!
|
|
||||||
func simpleHashFromHashes(hashes [][]byte) []byte {
|
|
||||||
// Recursive impl.
|
|
||||||
switch len(hashes) {
|
|
||||||
case 0:
|
|
||||||
return nil
|
|
||||||
case 1:
|
|
||||||
return hashes[0]
|
|
||||||
default:
|
|
||||||
left := simpleHashFromHashes(hashes[:(len(hashes)+1)/2])
|
|
||||||
right := simpleHashFromHashes(hashes[(len(hashes)+1)/2:])
|
|
||||||
return SimpleHashFromTwoHashes(left, right)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@@ -411,7 +411,8 @@ must be greater than 2/3 of the total voting power of the complete validator set
|
|||||||
A vote is a signed message broadcast in the consensus for a particular block at a particular height and round.
|
A vote is a signed message broadcast in the consensus for a particular block at a particular height and round.
|
||||||
When stored in the blockchain or propagated over the network, votes are encoded in Amino.
|
When stored in the blockchain or propagated over the network, votes are encoded in Amino.
|
||||||
For signing, votes are represented via `CanonicalVote` and also encoded using amino (protobuf compatible) via
|
For signing, votes are represented via `CanonicalVote` and also encoded using amino (protobuf compatible) via
|
||||||
`Vote.SignBytes` which includes the `ChainID`.
|
`Vote.SignBytes` which includes the `ChainID`, and uses a different ordering of
|
||||||
|
the fields.
|
||||||
|
|
||||||
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the `SignBytes`
|
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the `SignBytes`
|
||||||
using the given ChainID:
|
using the given ChainID:
|
||||||
|
@@ -300,20 +300,23 @@ Where the `"value"` is the base64 encoding of the raw pubkey bytes, and the
|
|||||||
|
|
||||||
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino.
|
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino.
|
||||||
|
|
||||||
When signing, the elements of a message are sorted alphabetically by key and prepended with
|
When signing, the elements of a message are re-ordered so the fixed-length fields
|
||||||
a `chain_id` and `type` field.
|
are first, making it easy to quickly check the version, height, round, and type.
|
||||||
|
The `ChainID` is also appended to the end.
|
||||||
We call this encoding the SignBytes. For instance, SignBytes for a vote is the Amino encoding of the following struct:
|
We call this encoding the SignBytes. For instance, SignBytes for a vote is the Amino encoding of the following struct:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type CanonicalVote struct {
|
type CanonicalVote struct {
|
||||||
ChainID string
|
Version uint64 `binary:"fixed64"`
|
||||||
Type string
|
Height int64 `binary:"fixed64"`
|
||||||
BlockID CanonicalBlockID
|
Round int64 `binary:"fixed64"`
|
||||||
Height int64
|
|
||||||
Round int
|
|
||||||
Timestamp time.Time
|
|
||||||
VoteType byte
|
VoteType byte
|
||||||
|
Timestamp time.Time
|
||||||
|
BlockID CanonicalBlockID
|
||||||
|
ChainID string
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
NOTE: see [#1622](https://github.com/tendermint/tendermint/issues/1622) for how field ordering will change
|
The field ordering and the fixed sized encoding for the first three fields is optimized to ease parsing of SignBytes
|
||||||
|
in HSMs. It creates fixed offsets for relevant fields that need to be read in this context.
|
||||||
|
See [#1622](https://github.com/tendermint/tendermint/issues/1622) for more details.
|
||||||
|
@@ -97,7 +97,7 @@ func makeVote(header *types.Header, valset *types.ValidatorSet, key crypto.PrivK
|
|||||||
Height: header.Height,
|
Height: header.Height,
|
||||||
Round: 1,
|
Round: 1,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: types.VoteTypePrecommit,
|
Type: types.PrecommitType,
|
||||||
BlockID: types.BlockID{Hash: header.Hash()},
|
BlockID: types.BlockID{Hash: header.Hash()},
|
||||||
}
|
}
|
||||||
// Sign it
|
// Sign it
|
||||||
|
@@ -761,8 +761,8 @@ func makeNodeInfo(
|
|||||||
if _, ok := txIndexer.(*null.TxIndex); ok {
|
if _, ok := txIndexer.(*null.TxIndex); ok {
|
||||||
txIndexerStatus = "off"
|
txIndexerStatus = "off"
|
||||||
}
|
}
|
||||||
nodeInfo := p2p.NodeInfo{
|
nodeInfo := p2p.DefaultNodeInfo{
|
||||||
ID: nodeID,
|
ID_: nodeID,
|
||||||
Network: chainID,
|
Network: chainID,
|
||||||
Version: version.Version,
|
Version: version.Version,
|
||||||
Channels: []byte{
|
Channels: []byte{
|
||||||
@@ -772,7 +772,7 @@ func makeNodeInfo(
|
|||||||
evidence.EvidenceChannel,
|
evidence.EvidenceChannel,
|
||||||
},
|
},
|
||||||
Moniker: config.Moniker,
|
Moniker: config.Moniker,
|
||||||
Other: p2p.NodeInfoOther{
|
Other: p2p.DefaultNodeInfoOther{
|
||||||
AminoVersion: amino.Version,
|
AminoVersion: amino.Version,
|
||||||
P2PVersion: p2p.Version,
|
P2PVersion: p2p.Version,
|
||||||
ConsensusVersion: cs.Version,
|
ConsensusVersion: cs.Version,
|
||||||
|
@@ -42,7 +42,7 @@ func (p *peer) IsPersistent() bool {
|
|||||||
|
|
||||||
// NodeInfo always returns empty node info.
|
// NodeInfo always returns empty node info.
|
||||||
func (p *peer) NodeInfo() p2p.NodeInfo {
|
func (p *peer) NodeInfo() p2p.NodeInfo {
|
||||||
return p2p.NodeInfo{}
|
return p2p.DefaultNodeInfo{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteIP always returns localhost.
|
// RemoteIP always returns localhost.
|
||||||
@@ -78,8 +78,3 @@ func (p *peer) Get(key string) interface{} {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OriginalAddr always returns nil.
|
|
||||||
func (p *peer) OriginalAddr() *p2p.NetAddress {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@@ -40,13 +40,12 @@ func (e ErrRejected) Error() string {
|
|||||||
if e.isDuplicate {
|
if e.isDuplicate {
|
||||||
if e.conn != nil {
|
if e.conn != nil {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"duplicate CONN<%s>: %s",
|
"duplicate CONN<%s>",
|
||||||
e.conn.RemoteAddr().String(),
|
e.conn.RemoteAddr().String(),
|
||||||
e.err,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if e.id != "" {
|
if e.id != "" {
|
||||||
return fmt.Sprintf("duplicate ID<%v>: %s", e.id, e.err)
|
return fmt.Sprintf("duplicate ID<%v>", e.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,7 +56,6 @@ func PrometheusMetrics(namespace string) *Metrics {
|
|||||||
Name: "num_txs",
|
Name: "num_txs",
|
||||||
Help: "Number of transactions submitted by each peer.",
|
Help: "Number of transactions submitted by each peer.",
|
||||||
}, []string{"peer_id"}),
|
}, []string{"peer_id"}),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@ package p2p
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
@@ -17,12 +18,32 @@ func MaxNodeInfoSize() int {
|
|||||||
return maxNodeInfoSize
|
return maxNodeInfoSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfo is the basic node information exchanged
|
// NodeInfo exposes basic info of a node
|
||||||
|
// and determines if we're compatible
|
||||||
|
type NodeInfo interface {
|
||||||
|
nodeInfoAddress
|
||||||
|
nodeInfoTransport
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeInfoAddress exposes just the core info of a node.
|
||||||
|
type nodeInfoAddress interface {
|
||||||
|
ID() ID
|
||||||
|
NetAddress() *NetAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// nodeInfoTransport is validates a nodeInfo and checks
|
||||||
|
// our compatibility with it. It's for use in the handshake.
|
||||||
|
type nodeInfoTransport interface {
|
||||||
|
ValidateBasic() error
|
||||||
|
CompatibleWith(other NodeInfo) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultNodeInfo is the basic node information exchanged
|
||||||
// between two peers during the Tendermint P2P handshake.
|
// between two peers during the Tendermint P2P handshake.
|
||||||
type NodeInfo struct {
|
type DefaultNodeInfo struct {
|
||||||
// Authenticate
|
// Authenticate
|
||||||
// TODO: replace with NetAddress
|
// TODO: replace with NetAddress
|
||||||
ID ID `json:"id"` // authenticated identifier
|
ID_ ID `json:"id"` // authenticated identifier
|
||||||
ListenAddr string `json:"listen_addr"` // accepting incoming
|
ListenAddr string `json:"listen_addr"` // accepting incoming
|
||||||
|
|
||||||
// Check compatibility.
|
// Check compatibility.
|
||||||
@@ -33,11 +54,11 @@ type NodeInfo struct {
|
|||||||
|
|
||||||
// ASCIIText fields
|
// ASCIIText fields
|
||||||
Moniker string `json:"moniker"` // arbitrary moniker
|
Moniker string `json:"moniker"` // arbitrary moniker
|
||||||
Other NodeInfoOther `json:"other"` // other application specific data
|
Other DefaultNodeInfoOther `json:"other"` // other application specific data
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeInfoOther is the misc. applcation specific data
|
// DefaultNodeInfoOther is the misc. applcation specific data
|
||||||
type NodeInfoOther struct {
|
type DefaultNodeInfoOther struct {
|
||||||
AminoVersion string `json:"amino_version"`
|
AminoVersion string `json:"amino_version"`
|
||||||
P2PVersion string `json:"p2p_version"`
|
P2PVersion string `json:"p2p_version"`
|
||||||
ConsensusVersion string `json:"consensus_version"`
|
ConsensusVersion string `json:"consensus_version"`
|
||||||
@@ -46,19 +67,12 @@ type NodeInfoOther struct {
|
|||||||
RPCAddress string `json:"rpc_address"`
|
RPCAddress string `json:"rpc_address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o NodeInfoOther) String() string {
|
// ID returns the node's peer ID.
|
||||||
return fmt.Sprintf(
|
func (info DefaultNodeInfo) ID() ID {
|
||||||
"{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v, rpc_address: %v}",
|
return info.ID_
|
||||||
o.AminoVersion,
|
|
||||||
o.P2PVersion,
|
|
||||||
o.ConsensusVersion,
|
|
||||||
o.RPCVersion,
|
|
||||||
o.TxIndex,
|
|
||||||
o.RPCAddress,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate checks the self-reported NodeInfo is safe.
|
// ValidateBasic checks the self-reported DefaultNodeInfo is safe.
|
||||||
// It returns an error if there
|
// It returns an error if there
|
||||||
// are too many Channels, if there are any duplicate Channels,
|
// are too many Channels, if there are any duplicate Channels,
|
||||||
// if the ListenAddr is malformed, or if the ListenAddr is a host name
|
// if the ListenAddr is malformed, or if the ListenAddr is a host name
|
||||||
@@ -71,7 +85,7 @@ func (o NodeInfoOther) String() string {
|
|||||||
// International clients could then use punycode (or we could use
|
// International clients could then use punycode (or we could use
|
||||||
// url-encoding), and we just need to be careful with how we handle that in our
|
// url-encoding), and we just need to be careful with how we handle that in our
|
||||||
// clients. (e.g. off by default).
|
// clients. (e.g. off by default).
|
||||||
func (info NodeInfo) Validate() error {
|
func (info DefaultNodeInfo) ValidateBasic() error {
|
||||||
if len(info.Channels) > maxNumChannels {
|
if len(info.Channels) > maxNumChannels {
|
||||||
return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels)
|
return fmt.Errorf("info.Channels is too long (%v). Max is %v", len(info.Channels), maxNumChannels)
|
||||||
}
|
}
|
||||||
@@ -111,14 +125,19 @@ func (info NodeInfo) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure ListenAddr is good
|
// ensure ListenAddr is good
|
||||||
_, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
|
_, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompatibleWith checks if two NodeInfo are compatible with eachother.
|
// CompatibleWith checks if two DefaultNodeInfo are compatible with eachother.
|
||||||
// CONTRACT: two nodes are compatible if the major version matches and network match
|
// CONTRACT: two nodes are compatible if the major version matches and network match
|
||||||
// and they have at least one channel in common.
|
// and they have at least one channel in common.
|
||||||
func (info NodeInfo) CompatibleWith(other NodeInfo) error {
|
func (info DefaultNodeInfo) CompatibleWith(other_ NodeInfo) error {
|
||||||
|
other, ok := other_.(DefaultNodeInfo)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("wrong NodeInfo type. Expected DefaultNodeInfo, got %v", reflect.TypeOf(other_))
|
||||||
|
}
|
||||||
|
|
||||||
iMajor, _, _, iErr := splitVersion(info.Version)
|
iMajor, _, _, iErr := splitVersion(info.Version)
|
||||||
oMajor, _, _, oErr := splitVersion(other.Version)
|
oMajor, _, _, oErr := splitVersion(other.Version)
|
||||||
|
|
||||||
@@ -164,18 +183,18 @@ OUTER_LOOP:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetAddress returns a NetAddress derived from the NodeInfo -
|
// NetAddress returns a NetAddress derived from the DefaultNodeInfo -
|
||||||
// it includes the authenticated peer ID and the self-reported
|
// it includes the authenticated peer ID and the self-reported
|
||||||
// ListenAddr. Note that the ListenAddr is not authenticated and
|
// ListenAddr. Note that the ListenAddr is not authenticated and
|
||||||
// may not match that address actually dialed if its an outbound peer.
|
// may not match that address actually dialed if its an outbound peer.
|
||||||
func (info NodeInfo) NetAddress() *NetAddress {
|
func (info DefaultNodeInfo) NetAddress() *NetAddress {
|
||||||
netAddr, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
|
netAddr, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case ErrNetAddressLookup:
|
case ErrNetAddressLookup:
|
||||||
// XXX If the peer provided a host name and the lookup fails here
|
// XXX If the peer provided a host name and the lookup fails here
|
||||||
// we're out of luck.
|
// we're out of luck.
|
||||||
// TODO: use a NetAddress in NodeInfo
|
// TODO: use a NetAddress in DefaultNodeInfo
|
||||||
default:
|
default:
|
||||||
panic(err) // everything should be well formed by now
|
panic(err) // everything should be well formed by now
|
||||||
}
|
}
|
||||||
@@ -183,11 +202,6 @@ func (info NodeInfo) NetAddress() *NetAddress {
|
|||||||
return netAddr
|
return netAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info NodeInfo) String() string {
|
|
||||||
return fmt.Sprintf("NodeInfo{id: %v, moniker: %v, network: %v [listen %v], version: %v (%v)}",
|
|
||||||
info.ID, info.Moniker, info.Network, info.ListenAddr, info.Version, info.Other)
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitVersion(version string) (string, string, string, error) {
|
func splitVersion(version string) (string, string, string, error) {
|
||||||
spl := strings.Split(version, ".")
|
spl := strings.Split(version, ".")
|
||||||
if len(spl) != 3 {
|
if len(spl) != 3 {
|
||||||
|
93
p2p/peer.go
93
p2p/peer.go
@@ -3,7 +3,6 @@ package p2p
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
@@ -15,19 +14,18 @@ import (
|
|||||||
|
|
||||||
const metricsTickerDuration = 10 * time.Second
|
const metricsTickerDuration = 10 * time.Second
|
||||||
|
|
||||||
var testIPSuffix uint32
|
|
||||||
|
|
||||||
// Peer is an interface representing a peer connected on a reactor.
|
// Peer is an interface representing a peer connected on a reactor.
|
||||||
type Peer interface {
|
type Peer interface {
|
||||||
cmn.Service
|
cmn.Service
|
||||||
|
|
||||||
ID() ID // peer's cryptographic ID
|
ID() ID // peer's cryptographic ID
|
||||||
RemoteIP() net.IP // remote IP of the connection
|
RemoteIP() net.IP // remote IP of the connection
|
||||||
|
|
||||||
IsOutbound() bool // did we dial the peer
|
IsOutbound() bool // did we dial the peer
|
||||||
IsPersistent() bool // do we redial this peer when we disconnect
|
IsPersistent() bool // do we redial this peer when we disconnect
|
||||||
|
|
||||||
NodeInfo() NodeInfo // peer's info
|
NodeInfo() NodeInfo // peer's info
|
||||||
Status() tmconn.ConnectionStatus
|
Status() tmconn.ConnectionStatus
|
||||||
OriginalAddr() *NetAddress
|
|
||||||
|
|
||||||
Send(byte, []byte) bool
|
Send(byte, []byte) bool
|
||||||
TrySend(byte, []byte) bool
|
TrySend(byte, []byte) bool
|
||||||
@@ -44,8 +42,9 @@ type peerConn struct {
|
|||||||
persistent bool
|
persistent bool
|
||||||
config *config.P2PConfig
|
config *config.P2PConfig
|
||||||
conn net.Conn // source connection
|
conn net.Conn // source connection
|
||||||
|
|
||||||
|
// cached RemoteIP()
|
||||||
ip net.IP
|
ip net.IP
|
||||||
originalAddr *NetAddress // nil for inbound connections
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID only exists for SecretConnection.
|
// ID only exists for SecretConnection.
|
||||||
@@ -60,14 +59,6 @@ func (pc peerConn) RemoteIP() net.IP {
|
|||||||
return pc.ip
|
return pc.ip
|
||||||
}
|
}
|
||||||
|
|
||||||
// In test cases a conn could not be present at all or be an in-memory
|
|
||||||
// implementation where we want to return a fake ip.
|
|
||||||
if pc.conn == nil || pc.conn.RemoteAddr().String() == "pipe" {
|
|
||||||
pc.ip = net.IP{172, 16, 0, byte(atomic.AddUint32(&testIPSuffix, 1))}
|
|
||||||
|
|
||||||
return pc.ip
|
|
||||||
}
|
|
||||||
|
|
||||||
host, _, err := net.SplitHostPort(pc.conn.RemoteAddr().String())
|
host, _, err := net.SplitHostPort(pc.conn.RemoteAddr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -120,7 +111,7 @@ func newPeer(
|
|||||||
p := &peer{
|
p := &peer{
|
||||||
peerConn: pc,
|
peerConn: pc,
|
||||||
nodeInfo: nodeInfo,
|
nodeInfo: nodeInfo,
|
||||||
channels: nodeInfo.Channels,
|
channels: nodeInfo.(DefaultNodeInfo).Channels, // TODO
|
||||||
Data: cmn.NewCMap(),
|
Data: cmn.NewCMap(),
|
||||||
metricsTicker: time.NewTicker(metricsTickerDuration),
|
metricsTicker: time.NewTicker(metricsTickerDuration),
|
||||||
metrics: NopMetrics(),
|
metrics: NopMetrics(),
|
||||||
@@ -142,6 +133,15 @@ func newPeer(
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String representation.
|
||||||
|
func (p *peer) String() string {
|
||||||
|
if p.outbound {
|
||||||
|
return fmt.Sprintf("Peer{%v %v out}", p.mconn, p.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.ID())
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------
|
//---------------------------------------------------
|
||||||
// Implements cmn.Service
|
// Implements cmn.Service
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ func (p *peer) OnStop() {
|
|||||||
|
|
||||||
// ID returns the peer's ID - the hex encoded hash of its pubkey.
|
// ID returns the peer's ID - the hex encoded hash of its pubkey.
|
||||||
func (p *peer) ID() ID {
|
func (p *peer) ID() ID {
|
||||||
return p.nodeInfo.ID
|
return p.nodeInfo.ID()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOutbound returns true if the connection is outbound, false otherwise.
|
// IsOutbound returns true if the connection is outbound, false otherwise.
|
||||||
@@ -195,15 +195,6 @@ func (p *peer) NodeInfo() NodeInfo {
|
|||||||
return p.nodeInfo
|
return p.nodeInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// OriginalAddr returns the original address, which was used to connect with
|
|
||||||
// the peer. Returns nil for inbound peers.
|
|
||||||
func (p *peer) OriginalAddr() *NetAddress {
|
|
||||||
if p.peerConn.outbound {
|
|
||||||
return p.peerConn.originalAddr
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status returns the peer's ConnectionStatus.
|
// Status returns the peer's ConnectionStatus.
|
||||||
func (p *peer) Status() tmconn.ConnectionStatus {
|
func (p *peer) Status() tmconn.ConnectionStatus {
|
||||||
return p.mconn.Status()
|
return p.mconn.Status()
|
||||||
@@ -272,53 +263,14 @@ func (p *peer) hasChannel(chID byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------
|
//---------------------------------------------------
|
||||||
// methods used by the Switch
|
// methods only used for testing
|
||||||
|
// TODO: can we remove these?
|
||||||
|
|
||||||
// CloseConn should be called by the Switch if the peer was created but never
|
// CloseConn closes the underlying connection
|
||||||
// started.
|
|
||||||
func (pc *peerConn) CloseConn() {
|
func (pc *peerConn) CloseConn() {
|
||||||
pc.conn.Close() // nolint: errcheck
|
pc.conn.Close() // nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandshakeTimeout performs the Tendermint P2P handshake between a given node
|
|
||||||
// and the peer by exchanging their NodeInfo. It sets the received nodeInfo on
|
|
||||||
// the peer.
|
|
||||||
// NOTE: blocking
|
|
||||||
func (pc *peerConn) HandshakeTimeout(
|
|
||||||
ourNodeInfo NodeInfo,
|
|
||||||
timeout time.Duration,
|
|
||||||
) (peerNodeInfo NodeInfo, err error) {
|
|
||||||
// Set deadline for handshake so we don't block forever on conn.ReadFull
|
|
||||||
if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
|
|
||||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error setting deadline")
|
|
||||||
}
|
|
||||||
|
|
||||||
var trs, _ = cmn.Parallel(
|
|
||||||
func(_ int) (val interface{}, err error, abort bool) {
|
|
||||||
_, err = cdc.MarshalBinaryWriter(pc.conn, ourNodeInfo)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
func(_ int) (val interface{}, err error, abort bool) {
|
|
||||||
_, err = cdc.UnmarshalBinaryReader(
|
|
||||||
pc.conn,
|
|
||||||
&peerNodeInfo,
|
|
||||||
int64(MaxNodeInfoSize()),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err := trs.FirstError(); err != nil {
|
|
||||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error during handshake")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove deadline
|
|
||||||
if err := pc.conn.SetDeadline(time.Time{}); err != nil {
|
|
||||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error removing deadline")
|
|
||||||
}
|
|
||||||
|
|
||||||
return peerNodeInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addr returns peer's remote network address.
|
// Addr returns peer's remote network address.
|
||||||
func (p *peer) Addr() net.Addr {
|
func (p *peer) Addr() net.Addr {
|
||||||
return p.peerConn.conn.RemoteAddr()
|
return p.peerConn.conn.RemoteAddr()
|
||||||
@@ -332,14 +284,7 @@ func (p *peer) CanSend(chID byte) bool {
|
|||||||
return p.mconn.CanSend(chID)
|
return p.mconn.CanSend(chID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String representation.
|
//---------------------------------------------------
|
||||||
func (p *peer) String() string {
|
|
||||||
if p.outbound {
|
|
||||||
return fmt.Sprintf("Peer{%v %v out}", p.mconn, p.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func PeerMetrics(metrics *Metrics) PeerOption {
|
func PeerMetrics(metrics *Metrics) PeerOption {
|
||||||
return func(p *peer) {
|
return func(p *peer) {
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -12,24 +11,34 @@ import (
|
|||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns an empty kvstore peer
|
// mockPeer for testing the PeerSet
|
||||||
func randPeer(ip net.IP) *peer {
|
type mockPeer struct {
|
||||||
|
cmn.BaseService
|
||||||
|
ip net.IP
|
||||||
|
id ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *mockPeer) TrySend(chID byte, msgBytes []byte) bool { return true }
|
||||||
|
func (mp *mockPeer) Send(chID byte, msgBytes []byte) bool { return true }
|
||||||
|
func (mp *mockPeer) NodeInfo() NodeInfo { return DefaultNodeInfo{} }
|
||||||
|
func (mp *mockPeer) Status() ConnectionStatus { return ConnectionStatus{} }
|
||||||
|
func (mp *mockPeer) ID() ID { return mp.id }
|
||||||
|
func (mp *mockPeer) IsOutbound() bool { return false }
|
||||||
|
func (mp *mockPeer) IsPersistent() bool { return true }
|
||||||
|
func (mp *mockPeer) Get(s string) interface{} { return s }
|
||||||
|
func (mp *mockPeer) Set(string, interface{}) {}
|
||||||
|
func (mp *mockPeer) RemoteIP() net.IP { return mp.ip }
|
||||||
|
|
||||||
|
// Returns a mock peer
|
||||||
|
func newMockPeer(ip net.IP) *mockPeer {
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
ip = net.IP{127, 0, 0, 1}
|
ip = net.IP{127, 0, 0, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||||
p := &peer{
|
return &mockPeer{
|
||||||
nodeInfo: NodeInfo{
|
ip: ip,
|
||||||
ID: nodeKey.ID(),
|
id: nodeKey.ID(),
|
||||||
ListenAddr: fmt.Sprintf("%v.%v.%v.%v:26656", cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256),
|
|
||||||
},
|
|
||||||
metrics: NopMetrics(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ip = ip
|
|
||||||
|
|
||||||
return p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerSetAddRemoveOne(t *testing.T) {
|
func TestPeerSetAddRemoveOne(t *testing.T) {
|
||||||
@@ -39,7 +48,7 @@ func TestPeerSetAddRemoveOne(t *testing.T) {
|
|||||||
|
|
||||||
var peerList []Peer
|
var peerList []Peer
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
p := randPeer(net.IP{127, 0, 0, byte(i)})
|
p := newMockPeer(net.IP{127, 0, 0, byte(i)})
|
||||||
if err := peerSet.Add(p); err != nil {
|
if err := peerSet.Add(p); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -83,7 +92,7 @@ func TestPeerSetAddRemoveMany(t *testing.T) {
|
|||||||
peers := []Peer{}
|
peers := []Peer{}
|
||||||
N := 100
|
N := 100
|
||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
peer := randPeer(net.IP{127, 0, 0, byte(i)})
|
peer := newMockPeer(net.IP{127, 0, 0, byte(i)})
|
||||||
if err := peerSet.Add(peer); err != nil {
|
if err := peerSet.Add(peer); err != nil {
|
||||||
t.Errorf("Failed to add new peer")
|
t.Errorf("Failed to add new peer")
|
||||||
}
|
}
|
||||||
@@ -107,7 +116,7 @@ func TestPeerSetAddRemoveMany(t *testing.T) {
|
|||||||
func TestPeerSetAddDuplicate(t *testing.T) {
|
func TestPeerSetAddDuplicate(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
peerSet := NewPeerSet()
|
peerSet := NewPeerSet()
|
||||||
peer := randPeer(nil)
|
peer := newMockPeer(nil)
|
||||||
|
|
||||||
n := 20
|
n := 20
|
||||||
errsChan := make(chan error)
|
errsChan := make(chan error)
|
||||||
@@ -149,7 +158,7 @@ func TestPeerSetGet(t *testing.T) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
peerSet = NewPeerSet()
|
peerSet = NewPeerSet()
|
||||||
peer = randPeer(nil)
|
peer = newMockPeer(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
assert.Nil(t, peerSet.Get(peer.ID()), "expecting a nil lookup, before .Add")
|
assert.Nil(t, peerSet.Get(peer.ID()), "expecting a nil lookup, before .Add")
|
||||||
|
@@ -19,8 +19,6 @@ import (
|
|||||||
tmconn "github.com/tendermint/tendermint/p2p/conn"
|
tmconn "github.com/tendermint/tendermint/p2p/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testCh = 0x01
|
|
||||||
|
|
||||||
func TestPeerBasic(t *testing.T) {
|
func TestPeerBasic(t *testing.T) {
|
||||||
assert, require := assert.New(t), require.New(t)
|
assert, require := assert.New(t), require.New(t)
|
||||||
|
|
||||||
@@ -81,18 +79,14 @@ func createOutboundPeerAndPerformHandshake(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nodeInfo, err := pc.HandshakeTimeout(NodeInfo{
|
timeout := 1 * time.Second
|
||||||
ID: addr.ID,
|
ourNodeInfo := testNodeInfo(addr.ID, "host_peer")
|
||||||
Moniker: "host_peer",
|
peerNodeInfo, err := handshake(pc.conn, timeout, ourNodeInfo)
|
||||||
Network: "testing",
|
|
||||||
Version: "123.123.123",
|
|
||||||
Channels: []byte{testCh},
|
|
||||||
}, 1*time.Second)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := newPeer(pc, mConfig, nodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {})
|
p := newPeer(pc, mConfig, peerNodeInfo, reactorsByCh, chDescs, func(p Peer, r interface{}) {})
|
||||||
p.SetLogger(log.TestingLogger().With("peer", addr))
|
p.SetLogger(log.TestingLogger().With("peer", addr))
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
@@ -120,7 +114,7 @@ func testOutboundPeerConn(
|
|||||||
return peerConn{}, cmn.ErrorWrap(err, "Error creating peer")
|
return peerConn{}, cmn.ErrorWrap(err, "Error creating peer")
|
||||||
}
|
}
|
||||||
|
|
||||||
pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey, addr)
|
pc, err := testPeerConn(conn, config, true, persistent, ourNodePrivKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if cerr := conn.Close(); cerr != nil {
|
if cerr := conn.Close(); cerr != nil {
|
||||||
return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
|
return peerConn{}, cmn.ErrorWrap(err, cerr.Error())
|
||||||
@@ -191,14 +185,7 @@ func (rp *remotePeer) accept(l net.Listener) {
|
|||||||
golog.Fatalf("Failed to create a peer: %+v", err)
|
golog.Fatalf("Failed to create a peer: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = handshake(pc.conn, time.Second, NodeInfo{
|
_, err = handshake(pc.conn, time.Second, rp.nodeInfo(l))
|
||||||
ID: rp.Addr().ID,
|
|
||||||
Moniker: "remote_peer",
|
|
||||||
Network: "testing",
|
|
||||||
Version: "123.123.123",
|
|
||||||
ListenAddr: l.Addr().String(),
|
|
||||||
Channels: rp.channels,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
golog.Fatalf("Failed to perform handshake: %+v", err)
|
golog.Fatalf("Failed to perform handshake: %+v", err)
|
||||||
}
|
}
|
||||||
@@ -217,3 +204,14 @@ func (rp *remotePeer) accept(l net.Listener) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rp *remotePeer) nodeInfo(l net.Listener) NodeInfo {
|
||||||
|
return DefaultNodeInfo{
|
||||||
|
ID_: rp.Addr().ID,
|
||||||
|
Moniker: "remote_peer",
|
||||||
|
Network: "testing",
|
||||||
|
Version: "123.123.123",
|
||||||
|
ListenAddr: l.Addr().String(),
|
||||||
|
Channels: rp.channels,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -320,7 +320,7 @@ func TestPEXReactorDoesNotAddPrivatePeersToAddrBook(t *testing.T) {
|
|||||||
peer := p2p.CreateRandomPeer(false)
|
peer := p2p.CreateRandomPeer(false)
|
||||||
|
|
||||||
pexR, book := createReactor(&PEXReactorConfig{})
|
pexR, book := createReactor(&PEXReactorConfig{})
|
||||||
book.AddPrivateIDs([]string{string(peer.NodeInfo().ID)})
|
book.AddPrivateIDs([]string{string(peer.NodeInfo().ID())})
|
||||||
defer teardownReactor(book)
|
defer teardownReactor(book)
|
||||||
|
|
||||||
// we have to send a request to receive responses
|
// we have to send a request to receive responses
|
||||||
@@ -391,8 +391,8 @@ func (mp mockPeer) ID() p2p.ID { return mp.addr.ID }
|
|||||||
func (mp mockPeer) IsOutbound() bool { return mp.outbound }
|
func (mp mockPeer) IsOutbound() bool { return mp.outbound }
|
||||||
func (mp mockPeer) IsPersistent() bool { return mp.persistent }
|
func (mp mockPeer) IsPersistent() bool { return mp.persistent }
|
||||||
func (mp mockPeer) NodeInfo() p2p.NodeInfo {
|
func (mp mockPeer) NodeInfo() p2p.NodeInfo {
|
||||||
return p2p.NodeInfo{
|
return p2p.DefaultNodeInfo{
|
||||||
ID: mp.addr.ID,
|
ID_: mp.addr.ID,
|
||||||
ListenAddr: mp.addr.DialString(),
|
ListenAddr: mp.addr.DialString(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,7 +402,6 @@ func (mockPeer) Send(byte, []byte) bool { return false }
|
|||||||
func (mockPeer) TrySend(byte, []byte) bool { return false }
|
func (mockPeer) TrySend(byte, []byte) bool { return false }
|
||||||
func (mockPeer) Set(string, interface{}) {}
|
func (mockPeer) Set(string, interface{}) {}
|
||||||
func (mockPeer) Get(string) interface{} { return nil }
|
func (mockPeer) Get(string) interface{} { return nil }
|
||||||
func (mockPeer) OriginalAddr() *p2p.NetAddress { return nil }
|
|
||||||
|
|
||||||
func assertPeersWithTimeout(
|
func assertPeersWithTimeout(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
|
@@ -280,12 +280,9 @@ func (sw *Switch) StopPeerForError(peer Peer, reason interface{}) {
|
|||||||
sw.stopAndRemovePeer(peer, reason)
|
sw.stopAndRemovePeer(peer, reason)
|
||||||
|
|
||||||
if peer.IsPersistent() {
|
if peer.IsPersistent() {
|
||||||
addr := peer.OriginalAddr()
|
// TODO: use the original address dialed, not the self reported one
|
||||||
if addr == nil {
|
// See #2618.
|
||||||
// FIXME: persistent peers can't be inbound right now.
|
addr := peer.NodeInfo().NetAddress()
|
||||||
// self-reported address for inbound persistent peers
|
|
||||||
addr = peer.NodeInfo().NetAddress()
|
|
||||||
}
|
|
||||||
go sw.reconnectToPeer(addr)
|
go sw.reconnectToPeer(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -560,9 +557,13 @@ func (sw *Switch) addOutboundPeerWithConfig(
|
|||||||
// to avoid dialing in the future.
|
// to avoid dialing in the future.
|
||||||
sw.addrBook.RemoveAddress(addr)
|
sw.addrBook.RemoveAddress(addr)
|
||||||
sw.addrBook.AddOurAddress(addr)
|
sw.addrBook.AddOurAddress(addr)
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// retry persistent peers after
|
||||||
|
// any dial error besides IsSelf()
|
||||||
if persistent {
|
if persistent {
|
||||||
go sw.reconnectToPeer(addr)
|
go sw.reconnectToPeer(addr)
|
||||||
}
|
}
|
||||||
|
@@ -143,6 +143,7 @@ func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, r
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
t.Fatalf("Expected to have received 1 message in channel #%v, got zero", channel)
|
t.Fatalf("Expected to have received 1 message in channel #%v, got zero", channel)
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,19 @@ import (
|
|||||||
"github.com/tendermint/tendermint/p2p/conn"
|
"github.com/tendermint/tendermint/p2p/conn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const testCh = 0x01
|
||||||
|
|
||||||
|
//------------------------------------------------
|
||||||
|
|
||||||
|
type mockNodeInfo struct {
|
||||||
|
addr *NetAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ni mockNodeInfo) ID() ID { return ni.addr.ID }
|
||||||
|
func (ni mockNodeInfo) NetAddress() *NetAddress { return ni.addr }
|
||||||
|
func (ni mockNodeInfo) ValidateBasic() error { return nil }
|
||||||
|
func (ni mockNodeInfo) CompatibleWith(other NodeInfo) error { return nil }
|
||||||
|
|
||||||
func AddPeerToSwitch(sw *Switch, peer Peer) {
|
func AddPeerToSwitch(sw *Switch, peer Peer) {
|
||||||
sw.peers.Add(peer)
|
sw.peers.Add(peer)
|
||||||
}
|
}
|
||||||
@@ -24,10 +37,7 @@ func CreateRandomPeer(outbound bool) *peer {
|
|||||||
peerConn: peerConn{
|
peerConn: peerConn{
|
||||||
outbound: outbound,
|
outbound: outbound,
|
||||||
},
|
},
|
||||||
nodeInfo: NodeInfo{
|
nodeInfo: mockNodeInfo{netAddr},
|
||||||
ID: netAddr.ID,
|
|
||||||
ListenAddr: netAddr.DialString(),
|
|
||||||
},
|
|
||||||
mconn: &conn.MConnection{},
|
mconn: &conn.MConnection{},
|
||||||
metrics: NopMetrics(),
|
metrics: NopMetrics(),
|
||||||
}
|
}
|
||||||
@@ -159,36 +169,15 @@ func MakeSwitch(
|
|||||||
initSwitch func(int, *Switch) *Switch,
|
initSwitch func(int, *Switch) *Switch,
|
||||||
opts ...SwitchOption,
|
opts ...SwitchOption,
|
||||||
) *Switch {
|
) *Switch {
|
||||||
var (
|
|
||||||
nodeKey = NodeKey{
|
nodeKey := NodeKey{
|
||||||
PrivKey: ed25519.GenPrivKey(),
|
PrivKey: ed25519.GenPrivKey(),
|
||||||
}
|
}
|
||||||
ni = NodeInfo{
|
nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i))
|
||||||
ID: nodeKey.ID(),
|
|
||||||
Moniker: fmt.Sprintf("switch%d", i),
|
|
||||||
Network: network,
|
|
||||||
Version: version,
|
|
||||||
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
|
||||||
Other: NodeInfoOther{
|
|
||||||
AminoVersion: "1.0",
|
|
||||||
P2PVersion: "1.0",
|
|
||||||
ConsensusVersion: "1.0",
|
|
||||||
RPCVersion: "1.0",
|
|
||||||
TxIndex: "off",
|
|
||||||
RPCAddress: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
addr, err := NewNetAddressStringWithOptionalID(
|
t := NewMultiplexTransport(nodeInfo, nodeKey)
|
||||||
IDAddressString(nodeKey.ID(), ni.ListenAddr),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := NewMultiplexTransport(ni, nodeKey)
|
|
||||||
|
|
||||||
|
addr := nodeInfo.NetAddress()
|
||||||
if err := t.Listen(*addr); err != nil {
|
if err := t.Listen(*addr); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -198,14 +187,16 @@ func MakeSwitch(
|
|||||||
sw.SetLogger(log.TestingLogger())
|
sw.SetLogger(log.TestingLogger())
|
||||||
sw.SetNodeKey(&nodeKey)
|
sw.SetNodeKey(&nodeKey)
|
||||||
|
|
||||||
|
ni := nodeInfo.(DefaultNodeInfo)
|
||||||
for ch := range sw.reactorsByCh {
|
for ch := range sw.reactorsByCh {
|
||||||
ni.Channels = append(ni.Channels, ch)
|
ni.Channels = append(ni.Channels, ch)
|
||||||
}
|
}
|
||||||
|
nodeInfo = ni
|
||||||
|
|
||||||
// TODO: We need to setup reactors ahead of time so the NodeInfo is properly
|
// TODO: We need to setup reactors ahead of time so the NodeInfo is properly
|
||||||
// populated and we don't have to do those awkward overrides and setters.
|
// populated and we don't have to do those awkward overrides and setters.
|
||||||
t.nodeInfo = ni
|
t.nodeInfo = nodeInfo
|
||||||
sw.SetNodeInfo(ni)
|
sw.SetNodeInfo(nodeInfo)
|
||||||
|
|
||||||
return sw
|
return sw
|
||||||
}
|
}
|
||||||
@@ -215,7 +206,7 @@ func testInboundPeerConn(
|
|||||||
config *config.P2PConfig,
|
config *config.P2PConfig,
|
||||||
ourNodePrivKey crypto.PrivKey,
|
ourNodePrivKey crypto.PrivKey,
|
||||||
) (peerConn, error) {
|
) (peerConn, error) {
|
||||||
return testPeerConn(conn, config, false, false, ourNodePrivKey, nil)
|
return testPeerConn(conn, config, false, false, ourNodePrivKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPeerConn(
|
func testPeerConn(
|
||||||
@@ -223,7 +214,6 @@ func testPeerConn(
|
|||||||
cfg *config.P2PConfig,
|
cfg *config.P2PConfig,
|
||||||
outbound, persistent bool,
|
outbound, persistent bool,
|
||||||
ourNodePrivKey crypto.PrivKey,
|
ourNodePrivKey crypto.PrivKey,
|
||||||
originalAddr *NetAddress,
|
|
||||||
) (pc peerConn, err error) {
|
) (pc peerConn, err error) {
|
||||||
conn := rawConn
|
conn := rawConn
|
||||||
|
|
||||||
@@ -245,6 +235,23 @@ func testPeerConn(
|
|||||||
outbound: outbound,
|
outbound: outbound,
|
||||||
persistent: persistent,
|
persistent: persistent,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
originalAddr: originalAddr,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// rand node info
|
||||||
|
|
||||||
|
func testNodeInfo(id ID, name string) NodeInfo {
|
||||||
|
return testNodeInfoWithNetwork(id, name, "testing")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
|
||||||
|
return DefaultNodeInfo{
|
||||||
|
ID_: id,
|
||||||
|
ListenAddr: fmt.Sprintf("127.0.0.1:%d", cmn.RandIntn(64512)+1023),
|
||||||
|
Moniker: name,
|
||||||
|
Network: network,
|
||||||
|
Version: "123.123.123",
|
||||||
|
Channels: []byte{testCh},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -335,7 +335,7 @@ func (mt *MultiplexTransport) upgrade(
|
|||||||
|
|
||||||
secretConn, err = upgradeSecretConn(c, mt.handshakeTimeout, mt.nodeKey.PrivKey)
|
secretConn, err = upgradeSecretConn(c, mt.handshakeTimeout, mt.nodeKey.PrivKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
conn: c,
|
conn: c,
|
||||||
err: fmt.Errorf("secrect conn failed: %v", err),
|
err: fmt.Errorf("secrect conn failed: %v", err),
|
||||||
isAuthFailure: true,
|
isAuthFailure: true,
|
||||||
@@ -344,15 +344,15 @@ func (mt *MultiplexTransport) upgrade(
|
|||||||
|
|
||||||
nodeInfo, err = handshake(secretConn, mt.handshakeTimeout, mt.nodeInfo)
|
nodeInfo, err = handshake(secretConn, mt.handshakeTimeout, mt.nodeInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
conn: c,
|
conn: c,
|
||||||
err: fmt.Errorf("handshake failed: %v", err),
|
err: fmt.Errorf("handshake failed: %v", err),
|
||||||
isAuthFailure: true,
|
isAuthFailure: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := nodeInfo.Validate(); err != nil {
|
if err := nodeInfo.ValidateBasic(); err != nil {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
conn: c,
|
conn: c,
|
||||||
err: err,
|
err: err,
|
||||||
isNodeInfoInvalid: true,
|
isNodeInfoInvalid: true,
|
||||||
@@ -360,34 +360,34 @@ func (mt *MultiplexTransport) upgrade(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure connection key matches self reported key.
|
// Ensure connection key matches self reported key.
|
||||||
if connID := PubKeyToID(secretConn.RemotePubKey()); connID != nodeInfo.ID {
|
if connID := PubKeyToID(secretConn.RemotePubKey()); connID != nodeInfo.ID() {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
conn: c,
|
conn: c,
|
||||||
id: connID,
|
id: connID,
|
||||||
err: fmt.Errorf(
|
err: fmt.Errorf(
|
||||||
"conn.ID (%v) NodeInfo.ID (%v) missmatch",
|
"conn.ID (%v) NodeInfo.ID (%v) missmatch",
|
||||||
connID,
|
connID,
|
||||||
nodeInfo.ID,
|
nodeInfo.ID(),
|
||||||
),
|
),
|
||||||
isAuthFailure: true,
|
isAuthFailure: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject self.
|
// Reject self.
|
||||||
if mt.nodeInfo.ID == nodeInfo.ID {
|
if mt.nodeInfo.ID() == nodeInfo.ID() {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
addr: *NewNetAddress(nodeInfo.ID, c.RemoteAddr()),
|
addr: *NewNetAddress(nodeInfo.ID(), c.RemoteAddr()),
|
||||||
conn: c,
|
conn: c,
|
||||||
id: nodeInfo.ID,
|
id: nodeInfo.ID(),
|
||||||
isSelf: true,
|
isSelf: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mt.nodeInfo.CompatibleWith(nodeInfo); err != nil {
|
if err := mt.nodeInfo.CompatibleWith(nodeInfo); err != nil {
|
||||||
return nil, NodeInfo{}, ErrRejected{
|
return nil, nil, ErrRejected{
|
||||||
conn: c,
|
conn: c,
|
||||||
err: err,
|
err: err,
|
||||||
id: nodeInfo.ID,
|
id: nodeInfo.ID(),
|
||||||
isIncompatible: true,
|
isIncompatible: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -430,17 +430,18 @@ func handshake(
|
|||||||
nodeInfo NodeInfo,
|
nodeInfo NodeInfo,
|
||||||
) (NodeInfo, error) {
|
) (NodeInfo, error) {
|
||||||
if err := c.SetDeadline(time.Now().Add(timeout)); err != nil {
|
if err := c.SetDeadline(time.Now().Add(timeout)); err != nil {
|
||||||
return NodeInfo{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errc = make(chan error, 2)
|
errc = make(chan error, 2)
|
||||||
|
|
||||||
peerNodeInfo NodeInfo
|
peerNodeInfo DefaultNodeInfo
|
||||||
|
ourNodeInfo = nodeInfo.(DefaultNodeInfo)
|
||||||
)
|
)
|
||||||
|
|
||||||
go func(errc chan<- error, c net.Conn) {
|
go func(errc chan<- error, c net.Conn) {
|
||||||
_, err := cdc.MarshalBinaryWriter(c, nodeInfo)
|
_, err := cdc.MarshalBinaryWriter(c, ourNodeInfo)
|
||||||
errc <- err
|
errc <- err
|
||||||
}(errc, c)
|
}(errc, c)
|
||||||
go func(errc chan<- error, c net.Conn) {
|
go func(errc chan<- error, c net.Conn) {
|
||||||
@@ -455,7 +456,7 @@ func handshake(
|
|||||||
for i := 0; i < cap(errc); i++ {
|
for i := 0; i < cap(errc); i++ {
|
||||||
err := <-errc
|
err := <-errc
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NodeInfo{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,9 +11,15 @@ import (
|
|||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defaultNodeName = "host_peer"
|
||||||
|
|
||||||
|
func emptyNodeInfo() NodeInfo {
|
||||||
|
return DefaultNodeInfo{}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTransportMultiplexConnFilter(t *testing.T) {
|
func TestTransportMultiplexConnFilter(t *testing.T) {
|
||||||
mt := NewMultiplexTransport(
|
mt := NewMultiplexTransport(
|
||||||
NodeInfo{},
|
emptyNodeInfo(),
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: ed25519.GenPrivKey(),
|
PrivKey: ed25519.GenPrivKey(),
|
||||||
},
|
},
|
||||||
@@ -70,7 +76,7 @@ func TestTransportMultiplexConnFilter(t *testing.T) {
|
|||||||
|
|
||||||
func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
|
func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
|
||||||
mt := NewMultiplexTransport(
|
mt := NewMultiplexTransport(
|
||||||
NodeInfo{},
|
emptyNodeInfo(),
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: ed25519.GenPrivKey(),
|
PrivKey: ed25519.GenPrivKey(),
|
||||||
},
|
},
|
||||||
@@ -120,6 +126,7 @@ func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
|
|||||||
t.Errorf("expected ErrFilterTimeout")
|
t.Errorf("expected ErrFilterTimeout")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransportMultiplexAcceptMultiple(t *testing.T) {
|
func TestTransportMultiplexAcceptMultiple(t *testing.T) {
|
||||||
mt := testSetupMultiplexTransport(t)
|
mt := testSetupMultiplexTransport(t)
|
||||||
|
|
||||||
@@ -134,12 +141,7 @@ func TestTransportMultiplexAcceptMultiple(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
pv = ed25519.GenPrivKey()
|
pv = ed25519.GenPrivKey()
|
||||||
dialer = NewMultiplexTransport(
|
dialer = NewMultiplexTransport(
|
||||||
NodeInfo{
|
testNodeInfo(PubKeyToID(pv.PubKey()), defaultNodeName),
|
||||||
ID: PubKeyToID(pv.PubKey()),
|
|
||||||
ListenAddr: "127.0.0.1:0",
|
|
||||||
Moniker: "dialer",
|
|
||||||
Version: "1.0.0",
|
|
||||||
},
|
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: pv,
|
PrivKey: pv,
|
||||||
},
|
},
|
||||||
@@ -207,12 +209,7 @@ func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
fastNodePV = ed25519.GenPrivKey()
|
fastNodePV = ed25519.GenPrivKey()
|
||||||
fastNodeInfo = NodeInfo{
|
fastNodeInfo = testNodeInfo(PubKeyToID(fastNodePV.PubKey()), "fastnode")
|
||||||
ID: PubKeyToID(fastNodePV.PubKey()),
|
|
||||||
ListenAddr: "127.0.0.1:0",
|
|
||||||
Moniker: "fastNode",
|
|
||||||
Version: "1.0.0",
|
|
||||||
}
|
|
||||||
errc = make(chan error)
|
errc = make(chan error)
|
||||||
fastc = make(chan struct{})
|
fastc = make(chan struct{})
|
||||||
slowc = make(chan struct{})
|
slowc = make(chan struct{})
|
||||||
@@ -248,11 +245,11 @@ func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = handshake(sc, 20*time.Millisecond, NodeInfo{
|
_, err = handshake(sc, 20*time.Millisecond,
|
||||||
ID: PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
testNodeInfo(
|
||||||
ListenAddr: "127.0.0.1:0",
|
PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
||||||
Moniker: "slow_peer",
|
"slow_peer",
|
||||||
})
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errc <- err
|
errc <- err
|
||||||
return
|
return
|
||||||
@@ -311,12 +308,7 @@ func TestTransportMultiplexValidateNodeInfo(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
pv = ed25519.GenPrivKey()
|
pv = ed25519.GenPrivKey()
|
||||||
dialer = NewMultiplexTransport(
|
dialer = NewMultiplexTransport(
|
||||||
NodeInfo{
|
testNodeInfo(PubKeyToID(pv.PubKey()), ""), // Should not be empty
|
||||||
ID: PubKeyToID(pv.PubKey()),
|
|
||||||
ListenAddr: "127.0.0.1:0",
|
|
||||||
Moniker: "", // Should not be empty.
|
|
||||||
Version: "1.0.0",
|
|
||||||
},
|
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: pv,
|
PrivKey: pv,
|
||||||
},
|
},
|
||||||
@@ -359,12 +351,9 @@ func TestTransportMultiplexRejectMissmatchID(t *testing.T) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
dialer := NewMultiplexTransport(
|
dialer := NewMultiplexTransport(
|
||||||
NodeInfo{
|
testNodeInfo(
|
||||||
ID: PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
PubKeyToID(ed25519.GenPrivKey().PubKey()), "dialer",
|
||||||
ListenAddr: "127.0.0.1:0",
|
),
|
||||||
Moniker: "dialer",
|
|
||||||
Version: "1.0.0",
|
|
||||||
},
|
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: ed25519.GenPrivKey(),
|
PrivKey: ed25519.GenPrivKey(),
|
||||||
},
|
},
|
||||||
@@ -408,12 +397,7 @@ func TestTransportMultiplexRejectIncompatible(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
pv = ed25519.GenPrivKey()
|
pv = ed25519.GenPrivKey()
|
||||||
dialer = NewMultiplexTransport(
|
dialer = NewMultiplexTransport(
|
||||||
NodeInfo{
|
testNodeInfoWithNetwork(PubKeyToID(pv.PubKey()), "dialer", "incompatible-network"),
|
||||||
ID: PubKeyToID(pv.PubKey()),
|
|
||||||
ListenAddr: "127.0.0.1:0",
|
|
||||||
Moniker: "dialer",
|
|
||||||
Version: "2.0.0",
|
|
||||||
},
|
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: pv,
|
PrivKey: pv,
|
||||||
},
|
},
|
||||||
@@ -521,9 +505,7 @@ func TestTransportHandshake(t *testing.T) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
peerPV = ed25519.GenPrivKey()
|
peerPV = ed25519.GenPrivKey()
|
||||||
peerNodeInfo = NodeInfo{
|
peerNodeInfo = testNodeInfo(PubKeyToID(peerPV.PubKey()), defaultNodeName)
|
||||||
ID: PubKeyToID(peerPV.PubKey()),
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -534,13 +516,13 @@ func TestTransportHandshake(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func(c net.Conn) {
|
go func(c net.Conn) {
|
||||||
_, err := cdc.MarshalBinaryWriter(c, peerNodeInfo)
|
_, err := cdc.MarshalBinaryWriter(c, peerNodeInfo.(DefaultNodeInfo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}(c)
|
}(c)
|
||||||
go func(c net.Conn) {
|
go func(c net.Conn) {
|
||||||
ni := NodeInfo{}
|
var ni DefaultNodeInfo
|
||||||
|
|
||||||
_, err := cdc.UnmarshalBinaryReader(
|
_, err := cdc.UnmarshalBinaryReader(
|
||||||
c,
|
c,
|
||||||
@@ -558,7 +540,7 @@ func TestTransportHandshake(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ni, err := handshake(c, 20*time.Millisecond, NodeInfo{})
|
ni, err := handshake(c, 20*time.Millisecond, emptyNodeInfo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -572,12 +554,9 @@ func testSetupMultiplexTransport(t *testing.T) *MultiplexTransport {
|
|||||||
var (
|
var (
|
||||||
pv = ed25519.GenPrivKey()
|
pv = ed25519.GenPrivKey()
|
||||||
mt = NewMultiplexTransport(
|
mt = NewMultiplexTransport(
|
||||||
NodeInfo{
|
testNodeInfo(
|
||||||
ID: PubKeyToID(pv.PubKey()),
|
PubKeyToID(pv.PubKey()), "transport",
|
||||||
ListenAddr: "127.0.0.1:0",
|
),
|
||||||
Moniker: "transport",
|
|
||||||
Version: "1.0.0",
|
|
||||||
},
|
|
||||||
NodeKey{
|
NodeKey{
|
||||||
PrivKey: pv,
|
PrivKey: pv,
|
||||||
},
|
},
|
||||||
|
@@ -25,9 +25,9 @@ const (
|
|||||||
|
|
||||||
func voteToStep(vote *types.Vote) int8 {
|
func voteToStep(vote *types.Vote) int8 {
|
||||||
switch vote.Type {
|
switch vote.Type {
|
||||||
case types.VoteTypePrevote:
|
case types.PrevoteType:
|
||||||
return stepPrevote
|
return stepPrevote
|
||||||
case types.VoteTypePrecommit:
|
case types.PrecommitType:
|
||||||
return stepPrecommit
|
return stepPrecommit
|
||||||
default:
|
default:
|
||||||
cmn.PanicSanity("Unknown vote type")
|
cmn.PanicSanity("Unknown vote type")
|
||||||
|
@@ -101,7 +101,7 @@ func TestSignVote(t *testing.T) {
|
|||||||
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
||||||
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}}
|
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}}
|
||||||
height, round := int64(10), 1
|
height, round := int64(10), 1
|
||||||
voteType := types.VoteTypePrevote
|
voteType := byte(types.PrevoteType)
|
||||||
|
|
||||||
// sign a vote for first time
|
// sign a vote for first time
|
||||||
vote := newVote(privVal.Address, 0, height, round, voteType, block1)
|
vote := newVote(privVal.Address, 0, height, round, voteType, block1)
|
||||||
@@ -206,7 +206,7 @@ func TestDifferByTimestamp(t *testing.T) {
|
|||||||
|
|
||||||
// test vote
|
// test vote
|
||||||
{
|
{
|
||||||
voteType := types.VoteTypePrevote
|
voteType := byte(types.PrevoteType)
|
||||||
blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
||||||
vote := newVote(privVal.Address, 0, height, round, voteType, blockID)
|
vote := newVote(privVal.Address, 0, height, round, voteType, blockID)
|
||||||
err := privVal.SignVote("mychainid", vote)
|
err := privVal.SignVote("mychainid", vote)
|
||||||
@@ -235,7 +235,7 @@ func newVote(addr types.Address, idx int, height int64, round int, typ byte, blo
|
|||||||
ValidatorIndex: idx,
|
ValidatorIndex: idx,
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Type: typ,
|
Type: types.SignedMsgType(typ),
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
BlockID: blockID,
|
BlockID: blockID,
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ func TestSocketPVVote(t *testing.T) {
|
|||||||
sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
|
sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
|
||||||
|
|
||||||
ts = time.Now()
|
ts = time.Now()
|
||||||
vType = types.VoteTypePrecommit
|
vType = types.PrecommitType
|
||||||
want = &types.Vote{Timestamp: ts, Type: vType}
|
want = &types.Vote{Timestamp: ts, Type: vType}
|
||||||
have = &types.Vote{Timestamp: ts, Type: vType}
|
have = &types.Vote{Timestamp: ts, Type: vType}
|
||||||
)
|
)
|
||||||
@@ -237,7 +237,7 @@ func TestRemoteSignVoteErrors(t *testing.T) {
|
|||||||
sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV())
|
sc, rs = testSetupSocketPair(t, chainID, types.NewErroringMockPV())
|
||||||
|
|
||||||
ts = time.Now()
|
ts = time.Now()
|
||||||
vType = types.VoteTypePrecommit
|
vType = types.PrecommitType
|
||||||
vote = &types.Vote{Timestamp: ts, Type: vType}
|
vote = &types.Vote{Timestamp: ts, Type: vType}
|
||||||
)
|
)
|
||||||
defer sc.Stop()
|
defer sc.Stop()
|
||||||
|
@@ -2,7 +2,6 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
cm "github.com/tendermint/tendermint/consensus"
|
cm "github.com/tendermint/tendermint/consensus"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
@@ -201,7 +200,7 @@ func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
|
|||||||
}
|
}
|
||||||
peerStates[i] = ctypes.PeerStateInfo{
|
peerStates[i] = ctypes.PeerStateInfo{
|
||||||
// Peer basic info.
|
// Peer basic info.
|
||||||
NodeAddress: p2p.IDAddressString(peer.ID(), peer.NodeInfo().ListenAddr),
|
NodeAddress: peer.NodeInfo().NetAddress().String(),
|
||||||
// Peer consensus state.
|
// Peer consensus state.
|
||||||
PeerState: peerStateJSON,
|
PeerState: peerStateJSON,
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/tendermint/tendermint/p2p"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,8 +40,12 @@ import (
|
|||||||
func NetInfo() (*ctypes.ResultNetInfo, error) {
|
func NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||||
peers := []ctypes.Peer{}
|
peers := []ctypes.Peer{}
|
||||||
for _, peer := range p2pPeers.Peers().List() {
|
for _, peer := range p2pPeers.Peers().List() {
|
||||||
|
nodeInfo, ok := peer.NodeInfo().(p2p.DefaultNodeInfo)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("peer.NodeInfo() is not DefaultNodeInfo")
|
||||||
|
}
|
||||||
peers = append(peers, ctypes.Peer{
|
peers = append(peers, ctypes.Peer{
|
||||||
NodeInfo: peer.NodeInfo(),
|
NodeInfo: nodeInfo,
|
||||||
IsOutbound: peer.IsOutbound(),
|
IsOutbound: peer.IsOutbound(),
|
||||||
ConnectionStatus: peer.Status(),
|
ConnectionStatus: peer.Status(),
|
||||||
})
|
})
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
"github.com/tendermint/tendermint/p2p"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
sm "github.com/tendermint/tendermint/state"
|
sm "github.com/tendermint/tendermint/state"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
@@ -91,7 +92,7 @@ func Status() (*ctypes.ResultStatus, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &ctypes.ResultStatus{
|
result := &ctypes.ResultStatus{
|
||||||
NodeInfo: p2pTransport.NodeInfo(),
|
NodeInfo: p2pTransport.NodeInfo().(p2p.DefaultNodeInfo),
|
||||||
SyncInfo: ctypes.SyncInfo{
|
SyncInfo: ctypes.SyncInfo{
|
||||||
LatestBlockHash: latestBlockHash,
|
LatestBlockHash: latestBlockHash,
|
||||||
LatestAppHash: latestAppHash,
|
LatestAppHash: latestAppHash,
|
||||||
|
@@ -74,7 +74,7 @@ type ValidatorInfo struct {
|
|||||||
|
|
||||||
// Node Status
|
// Node Status
|
||||||
type ResultStatus struct {
|
type ResultStatus struct {
|
||||||
NodeInfo p2p.NodeInfo `json:"node_info"`
|
NodeInfo p2p.DefaultNodeInfo `json:"node_info"`
|
||||||
SyncInfo SyncInfo `json:"sync_info"`
|
SyncInfo SyncInfo `json:"sync_info"`
|
||||||
ValidatorInfo ValidatorInfo `json:"validator_info"`
|
ValidatorInfo ValidatorInfo `json:"validator_info"`
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ type ResultDialPeers struct {
|
|||||||
|
|
||||||
// A peer
|
// A peer
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
p2p.NodeInfo `json:"node_info"`
|
NodeInfo p2p.DefaultNodeInfo `json:"node_info"`
|
||||||
IsOutbound bool `json:"is_outbound"`
|
IsOutbound bool `json:"is_outbound"`
|
||||||
ConnectionStatus p2p.ConnectionStatus `json:"connection_status"`
|
ConnectionStatus p2p.ConnectionStatus `json:"connection_status"`
|
||||||
}
|
}
|
||||||
|
@@ -15,17 +15,17 @@ func TestStatusIndexer(t *testing.T) {
|
|||||||
status = &ResultStatus{}
|
status = &ResultStatus{}
|
||||||
assert.False(t, status.TxIndexEnabled())
|
assert.False(t, status.TxIndexEnabled())
|
||||||
|
|
||||||
status.NodeInfo = p2p.NodeInfo{}
|
status.NodeInfo = p2p.DefaultNodeInfo{}
|
||||||
assert.False(t, status.TxIndexEnabled())
|
assert.False(t, status.TxIndexEnabled())
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
expected bool
|
expected bool
|
||||||
other p2p.NodeInfoOther
|
other p2p.DefaultNodeInfoOther
|
||||||
}{
|
}{
|
||||||
{false, p2p.NodeInfoOther{}},
|
{false, p2p.DefaultNodeInfoOther{}},
|
||||||
{false, p2p.NodeInfoOther{TxIndex: "aa"}},
|
{false, p2p.DefaultNodeInfoOther{TxIndex: "aa"}},
|
||||||
{false, p2p.NodeInfoOther{TxIndex: "off"}},
|
{false, p2p.DefaultNodeInfoOther{TxIndex: "off"}},
|
||||||
{true, p2p.NodeInfoOther{TxIndex: "on"}},
|
{true, p2p.DefaultNodeInfoOther{TxIndex: "on"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
@@ -95,7 +95,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
|||||||
startTime := time.Now().UnixNano()
|
startTime := time.Now().UnixNano()
|
||||||
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db)
|
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db)
|
||||||
endTime := time.Now().UnixNano()
|
endTime := time.Now().UnixNano()
|
||||||
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime - startTime) / 1000000)
|
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state, ErrProxyAppConn(err)
|
return state, ErrProxyAppConn(err)
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,7 @@ func TestBeginBlockValidators(t *testing.T) {
|
|||||||
prevBlockID := types.BlockID{prevHash, prevParts}
|
prevBlockID := types.BlockID{prevHash, prevParts}
|
||||||
|
|
||||||
now := tmtime.Now()
|
now := tmtime.Now()
|
||||||
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.PrecommitType}
|
||||||
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@@ -135,7 +135,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
|||||||
types.TM2PB.Evidence(ev2, valSet, now)}},
|
types.TM2PB.Evidence(ev2, valSet, now)}},
|
||||||
}
|
}
|
||||||
|
|
||||||
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}
|
vote0 := &types.Vote{ValidatorIndex: 0, Timestamp: now, Type: types.PrecommitType}
|
||||||
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
vote1 := &types.Vote{ValidatorIndex: 1, Timestamp: now}
|
||||||
votes := []*types.Vote{vote0, vote1}
|
votes := []*types.Vote{vote0, vote1}
|
||||||
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
|
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
|
||||||
|
@@ -2,9 +2,9 @@ package state
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-kit/kit/metrics"
|
"github.com/go-kit/kit/metrics"
|
||||||
|
"github.com/go-kit/kit/metrics/discard"
|
||||||
"github.com/go-kit/kit/metrics/prometheus"
|
"github.com/go-kit/kit/metrics/prometheus"
|
||||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/go-kit/kit/metrics/discard"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const MetricsSubsystem = "state"
|
const MetricsSubsystem = "state"
|
||||||
|
@@ -388,7 +388,7 @@ func (commit *Commit) FirstPrecommit() *Vote {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &Vote{
|
return &Vote{
|
||||||
Type: VoteTypePrecommit,
|
Type: PrecommitType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ func (commit *Commit) Round() int {
|
|||||||
|
|
||||||
// Type returns the vote type of the commit, which is always VoteTypePrecommit
|
// Type returns the vote type of the commit, which is always VoteTypePrecommit
|
||||||
func (commit *Commit) Type() byte {
|
func (commit *Commit) Type() byte {
|
||||||
return VoteTypePrecommit
|
return byte(PrecommitType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the number of votes in the commit
|
// Size returns the number of votes in the commit
|
||||||
@@ -462,7 +462,7 @@ func (commit *Commit) ValidateBasic() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Ensure that all votes are precommits.
|
// Ensure that all votes are precommits.
|
||||||
if precommit.Type != VoteTypePrecommit {
|
if precommit.Type != PrecommitType {
|
||||||
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
|
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
|
||||||
precommit.Type)
|
precommit.Type)
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ func TestBlockAddEvidence(t *testing.T) {
|
|||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
|
|
||||||
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ func TestBlockValidateBasic(t *testing.T) {
|
|||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
|
|
||||||
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) {
|
|||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
|
|
||||||
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ func TestBlockHashesTo(t *testing.T) {
|
|||||||
|
|
||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, valSet, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -190,14 +190,14 @@ func TestNilDataHashDoesntCrash(t *testing.T) {
|
|||||||
func TestCommit(t *testing.T) {
|
func TestCommit(t *testing.T) {
|
||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, _, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.NotNil(t, commit.FirstPrecommit())
|
assert.NotNil(t, commit.FirstPrecommit())
|
||||||
assert.Equal(t, h-1, commit.Height())
|
assert.Equal(t, h-1, commit.Height())
|
||||||
assert.Equal(t, 1, commit.Round())
|
assert.Equal(t, 1, commit.Round())
|
||||||
assert.Equal(t, VoteTypePrecommit, commit.Type())
|
assert.Equal(t, PrecommitType, SignedMsgType(commit.Type()))
|
||||||
if commit.Size() <= 0 {
|
if commit.Size() <= 0 {
|
||||||
t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size())
|
t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size())
|
||||||
}
|
}
|
||||||
@@ -218,7 +218,7 @@ func TestCommitValidateBasic(t *testing.T) {
|
|||||||
{"Random Commit", func(com *Commit) {}, false},
|
{"Random Commit", func(com *Commit) {}, false},
|
||||||
{"Nil precommit", func(com *Commit) { com.Precommits[0] = nil }, false},
|
{"Nil precommit", func(com *Commit) { com.Precommits[0] = nil }, false},
|
||||||
{"Incorrect signature", func(com *Commit) { com.Precommits[0].Signature = []byte{0} }, false},
|
{"Incorrect signature", func(com *Commit) { com.Precommits[0].Signature = []byte{0} }, false},
|
||||||
{"Incorrect type", func(com *Commit) { com.Precommits[0].Type = VoteTypePrevote }, true},
|
{"Incorrect type", func(com *Commit) { com.Precommits[0].Type = PrevoteType }, true},
|
||||||
{"Incorrect height", func(com *Commit) { com.Precommits[0].Height = int64(100) }, true},
|
{"Incorrect height", func(com *Commit) { com.Precommits[0].Height = int64(100) }, true},
|
||||||
{"Incorrect round", func(com *Commit) { com.Precommits[0].Round = 100 }, true},
|
{"Incorrect round", func(com *Commit) { com.Precommits[0].Round = 100 }, true},
|
||||||
}
|
}
|
||||||
@@ -268,7 +268,7 @@ func TestMaxHeaderBytes(t *testing.T) {
|
|||||||
func randCommit() *Commit {
|
func randCommit() *Commit {
|
||||||
lastID := makeBlockIDRandom()
|
lastID := makeBlockIDRandom()
|
||||||
h := int64(3)
|
h := int64(3)
|
||||||
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
voteSet, _, vals := randVoteSet(h-1, 1, PrecommitType, 10, 1)
|
||||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@@ -13,44 +13,46 @@ import (
|
|||||||
const TimeFormat = time.RFC3339Nano
|
const TimeFormat = time.RFC3339Nano
|
||||||
|
|
||||||
type CanonicalBlockID struct {
|
type CanonicalBlockID struct {
|
||||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
Hash cmn.HexBytes
|
||||||
PartsHeader CanonicalPartSetHeader `json:"parts,omitempty"`
|
PartsHeader CanonicalPartSetHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
type CanonicalPartSetHeader struct {
|
type CanonicalPartSetHeader struct {
|
||||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
Hash cmn.HexBytes
|
||||||
Total int `json:"total,omitempty"`
|
Total int
|
||||||
}
|
}
|
||||||
|
|
||||||
type CanonicalProposal struct {
|
type CanonicalProposal struct {
|
||||||
ChainID string `json:"@chain_id"`
|
Version uint64 `binary:"fixed64"`
|
||||||
Type string `json:"@type"`
|
Height int64 `binary:"fixed64"`
|
||||||
BlockPartsHeader CanonicalPartSetHeader `json:"block_parts_header"`
|
Round int64 `binary:"fixed64"`
|
||||||
Height int64 `json:"height"`
|
Type SignedMsgType // type alias for byte
|
||||||
POLBlockID CanonicalBlockID `json:"pol_block_id"`
|
POLRound int64 `binary:"fixed64"`
|
||||||
POLRound int `json:"pol_round"`
|
Timestamp time.Time
|
||||||
Round int `json:"round"`
|
BlockPartsHeader CanonicalPartSetHeader
|
||||||
Timestamp time.Time `json:"timestamp"`
|
POLBlockID CanonicalBlockID
|
||||||
|
ChainID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CanonicalVote struct {
|
type CanonicalVote struct {
|
||||||
ChainID string `json:"@chain_id"`
|
Version uint64 `binary:"fixed64"`
|
||||||
Type string `json:"@type"`
|
Height int64 `binary:"fixed64"`
|
||||||
BlockID CanonicalBlockID `json:"block_id"`
|
Round int64 `binary:"fixed64"`
|
||||||
Height int64 `json:"height"`
|
Type SignedMsgType // type alias for byte
|
||||||
Round int `json:"round"`
|
Timestamp time.Time
|
||||||
Timestamp time.Time `json:"timestamp"`
|
BlockID CanonicalBlockID
|
||||||
VoteType byte `json:"type"`
|
ChainID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type CanonicalHeartbeat struct {
|
type CanonicalHeartbeat struct {
|
||||||
ChainID string `json:"@chain_id"`
|
Version uint64 `binary:"fixed64"`
|
||||||
Type string `json:"@type"`
|
Height int64 `binary:"fixed64"`
|
||||||
Height int64 `json:"height"`
|
Round int `binary:"fixed64"`
|
||||||
Round int `json:"round"`
|
Type byte
|
||||||
Sequence int `json:"sequence"`
|
Sequence int `binary:"fixed64"`
|
||||||
ValidatorAddress Address `json:"validator_address"`
|
ValidatorAddress Address
|
||||||
ValidatorIndex int `json:"validator_index"`
|
ValidatorIndex int
|
||||||
|
ChainID string
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
@@ -72,38 +74,40 @@ func CanonicalizePartSetHeader(psh PartSetHeader) CanonicalPartSetHeader {
|
|||||||
|
|
||||||
func CanonicalizeProposal(chainID string, proposal *Proposal) CanonicalProposal {
|
func CanonicalizeProposal(chainID string, proposal *Proposal) CanonicalProposal {
|
||||||
return CanonicalProposal{
|
return CanonicalProposal{
|
||||||
ChainID: chainID,
|
Version: 0, // TODO
|
||||||
Type: "proposal",
|
|
||||||
BlockPartsHeader: CanonicalizePartSetHeader(proposal.BlockPartsHeader),
|
|
||||||
Height: proposal.Height,
|
Height: proposal.Height,
|
||||||
|
Round: int64(proposal.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int)
|
||||||
|
Type: ProposalType,
|
||||||
|
POLRound: int64(proposal.POLRound),
|
||||||
Timestamp: proposal.Timestamp,
|
Timestamp: proposal.Timestamp,
|
||||||
|
BlockPartsHeader: CanonicalizePartSetHeader(proposal.BlockPartsHeader),
|
||||||
POLBlockID: CanonicalizeBlockID(proposal.POLBlockID),
|
POLBlockID: CanonicalizeBlockID(proposal.POLBlockID),
|
||||||
POLRound: proposal.POLRound,
|
ChainID: chainID,
|
||||||
Round: proposal.Round,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote {
|
func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote {
|
||||||
return CanonicalVote{
|
return CanonicalVote{
|
||||||
ChainID: chainID,
|
Version: 0, // TODO
|
||||||
Type: "vote",
|
|
||||||
BlockID: CanonicalizeBlockID(vote.BlockID),
|
|
||||||
Height: vote.Height,
|
Height: vote.Height,
|
||||||
Round: vote.Round,
|
Round: int64(vote.Round), // cast int->int64 to make amino encode it fixed64 (does not work for int)
|
||||||
|
Type: vote.Type,
|
||||||
Timestamp: vote.Timestamp,
|
Timestamp: vote.Timestamp,
|
||||||
VoteType: vote.Type,
|
BlockID: CanonicalizeBlockID(vote.BlockID),
|
||||||
|
ChainID: chainID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CanonicalizeHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalHeartbeat {
|
func CanonicalizeHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalHeartbeat {
|
||||||
return CanonicalHeartbeat{
|
return CanonicalHeartbeat{
|
||||||
ChainID: chainID,
|
Version: 0, // TODO
|
||||||
Type: "heartbeat",
|
|
||||||
Height: heartbeat.Height,
|
Height: heartbeat.Height,
|
||||||
Round: heartbeat.Round,
|
Round: heartbeat.Round,
|
||||||
|
Type: byte(HeartbeatType),
|
||||||
Sequence: heartbeat.Sequence,
|
Sequence: heartbeat.Sequence,
|
||||||
ValidatorAddress: heartbeat.ValidatorAddress,
|
ValidatorAddress: heartbeat.ValidatorAddress,
|
||||||
ValidatorIndex: heartbeat.ValidatorIndex,
|
ValidatorIndex: heartbeat.ValidatorIndex,
|
||||||
|
ChainID: chainID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ func makeVote(val PrivValidator, chainID string, valIndex int, height int64, rou
|
|||||||
ValidatorIndex: valIndex,
|
ValidatorIndex: valIndex,
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Type: byte(step),
|
Type: SignedMsgType(step),
|
||||||
BlockID: blockID,
|
BlockID: blockID,
|
||||||
}
|
}
|
||||||
err := val.SignVote(chainID, v)
|
err := val.SignVote(chainID, v)
|
||||||
|
27
types/signed_msg_type.go
Normal file
27
types/signed_msg_type.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
// SignedMsgType is a type of signed message in the consensus.
|
||||||
|
type SignedMsgType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Votes
|
||||||
|
PrevoteType SignedMsgType = 0x01
|
||||||
|
PrecommitType SignedMsgType = 0x02
|
||||||
|
|
||||||
|
// Proposals
|
||||||
|
ProposalType SignedMsgType = 0x20
|
||||||
|
|
||||||
|
// Heartbeat
|
||||||
|
HeartbeatType SignedMsgType = 0x30
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsVoteTypeValid(type_ SignedMsgType) bool {
|
||||||
|
switch type_ {
|
||||||
|
case PrevoteType:
|
||||||
|
return true
|
||||||
|
case PrecommitType:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@@ -16,7 +16,7 @@ func MakeCommit(blockID BlockID, height int64, round int,
|
|||||||
ValidatorIndex: i,
|
ValidatorIndex: i,
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Type: VoteTypePrecommit,
|
Type: PrecommitType,
|
||||||
BlockID: blockID,
|
BlockID: blockID,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
}
|
}
|
||||||
|
@@ -282,7 +282,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
|
|||||||
if precommit.Round != round {
|
if precommit.Round != round {
|
||||||
return fmt.Errorf("Invalid commit -- wrong round: want %v got %v", round, precommit.Round)
|
return fmt.Errorf("Invalid commit -- wrong round: want %v got %v", round, precommit.Round)
|
||||||
}
|
}
|
||||||
if precommit.Type != VoteTypePrecommit {
|
if precommit.Type != PrecommitType {
|
||||||
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
|
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
|
||||||
}
|
}
|
||||||
_, val := vals.GetByIndex(idx)
|
_, val := vals.GetByIndex(idx)
|
||||||
@@ -361,7 +361,7 @@ func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID strin
|
|||||||
if precommit.Round != round {
|
if precommit.Round != round {
|
||||||
return cmn.NewError("Invalid commit -- wrong round: %v vs %v", round, precommit.Round)
|
return cmn.NewError("Invalid commit -- wrong round: %v vs %v", round, precommit.Round)
|
||||||
}
|
}
|
||||||
if precommit.Type != VoteTypePrecommit {
|
if precommit.Type != PrecommitType {
|
||||||
return cmn.NewError("Invalid commit -- not precommit @ index %v", idx)
|
return cmn.NewError("Invalid commit -- not precommit @ index %v", idx)
|
||||||
}
|
}
|
||||||
// See if this validator is in oldVals.
|
// See if this validator is in oldVals.
|
||||||
|
@@ -385,7 +385,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) {
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: 0,
|
Round: 0,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrecommit,
|
Type: PrecommitType,
|
||||||
BlockID: blockID,
|
BlockID: blockID,
|
||||||
}
|
}
|
||||||
sig, err := privKey.Sign(vote.SignBytes(chainID))
|
sig, err := privKey.Sign(vote.SignBytes(chainID))
|
||||||
|
@@ -43,24 +43,6 @@ func NewConflictingVoteError(val *Validator, voteA, voteB *Vote) *ErrVoteConflic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types of votes
|
|
||||||
// TODO Make a new type "VoteType"
|
|
||||||
const (
|
|
||||||
VoteTypePrevote = byte(0x01)
|
|
||||||
VoteTypePrecommit = byte(0x02)
|
|
||||||
)
|
|
||||||
|
|
||||||
func IsVoteTypeValid(type_ byte) bool {
|
|
||||||
switch type_ {
|
|
||||||
case VoteTypePrevote:
|
|
||||||
return true
|
|
||||||
case VoteTypePrecommit:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Address is hex bytes.
|
// Address is hex bytes.
|
||||||
type Address = crypto.Address
|
type Address = crypto.Address
|
||||||
|
|
||||||
@@ -71,7 +53,7 @@ type Vote struct {
|
|||||||
Height int64 `json:"height"`
|
Height int64 `json:"height"`
|
||||||
Round int `json:"round"`
|
Round int `json:"round"`
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
Type byte `json:"type"`
|
Type SignedMsgType `json:"type"`
|
||||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||||
Signature []byte `json:"signature"`
|
Signature []byte `json:"signature"`
|
||||||
}
|
}
|
||||||
@@ -95,9 +77,9 @@ func (vote *Vote) String() string {
|
|||||||
}
|
}
|
||||||
var typeString string
|
var typeString string
|
||||||
switch vote.Type {
|
switch vote.Type {
|
||||||
case VoteTypePrevote:
|
case PrevoteType:
|
||||||
typeString = "Prevote"
|
typeString = "Prevote"
|
||||||
case VoteTypePrecommit:
|
case PrecommitType:
|
||||||
typeString = "Precommit"
|
typeString = "Precommit"
|
||||||
default:
|
default:
|
||||||
cmn.PanicSanity("Unknown vote type")
|
cmn.PanicSanity("Unknown vote type")
|
||||||
|
@@ -55,7 +55,7 @@ type VoteSet struct {
|
|||||||
chainID string
|
chainID string
|
||||||
height int64
|
height int64
|
||||||
round int
|
round int
|
||||||
type_ byte
|
type_ SignedMsgType
|
||||||
valSet *ValidatorSet
|
valSet *ValidatorSet
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
@@ -68,7 +68,7 @@ type VoteSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a new VoteSet struct used to accumulate votes for given height/round.
|
// Constructs a new VoteSet struct used to accumulate votes for given height/round.
|
||||||
func NewVoteSet(chainID string, height int64, round int, type_ byte, valSet *ValidatorSet) *VoteSet {
|
func NewVoteSet(chainID string, height int64, round int, type_ SignedMsgType, valSet *ValidatorSet) *VoteSet {
|
||||||
if height == 0 {
|
if height == 0 {
|
||||||
cmn.PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
|
cmn.PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ func (voteSet *VoteSet) Type() byte {
|
|||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return 0x00
|
return 0x00
|
||||||
}
|
}
|
||||||
return voteSet.type_
|
return byte(voteSet.type_)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) Size() int {
|
func (voteSet *VoteSet) Size() int {
|
||||||
@@ -381,7 +381,7 @@ func (voteSet *VoteSet) IsCommit() bool {
|
|||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if voteSet.type_ != VoteTypePrecommit {
|
if voteSet.type_ != PrecommitType {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
@@ -529,8 +529,8 @@ func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
|
|||||||
// Commit
|
// Commit
|
||||||
|
|
||||||
func (voteSet *VoteSet) MakeCommit() *Commit {
|
func (voteSet *VoteSet) MakeCommit() *Commit {
|
||||||
if voteSet.type_ != VoteTypePrecommit {
|
if voteSet.type_ != PrecommitType {
|
||||||
cmn.PanicSanity("Cannot MakeCommit() unless VoteSet.Type is VoteTypePrecommit")
|
cmn.PanicSanity("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
|
||||||
}
|
}
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
defer voteSet.mtx.Unlock()
|
defer voteSet.mtx.Unlock()
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: privValidators are in order
|
// NOTE: privValidators are in order
|
||||||
func randVoteSet(height int64, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []PrivValidator) {
|
func randVoteSet(height int64, round int, type_ SignedMsgType, numValidators int, votingPower int64) (*VoteSet, *ValidatorSet, []PrivValidator) {
|
||||||
valSet, privValidators := RandValidatorSet(numValidators, votingPower)
|
valSet, privValidators := RandValidatorSet(numValidators, votingPower)
|
||||||
return NewVoteSet("test_chain_id", height, round, type_, valSet), valSet, privValidators
|
return NewVoteSet("test_chain_id", height, round, type_, valSet), valSet, privValidators
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ func withRound(vote *Vote, round int) *Vote {
|
|||||||
// Convenience: Return new vote with different type
|
// Convenience: Return new vote with different type
|
||||||
func withType(vote *Vote, type_ byte) *Vote {
|
func withType(vote *Vote, type_ byte) *Vote {
|
||||||
vote = vote.Copy()
|
vote = vote.Copy()
|
||||||
vote.Type = type_
|
vote.Type = SignedMsgType(type_)
|
||||||
return vote
|
return vote
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
|
|||||||
|
|
||||||
func TestAddVote(t *testing.T) {
|
func TestAddVote(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||||
val0 := privValidators[0]
|
val0 := privValidators[0]
|
||||||
|
|
||||||
// t.Logf(">> %v", voteSet)
|
// t.Logf(">> %v", voteSet)
|
||||||
@@ -82,7 +82,7 @@ func TestAddVote(t *testing.T) {
|
|||||||
ValidatorIndex: 0, // since privValidators are in order
|
ValidatorIndex: 0, // since privValidators are in order
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
BlockID: BlockID{nil, PartSetHeader{}},
|
BlockID: BlockID{nil, PartSetHeader{}},
|
||||||
}
|
}
|
||||||
@@ -105,14 +105,14 @@ func TestAddVote(t *testing.T) {
|
|||||||
|
|
||||||
func Test2_3Majority(t *testing.T) {
|
func Test2_3Majority(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||||
|
|
||||||
voteProto := &Vote{
|
voteProto := &Vote{
|
||||||
ValidatorAddress: nil, // NOTE: must fill in
|
ValidatorAddress: nil, // NOTE: must fill in
|
||||||
ValidatorIndex: -1, // NOTE: must fill in
|
ValidatorIndex: -1, // NOTE: must fill in
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
BlockID: BlockID{nil, PartSetHeader{}},
|
BlockID: BlockID{nil, PartSetHeader{}},
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ func Test2_3Majority(t *testing.T) {
|
|||||||
|
|
||||||
func Test2_3MajorityRedux(t *testing.T) {
|
func Test2_3MajorityRedux(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 100, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 100, 1)
|
||||||
|
|
||||||
blockHash := crypto.CRandBytes(32)
|
blockHash := crypto.CRandBytes(32)
|
||||||
blockPartsTotal := 123
|
blockPartsTotal := 123
|
||||||
@@ -170,7 +170,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
BlockID: BlockID{blockHash, blockPartsHeader},
|
BlockID: BlockID{blockHash, blockPartsHeader},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
|||||||
|
|
||||||
func TestBadVotes(t *testing.T) {
|
func TestBadVotes(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||||
|
|
||||||
voteProto := &Vote{
|
voteProto := &Vote{
|
||||||
ValidatorAddress: nil,
|
ValidatorAddress: nil,
|
||||||
@@ -265,7 +265,7 @@ func TestBadVotes(t *testing.T) {
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
BlockID: BlockID{nil, PartSetHeader{}},
|
BlockID: BlockID{nil, PartSetHeader{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +308,7 @@ func TestBadVotes(t *testing.T) {
|
|||||||
// val3 votes of another type.
|
// val3 votes of another type.
|
||||||
{
|
{
|
||||||
vote := withValidator(voteProto, privValidators[3].GetAddress(), 3)
|
vote := withValidator(voteProto, privValidators[3].GetAddress(), 3)
|
||||||
added, err := signAddVote(privValidators[3], withType(vote, VoteTypePrecommit), voteSet)
|
added, err := signAddVote(privValidators[3], withType(vote, byte(PrecommitType)), voteSet)
|
||||||
if added || err == nil {
|
if added || err == nil {
|
||||||
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
||||||
}
|
}
|
||||||
@@ -317,7 +317,7 @@ func TestBadVotes(t *testing.T) {
|
|||||||
|
|
||||||
func TestConflicts(t *testing.T) {
|
func TestConflicts(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 4, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 4, 1)
|
||||||
blockHash1 := cmn.RandBytes(32)
|
blockHash1 := cmn.RandBytes(32)
|
||||||
blockHash2 := cmn.RandBytes(32)
|
blockHash2 := cmn.RandBytes(32)
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ func TestConflicts(t *testing.T) {
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
BlockID: BlockID{nil, PartSetHeader{}},
|
BlockID: BlockID{nil, PartSetHeader{}},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,7 +447,7 @@ func TestConflicts(t *testing.T) {
|
|||||||
|
|
||||||
func TestMakeCommit(t *testing.T) {
|
func TestMakeCommit(t *testing.T) {
|
||||||
height, round := int64(1), 0
|
height, round := int64(1), 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrecommit, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, PrecommitType, 10, 1)
|
||||||
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
|
blockHash, blockPartsHeader := crypto.CRandBytes(32), PartSetHeader{123, crypto.CRandBytes(32)}
|
||||||
|
|
||||||
voteProto := &Vote{
|
voteProto := &Vote{
|
||||||
@@ -456,7 +456,7 @@ func TestMakeCommit(t *testing.T) {
|
|||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrecommit,
|
Type: PrecommitType,
|
||||||
BlockID: BlockID{blockHash, blockPartsHeader},
|
BlockID: BlockID{blockHash, blockPartsHeader},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,11 +13,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func examplePrevote() *Vote {
|
func examplePrevote() *Vote {
|
||||||
return exampleVote(VoteTypePrevote)
|
return exampleVote(byte(PrevoteType))
|
||||||
}
|
}
|
||||||
|
|
||||||
func examplePrecommit() *Vote {
|
func examplePrecommit() *Vote {
|
||||||
return exampleVote(VoteTypePrecommit)
|
return exampleVote(byte(PrecommitType))
|
||||||
}
|
}
|
||||||
|
|
||||||
func exampleVote(t byte) *Vote {
|
func exampleVote(t byte) *Vote {
|
||||||
@@ -32,7 +32,7 @@ func exampleVote(t byte) *Vote {
|
|||||||
Height: 12345,
|
Height: 12345,
|
||||||
Round: 2,
|
Round: 2,
|
||||||
Timestamp: stamp,
|
Timestamp: stamp,
|
||||||
Type: t,
|
Type: SignedMsgType(t),
|
||||||
BlockID: BlockID{
|
BlockID: BlockID{
|
||||||
Hash: tmhash.Sum([]byte("blockID_hash")),
|
Hash: tmhash.Sum([]byte("blockID_hash")),
|
||||||
PartsHeader: PartSetHeader{
|
PartsHeader: PartSetHeader{
|
||||||
@@ -53,6 +53,98 @@ func TestVoteSignable(t *testing.T) {
|
|||||||
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Vote.")
|
require.Equal(t, expected, signBytes, "Got unexpected sign bytes for Vote.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVoteSignableTestVectors(t *testing.T) {
|
||||||
|
voteWithVersion := CanonicalizeVote("", &Vote{Height: 1, Round: 1})
|
||||||
|
voteWithVersion.Version = 123
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
canonicalVote CanonicalVote
|
||||||
|
want []byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
CanonicalizeVote("", &Vote{}),
|
||||||
|
// NOTE: Height and Round are skipped here. This case needs to be considered while parsing.
|
||||||
|
[]byte{0xb, 0x2a, 0x9, 0x9, 0x0, 0x9, 0x6e, 0x88, 0xf1, 0xff, 0xff, 0xff},
|
||||||
|
},
|
||||||
|
// with proper (fixed size) height and round (PreCommit):
|
||||||
|
{
|
||||||
|
CanonicalizeVote("", &Vote{Height: 1, Round: 1, Type: PrecommitType}),
|
||||||
|
[]byte{
|
||||||
|
0x1f, // total length
|
||||||
|
0x11, // (field_number << 3) | wire_type (version is missing)
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||||
|
0x19, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||||
|
0x20, // (field_number << 3) | wire_type
|
||||||
|
0x2, // PrecommitType
|
||||||
|
0x2a, // (field_number << 3) | wire_type
|
||||||
|
// remaining fields (timestamp):
|
||||||
|
0x9, 0x9, 0x0, 0x9, 0x6e, 0x88, 0xf1, 0xff, 0xff, 0xff},
|
||||||
|
},
|
||||||
|
// with proper (fixed size) height and round (PreVote):
|
||||||
|
{
|
||||||
|
CanonicalizeVote("", &Vote{Height: 1, Round: 1, Type: PrevoteType}),
|
||||||
|
[]byte{
|
||||||
|
0x1f, // total length
|
||||||
|
0x11, // (field_number << 3) | wire_type (version is missing)
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||||
|
0x19, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||||
|
0x20, // (field_number << 3) | wire_type
|
||||||
|
0x1, // PrevoteType
|
||||||
|
0x2a, // (field_number << 3) | wire_type
|
||||||
|
// remaining fields (timestamp):
|
||||||
|
0x9, 0x9, 0x0, 0x9, 0x6e, 0x88, 0xf1, 0xff, 0xff, 0xff},
|
||||||
|
},
|
||||||
|
// containing version (empty type)
|
||||||
|
{
|
||||||
|
voteWithVersion,
|
||||||
|
[]byte{
|
||||||
|
0x26, // total length
|
||||||
|
0x9, // (field_number << 3) | wire_type
|
||||||
|
0x7b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // version (123)
|
||||||
|
0x11, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||||
|
0x19, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||||
|
// remaining fields (timestamp):
|
||||||
|
0x2a,
|
||||||
|
0x9, 0x9, 0x0, 0x9, 0x6e, 0x88, 0xf1, 0xff, 0xff, 0xff},
|
||||||
|
},
|
||||||
|
// containing non-empty chain_id:
|
||||||
|
{
|
||||||
|
CanonicalizeVote("test_chain_id", &Vote{Height: 1, Round: 1}),
|
||||||
|
[]byte{
|
||||||
|
0x2c, // total length
|
||||||
|
0x11, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
|
||||||
|
0x19, // (field_number << 3) | wire_type
|
||||||
|
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // round
|
||||||
|
// remaining fields:
|
||||||
|
0x2a, // (field_number << 3) | wire_type
|
||||||
|
0x9, 0x9, 0x0, 0x9, 0x6e, 0x88, 0xf1, 0xff, 0xff, 0xff, // timestamp
|
||||||
|
0x3a, // (field_number << 3) | wire_type
|
||||||
|
0xd, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64}, // chainID
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tc := range tests {
|
||||||
|
got, err := cdc.MarshalBinary(tc.canonicalVote)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, tc.want, got, "test case #%v: got unexpected sign bytes for Vote.", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVoteProposalNotEq(t *testing.T) {
|
||||||
|
cv := CanonicalizeVote("", &Vote{Height: 1, Round: 1})
|
||||||
|
p := CanonicalizeProposal("", &Proposal{Height: 1, Round: 1})
|
||||||
|
vb, err := cdc.MarshalBinary(cv)
|
||||||
|
require.NoError(t, err)
|
||||||
|
pb, err := cdc.MarshalBinary(p)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEqual(t, vb, pb)
|
||||||
|
}
|
||||||
|
|
||||||
func TestVoteVerifySignature(t *testing.T) {
|
func TestVoteVerifySignature(t *testing.T) {
|
||||||
privVal := NewMockPV()
|
privVal := NewMockPV()
|
||||||
pubkey := privVal.GetPubKey()
|
pubkey := privVal.GetPubKey()
|
||||||
@@ -85,12 +177,12 @@ func TestVoteVerifySignature(t *testing.T) {
|
|||||||
func TestIsVoteTypeValid(t *testing.T) {
|
func TestIsVoteTypeValid(t *testing.T) {
|
||||||
tc := []struct {
|
tc := []struct {
|
||||||
name string
|
name string
|
||||||
in byte
|
in SignedMsgType
|
||||||
out bool
|
out bool
|
||||||
}{
|
}{
|
||||||
{"Prevote", VoteTypePrevote, true},
|
{"Prevote", PrevoteType, true},
|
||||||
{"Precommit", VoteTypePrecommit, true},
|
{"Precommit", PrecommitType, true},
|
||||||
{"InvalidType", byte(3), false},
|
{"InvalidType", SignedMsgType(0x3), false},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tc {
|
for _, tt := range tc {
|
||||||
@@ -128,7 +220,7 @@ func TestMaxVoteBytes(t *testing.T) {
|
|||||||
Height: math.MaxInt64,
|
Height: math.MaxInt64,
|
||||||
Round: math.MaxInt64,
|
Round: math.MaxInt64,
|
||||||
Timestamp: tmtime.Now(),
|
Timestamp: tmtime.Now(),
|
||||||
Type: VoteTypePrevote,
|
Type: PrevoteType,
|
||||||
BlockID: BlockID{
|
BlockID: BlockID{
|
||||||
Hash: tmhash.Sum([]byte("blockID_hash")),
|
Hash: tmhash.Sum([]byte("blockID_hash")),
|
||||||
PartsHeader: PartSetHeader{
|
PartsHeader: PartSetHeader{
|
||||||
|
Reference in New Issue
Block a user