mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-16 12:51: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`.
|
||||
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
|
||||
* [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices
|
||||
* [types] \#2598 `VoteTypeXxx` are now
|
||||
|
||||
* 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
|
||||
* [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
|
||||
|
||||
@@ -37,9 +42,10 @@ FEATURES:
|
||||
- [abci] \#2557 Add `Codespace` field to `Response{CheckTx, DeliverTx, Query}`
|
||||
|
||||
IMPROVEMENTS:
|
||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169) add additional metrics
|
||||
- [config] \#2232 added ValidateBasic method, which performs basic checks
|
||||
- Additional Metrics
|
||||
- [consensus] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [p2p] [\#2169](https://github.com/cosmos/cosmos-sdk/issues/2169)
|
||||
- [config] \#2232 Added ValidateBasic method, which performs basic checks
|
||||
- [crypto/ed25519] \#2558 Switch to use latest `golang.org/x/crypto` through our fork at
|
||||
github.com/tendermint/crypto
|
||||
- [tools] \#2238 Binary dependencies are now locked to a specific git commit
|
||||
@@ -50,6 +56,8 @@ BUG FIXES:
|
||||
- [node] \#2434 Make node respond to signal interrupts while sleeping for genesis time
|
||||
- [consensus] [\#1690](https://github.com/tendermint/tendermint/issues/1690) wait for
|
||||
timeoutPrecommit before starting next round
|
||||
- [consensus] [\#1745](https://github.com/tendermint/tendermint/issues/1745) wait for
|
||||
Proposal or timeoutProposal before entering prevote
|
||||
- [evidence] \#2515 fix db iter leak (@goolAdapter)
|
||||
- [common/bit_array] Fixed a bug in the `Or` function
|
||||
- [common/bit_array] Fixed a bug in the `Sub` function (@james-ray)
|
||||
|
@@ -12,23 +12,27 @@ import (
|
||||
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) {
|
||||
b.StopTimer()
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||
status := &ctypes.ResultStatus{
|
||||
NodeInfo: p2p.NodeInfo{
|
||||
ID: nodeKey.ID(),
|
||||
Moniker: "SOMENAME",
|
||||
Network: "SOMENAME",
|
||||
ListenAddr: "SOMEADDR",
|
||||
Version: "SOMEVER",
|
||||
Other: p2p.NodeInfoOther{
|
||||
AminoVersion: "SOMESTRING",
|
||||
P2PVersion: "OTHERSTRING",
|
||||
},
|
||||
},
|
||||
NodeInfo: testNodeInfo(nodeKey.ID()),
|
||||
SyncInfo: ctypes.SyncInfo{
|
||||
LatestBlockHash: []byte("SOMEBYTES"),
|
||||
LatestBlockHeight: 123,
|
||||
@@ -56,17 +60,7 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) {
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
ID: nodeKey.ID(),
|
||||
Moniker: "SOMENAME",
|
||||
Network: "SOMENAME",
|
||||
ListenAddr: "SOMEADDR",
|
||||
Version: "SOMEVER",
|
||||
Other: p2p.NodeInfoOther{
|
||||
AminoVersion: "SOMESTRING",
|
||||
P2PVersion: "OTHERSTRING",
|
||||
},
|
||||
}
|
||||
nodeInfo := testNodeInfo(nodeKey.ID())
|
||||
b.StartTimer()
|
||||
|
||||
counter := 0
|
||||
@@ -84,17 +78,7 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
nodeKey := p2p.NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
ID: nodeKey.ID(),
|
||||
Moniker: "SOMENAME",
|
||||
Network: "SOMENAME",
|
||||
ListenAddr: "SOMEADDR",
|
||||
Version: "SOMEVER",
|
||||
Other: p2p.NodeInfoOther{
|
||||
AminoVersion: "SOMESTRING",
|
||||
P2PVersion: "OTHERSTRING",
|
||||
},
|
||||
}
|
||||
nodeInfo := testNodeInfo(nodeKey.ID())
|
||||
b.StartTimer()
|
||||
|
||||
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) 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) ID() p2p.ID { return tp.id }
|
||||
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) Set(string, interface{}) {}
|
||||
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
|
||||
func TestConsensusConfig() *ConsensusConfig {
|
||||
cfg := DefaultConsensusConfig()
|
||||
cfg.TimeoutPropose = 100 * time.Millisecond
|
||||
cfg.TimeoutPropose = 40 * time.Millisecond
|
||||
cfg.TimeoutProposeDelta = 1 * time.Millisecond
|
||||
cfg.TimeoutPrevote = 10 * time.Millisecond
|
||||
cfg.TimeoutPrevoteDelta = 1 * time.Millisecond
|
||||
|
@@ -226,8 +226,8 @@ func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.
|
||||
|
||||
// votes
|
||||
cs.mtx.Lock()
|
||||
prevote, _ := cs.signVote(types.VoteTypePrevote, blockHash, parts.Header())
|
||||
precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, parts.Header())
|
||||
prevote, _ := cs.signVote(types.PrevoteType, blockHash, parts.Header())
|
||||
precommit, _ := cs.signVote(types.PrecommitType, blockHash, parts.Header())
|
||||
cs.mtx.Unlock()
|
||||
|
||||
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
|
||||
|
@@ -39,8 +39,8 @@ const (
|
||||
)
|
||||
|
||||
// genesis, chain_id, priv_val
|
||||
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 config *cfg.Config // NOTE: must be reset for each _test.go file
|
||||
var ensureTimeout = time.Millisecond * 100
|
||||
|
||||
func ensureDir(dir string, mode os.FileMode) {
|
||||
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{
|
||||
ValidatorIndex: vs.Index,
|
||||
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
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
for i, vs := range vss {
|
||||
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...)
|
||||
addVotes(to, votes...)
|
||||
}
|
||||
@@ -317,67 +317,156 @@ func ensureNoNewEvent(ch <-chan interface{}, timeout time.Duration,
|
||||
}
|
||||
}
|
||||
|
||||
func ensureNoNewStep(stepCh <-chan interface{}) {
|
||||
ensureNoNewEvent(stepCh, ensureTimeout, "We should be stuck waiting, "+
|
||||
"not moving to the next step")
|
||||
func ensureNoNewEventOnChannel(ch <-chan interface{}) {
|
||||
ensureNoNewEvent(
|
||||
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) {
|
||||
timeoutDuration := time.Duration(timeout*5) * time.Nanosecond
|
||||
ensureNoNewEvent(stepCh, timeoutDuration, "We should be stuck waiting, "+
|
||||
"not moving to the next step")
|
||||
ensureNoNewEvent(
|
||||
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 {
|
||||
case <-time.After(timeout):
|
||||
panic(errorMessage)
|
||||
case <-ch:
|
||||
break
|
||||
case ev := <-ch:
|
||||
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{}) {
|
||||
ensureNewEvent(stepCh, ensureTimeout,
|
||||
func ensureNewRoundStep(stepCh <-chan interface{}, height int64, round int) {
|
||||
ensureNewEvent(
|
||||
stepCh,
|
||||
height,
|
||||
round,
|
||||
ensureTimeout,
|
||||
"Timeout expired while waiting for NewStep event")
|
||||
}
|
||||
|
||||
func ensureNewRound(roundCh <-chan interface{}) {
|
||||
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) {
|
||||
func ensureNewVote(voteCh <-chan interface{}, height int64, round int) {
|
||||
select {
|
||||
case <-time.After(ensureTimeout):
|
||||
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:
|
||||
edv, ok := v.(types.EventDataVote)
|
||||
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
|
||||
|
||||
@@ -471,7 +568,7 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
|
||||
|
||||
func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
||||
for i, s := range switches {
|
||||
if peer.NodeInfo().ID == s.NodeInfo().ID {
|
||||
if peer.NodeInfo().ID() == s.NodeInfo().ID() {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
@@ -28,12 +28,12 @@ func TestMempoolNoProgressUntilTxsAvailable(t *testing.T) {
|
||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||
startTestRound(cs, height, round)
|
||||
|
||||
ensureNewStep(newBlockCh) // first block gets committed
|
||||
ensureNoNewStep(newBlockCh)
|
||||
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||
ensureNoNewEventOnChannel(newBlockCh)
|
||||
deliverTxsRange(cs, 0, 1)
|
||||
ensureNewStep(newBlockCh) // commit txs
|
||||
ensureNewStep(newBlockCh) // commit updated app hash
|
||||
ensureNoNewStep(newBlockCh)
|
||||
ensureNewEventOnChannel(newBlockCh) // commit txs
|
||||
ensureNewEventOnChannel(newBlockCh) // commit updated app hash
|
||||
ensureNoNewEventOnChannel(newBlockCh)
|
||||
}
|
||||
|
||||
func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
||||
@@ -46,9 +46,9 @@ func TestMempoolProgressAfterCreateEmptyBlocksInterval(t *testing.T) {
|
||||
newBlockCh := subscribe(cs.eventBus, types.EventQueryNewBlock)
|
||||
startTestRound(cs, height, round)
|
||||
|
||||
ensureNewStep(newBlockCh) // first block gets committed
|
||||
ensureNoNewStep(newBlockCh) // then we dont make a block ...
|
||||
ensureNewStep(newBlockCh) // until the CreateEmptyBlocksInterval has passed
|
||||
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||
ensureNoNewEventOnChannel(newBlockCh) // then we dont make a block ...
|
||||
ensureNewEventOnChannel(newBlockCh) // until the CreateEmptyBlocksInterval has passed
|
||||
}
|
||||
|
||||
func TestMempoolProgressInHigherRound(t *testing.T) {
|
||||
@@ -72,13 +72,19 @@ func TestMempoolProgressInHigherRound(t *testing.T) {
|
||||
}
|
||||
startTestRound(cs, height, round)
|
||||
|
||||
ensureNewStep(newRoundCh) // first round at first height
|
||||
ensureNewStep(newBlockCh) // first block gets committed
|
||||
ensureNewStep(newRoundCh) // first round at next height
|
||||
deliverTxsRange(cs, 0, 1) // we deliver txs, but dont set a proposal so we get the next round
|
||||
<-timeoutCh
|
||||
ensureNewStep(newRoundCh) // wait for the next round
|
||||
ensureNewStep(newBlockCh) // now we can commit the block
|
||||
ensureNewRoundStep(newRoundCh, height, round) // first round at first height
|
||||
ensureNewEventOnChannel(newBlockCh) // first block gets committed
|
||||
|
||||
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
|
||||
ensureNewTimeout(timeoutCh, height, round, cs.config.TimeoutPropose.Nanoseconds())
|
||||
|
||||
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) {
|
||||
|
@@ -237,9 +237,9 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
// (and consequently shows which we don't have)
|
||||
var ourVotes *cmn.BitArray
|
||||
switch msg.Type {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
default:
|
||||
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 {
|
||||
var ourVotes *cmn.BitArray
|
||||
switch msg.Type {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
ourVotes = votes.Prevotes(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
ourVotes = votes.Precommits(msg.Round).BitArrayByBlockID(msg.BlockID)
|
||||
default:
|
||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||
@@ -739,7 +739,7 @@ OUTER_LOOP:
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: types.VoteTypePrevote,
|
||||
Type: types.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
@@ -756,7 +756,7 @@ OUTER_LOOP:
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: types.VoteTypePrecommit,
|
||||
Type: types.PrecommitType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
@@ -773,7 +773,7 @@ OUTER_LOOP:
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.ProposalPOLRound,
|
||||
Type: types.VoteTypePrevote,
|
||||
Type: types.PrevoteType,
|
||||
BlockID: maj23,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
@@ -792,7 +792,7 @@ OUTER_LOOP:
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: commit.Round(),
|
||||
Type: types.VoteTypePrecommit,
|
||||
Type: types.PrecommitType,
|
||||
BlockID: commit.BlockID,
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23SleepDuration)
|
||||
@@ -1022,7 +1022,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
|
||||
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'.
|
||||
if votes.IsCommit() {
|
||||
@@ -1041,7 +1041,7 @@ func (ps *PeerState) PickVoteToSend(votes types.VoteSetReader) (vote *types.Vote
|
||||
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_) {
|
||||
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.Round == round {
|
||||
switch type_ {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return ps.PRS.Prevotes
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
return ps.PRS.Precommits
|
||||
}
|
||||
}
|
||||
if ps.PRS.CatchupCommitRound == round {
|
||||
switch type_ {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return nil
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
return ps.PRS.CatchupCommit
|
||||
}
|
||||
}
|
||||
if ps.PRS.ProposalPOLRound == round {
|
||||
switch type_ {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return ps.PRS.ProposalPOL
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
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.LastCommitRound == round {
|
||||
switch type_ {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return nil
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
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)
|
||||
}
|
||||
|
||||
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.Debug("setHasVote", "type", type_, "index", index)
|
||||
|
||||
@@ -1453,7 +1453,7 @@ func (m *VoteMessage) String() string {
|
||||
type HasVoteMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
Type types.SignedMsgType
|
||||
Index int
|
||||
}
|
||||
|
||||
@@ -1468,7 +1468,7 @@ func (m *HasVoteMessage) String() string {
|
||||
type VoteSetMaj23Message struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
Type types.SignedMsgType
|
||||
BlockID types.BlockID
|
||||
}
|
||||
|
||||
@@ -1483,7 +1483,7 @@ func (m *VoteSetMaj23Message) String() string {
|
||||
type VoteSetBitsMessage struct {
|
||||
Height int64
|
||||
Round int
|
||||
Type byte
|
||||
Type types.SignedMsgType
|
||||
BlockID types.BlockID
|
||||
Votes *cmn.BitArray
|
||||
}
|
||||
|
@@ -287,6 +287,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
|
||||
return nil, err
|
||||
}
|
||||
state.Validators = types.NewValidatorSet(vals)
|
||||
state.NextValidators = types.NewValidatorSet(vals)
|
||||
}
|
||||
if res.ConsensusParams != nil {
|
||||
state.ConsensusParams = types.PB2TM.ConsensusParams(res.ConsensusParams)
|
||||
|
@@ -542,7 +542,7 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
case *types.Vote:
|
||||
if p.Type == types.VoteTypePrecommit {
|
||||
if p.Type == types.PrecommitType {
|
||||
thisBlockCommit = &types.Commit{
|
||||
BlockID: p.BlockID,
|
||||
Precommits: []*types.Vote{p},
|
||||
|
@@ -83,7 +83,8 @@ type ConsensusState struct {
|
||||
// internal state
|
||||
mtx sync.RWMutex
|
||||
cstypes.RoundState
|
||||
state sm.State // State until height-1.
|
||||
triggeredTimeoutPrecommit bool
|
||||
state sm.State // State until height-1.
|
||||
|
||||
// state changes may be triggered by: msgs from peers,
|
||||
// msgs from ourself, or by timeouts
|
||||
@@ -459,7 +460,7 @@ func (cs *ConsensusState) reconstructLastCommit(state sm.State) {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
if precommit == nil {
|
||||
continue
|
||||
@@ -711,6 +712,7 @@ func (cs *ConsensusState) handleTimeout(ti timeoutInfo, rs cstypes.RoundState) {
|
||||
cs.enterPrecommit(ti.Height, ti.Round)
|
||||
case cstypes.RoundStepPrecommitWait:
|
||||
cs.eventBus.PublishEventTimeoutWait(cs.RoundStateEvent())
|
||||
cs.enterPrecommit(ti.Height, ti.Round)
|
||||
cs.enterNewRound(ti.Height, ti.Round+1)
|
||||
default:
|
||||
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.Votes.SetRound(round + 1) // also track next round (round+1) to allow round-skipping
|
||||
cs.triggeredTimeoutPrecommit = false
|
||||
|
||||
cs.eventBus.PublishEventNewRound(cs.RoundStateEvent())
|
||||
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)
|
||||
if waitForTxs {
|
||||
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)
|
||||
} else {
|
||||
@@ -1013,17 +1017,18 @@ func (cs *ConsensusState) enterPrevote(height int64, round int) {
|
||||
|
||||
func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
||||
logger := cs.Logger.With("height", height, "round", round)
|
||||
|
||||
// If a block is locked, prevote that.
|
||||
if cs.LockedBlock != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// If ProposalBlock is nil, prevote nil.
|
||||
if cs.ProposalBlock == nil {
|
||||
logger.Info("enterPrevote: ProposalBlock is nil")
|
||||
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
||||
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1032,7 +1037,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
||||
if err != nil {
|
||||
// ProposalBlock is invalid, prevote nil.
|
||||
logger.Error("enterPrevote: ProposalBlock is invalid", "err", err)
|
||||
cs.signAddVote(types.VoteTypePrevote, nil, types.PartSetHeader{})
|
||||
cs.signAddVote(types.PrevoteType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1040,7 +1045,7 @@ func (cs *ConsensusState) defaultDoPrevote(height int64, round int) {
|
||||
// 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)
|
||||
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.
|
||||
@@ -1098,7 +1103,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1122,7 +1127,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
||||
cs.LockedBlockParts = nil
|
||||
cs.eventBus.PublishEventUnlock(cs.RoundStateEvent())
|
||||
}
|
||||
cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{})
|
||||
cs.signAddVote(types.PrecommitType, nil, types.PartSetHeader{})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1133,7 +1138,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
||||
logger.Info("enterPrecommit: +2/3 prevoted locked block. Relocking")
|
||||
cs.LockedRound = round
|
||||
cs.eventBus.PublishEventRelock(cs.RoundStateEvent())
|
||||
cs.signAddVote(types.VoteTypePrecommit, blockID.Hash, blockID.PartsHeader)
|
||||
cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1148,7 +1153,7 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
||||
cs.LockedBlock = cs.ProposalBlock
|
||||
cs.LockedBlockParts = cs.ProposalBlockParts
|
||||
cs.eventBus.PublishEventLock(cs.RoundStateEvent())
|
||||
cs.signAddVote(types.VoteTypePrecommit, blockID.Hash, blockID.PartsHeader)
|
||||
cs.signAddVote(types.PrecommitType, blockID.Hash, blockID.PartsHeader)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1164,15 +1169,19 @@ func (cs *ConsensusState) enterPrecommit(height int64, round int) {
|
||||
cs.ProposalBlockParts = types.NewPartSetFromHeader(blockID.PartsHeader)
|
||||
}
|
||||
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.
|
||||
func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
|
||||
logger := cs.Logger.With("height", height, "round", round)
|
||||
|
||||
if cs.Height != height || round < cs.Round || (cs.Round == round && cstypes.RoundStepPrecommitWait <= cs.Step) {
|
||||
logger.Debug(fmt.Sprintf("enterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step))
|
||||
if cs.Height != height || round < cs.Round || (cs.Round == round && cs.triggeredTimeoutPrecommit) {
|
||||
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
|
||||
}
|
||||
if !cs.Votes.Precommits(round).HasTwoThirdsAny() {
|
||||
@@ -1182,7 +1191,7 @@ func (cs *ConsensusState) enterPrecommitWait(height int64, round int) {
|
||||
|
||||
defer func() {
|
||||
// Done enterPrecommitWait:
|
||||
cs.updateRoundStep(round, cstypes.RoundStepPrecommitWait)
|
||||
cs.triggeredTimeoutPrecommit = true
|
||||
cs.newStep()
|
||||
}()
|
||||
|
||||
@@ -1495,6 +1504,9 @@ func (cs *ConsensusState) addProposalBlockPart(msg *BlockPartMessage, peerID p2p
|
||||
if cs.Step <= cstypes.RoundStepPropose && cs.isProposalComplete() {
|
||||
// Move onto the next step
|
||||
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 {
|
||||
// If we're waiting on the proposal block...
|
||||
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?
|
||||
// These come in while we wait timeoutCommit
|
||||
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 ..
|
||||
// fmt.Errorf("tryAddVote: Wrong height, not a LastCommit straggler commit.")
|
||||
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)
|
||||
|
||||
switch vote.Type {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
prevotes := cs.Votes.Prevotes(vote.Round)
|
||||
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.
|
||||
// NOTE: our proposal block may be nil or not what received a polka..
|
||||
// TODO: we may want to still update the ValidBlock and obtain it via gossipping
|
||||
if !blockID.IsZero() &&
|
||||
if len(blockID.Hash) != 0 &&
|
||||
(cs.ValidRound < vote.Round) &&
|
||||
(vote.Round <= cs.Round) &&
|
||||
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 cs.Round <= vote.Round && prevotes.HasTwoThirdsAny() {
|
||||
// Round-skip over to PrevoteWait or goto Precommit.
|
||||
cs.enterNewRound(height, vote.Round) // if the vote is ahead of us
|
||||
// If +2/3 prevotes for *anything* for future round:
|
||||
if cs.Round < vote.Round && prevotes.HasTwoThirdsAny() {
|
||||
// Round-skip if there is any 2/3+ of votes ahead of us
|
||||
cs.enterNewRound(height, vote.Round)
|
||||
} else if cs.Round == vote.Round && cstypes.RoundStepPrevote <= cs.Step { // current round
|
||||
if prevotes.HasTwoThirdsMajority() {
|
||||
cs.enterPrecommit(height, vote.Round)
|
||||
} else {
|
||||
cs.enterPrevote(height, vote.Round) // if the vote is ahead of us
|
||||
} else if prevotes.HasTwoThirdsAny() {
|
||||
cs.enterPrevoteWait(height, 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)
|
||||
cs.Logger.Info("Added to precommit", "vote", vote, "precommits", precommits.StringShort())
|
||||
|
||||
blockID, ok := precommits.TwoThirdsMajority()
|
||||
if ok && len(blockID.Hash) != 0 {
|
||||
if ok {
|
||||
// Executed as TwoThirdsMajority could be from a higher round
|
||||
cs.enterNewRound(height, vote.Round)
|
||||
cs.enterPrecommit(height, vote.Round)
|
||||
cs.enterCommit(height, vote.Round)
|
||||
|
||||
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
||||
cs.enterNewRound(cs.Height, 0)
|
||||
if len(blockID.Hash) != 0 {
|
||||
cs.enterCommit(height, vote.Round)
|
||||
if cs.config.SkipTimeoutCommit && precommits.HasAll() {
|
||||
cs.enterNewRound(cs.Height, 0)
|
||||
}
|
||||
} else {
|
||||
cs.enterPrecommitWait(height, vote.Round)
|
||||
}
|
||||
} else if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() {
|
||||
cs.enterNewRound(height, vote.Round)
|
||||
cs.enterPrecommit(height, vote.Round)
|
||||
cs.enterPrecommitWait(height, vote.Round)
|
||||
}
|
||||
|
||||
default:
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
valIndex, _ := cs.Validators.GetByAddress(addr)
|
||||
|
||||
@@ -1698,7 +1714,7 @@ func (cs *ConsensusState) voteTime() time.Time {
|
||||
}
|
||||
|
||||
// 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 cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
|
||||
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")
|
||||
}
|
||||
// log.Debug("addRound(round)", "round", round)
|
||||
prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrevote, hvs.valSet)
|
||||
precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, types.VoteTypePrecommit, hvs.valSet)
|
||||
prevotes := types.NewVoteSet(hvs.chainID, hvs.height, round, types.PrevoteType, hvs.valSet)
|
||||
precommits := types.NewVoteSet(hvs.chainID, hvs.height, round, types.PrecommitType, hvs.valSet)
|
||||
hvs.roundVoteSets[round] = RoundVoteSet{
|
||||
Prevotes: prevotes,
|
||||
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 {
|
||||
hvs.mtx.Lock()
|
||||
defer hvs.mtx.Unlock()
|
||||
return hvs.getVoteSet(round, types.VoteTypePrevote)
|
||||
return hvs.getVoteSet(round, types.PrevoteType)
|
||||
}
|
||||
|
||||
func (hvs *HeightVoteSet) Precommits(round int) *types.VoteSet {
|
||||
hvs.mtx.Lock()
|
||||
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.
|
||||
@@ -149,7 +149,7 @@ func (hvs *HeightVoteSet) POLInfo() (polRound int, polBlockID types.BlockID) {
|
||||
hvs.mtx.Lock()
|
||||
defer hvs.mtx.Unlock()
|
||||
for r := hvs.round; r >= 0; r-- {
|
||||
rvs := hvs.getVoteSet(r, types.VoteTypePrevote)
|
||||
rvs := hvs.getVoteSet(r, types.PrevoteType)
|
||||
polBlockID, ok := rvs.TwoThirdsMajority()
|
||||
if ok {
|
||||
return r, polBlockID
|
||||
@@ -158,15 +158,15 @@ func (hvs *HeightVoteSet) POLInfo() (polRound int, polBlockID 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]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
switch type_ {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return rvs.Prevotes
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
return rvs.Precommits
|
||||
default:
|
||||
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,
|
||||
// this can cause memory issues.
|
||||
// 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()
|
||||
defer hvs.mtx.Unlock()
|
||||
if !types.IsVoteTypeValid(type_) {
|
||||
|
@@ -56,7 +56,7 @@ func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivVali
|
||||
Height: height,
|
||||
Round: round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: types.VoteTypePrecommit,
|
||||
Type: types.PrecommitType,
|
||||
BlockID: types.BlockID{[]byte("fakehash"), types.PartSetHeader{}},
|
||||
}
|
||||
chainID := config.ChainID()
|
||||
|
@@ -46,6 +46,12 @@ func (privKey PrivKeyEd25519) Bytes() []byte {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
signatureBytes := ed25519.Sign(privKey[:], msg)
|
||||
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,
|
||||
// in the provided order.
|
||||
func SimpleHashFromByteSlices(items [][]byte) []byte {
|
||||
hashes := make([][]byte, len(items))
|
||||
for i, item := range items {
|
||||
hash := tmhash.Sum(item)
|
||||
hashes[i] = hash
|
||||
switch len(items) {
|
||||
case 0:
|
||||
return nil
|
||||
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.
|
||||
@@ -40,20 +44,3 @@ func SimpleHashFromMap(m map[string][]byte) []byte {
|
||||
}
|
||||
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.
|
||||
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
|
||||
`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`
|
||||
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.
|
||||
|
||||
When signing, the elements of a message are sorted alphabetically by key and prepended with
|
||||
a `chain_id` and `type` field.
|
||||
When signing, the elements of a message are re-ordered so the fixed-length fields
|
||||
are first, making it easy to quickly check the version, height, round, and type.
|
||||
The `ChainID` is also appended to the end.
|
||||
We call this encoding the SignBytes. For instance, SignBytes for a vote is the Amino encoding of the following struct:
|
||||
|
||||
```go
|
||||
type CanonicalVote struct {
|
||||
ChainID string
|
||||
Type string
|
||||
BlockID CanonicalBlockID
|
||||
Height int64
|
||||
Round int
|
||||
Timestamp time.Time
|
||||
Version uint64 `binary:"fixed64"`
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
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,
|
||||
Round: 1,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: types.VoteTypePrecommit,
|
||||
Type: types.PrecommitType,
|
||||
BlockID: types.BlockID{Hash: header.Hash()},
|
||||
}
|
||||
// Sign it
|
||||
|
@@ -106,7 +106,7 @@ func DefaultMetricsProvider(config *cfg.InstrumentationConfig) MetricsProvider {
|
||||
return func() (*cs.Metrics, *p2p.Metrics, *mempl.Metrics, *sm.Metrics) {
|
||||
if config.Prometheus {
|
||||
return cs.PrometheusMetrics(config.Namespace), p2p.PrometheusMetrics(config.Namespace),
|
||||
mempl.PrometheusMetrics(config.Namespace), sm.PrometheusMetrics(config.Namespace)
|
||||
mempl.PrometheusMetrics(config.Namespace), sm.PrometheusMetrics(config.Namespace)
|
||||
}
|
||||
return cs.NopMetrics(), p2p.NopMetrics(), mempl.NopMetrics(), sm.NopMetrics()
|
||||
}
|
||||
@@ -761,8 +761,8 @@ func makeNodeInfo(
|
||||
if _, ok := txIndexer.(*null.TxIndex); ok {
|
||||
txIndexerStatus = "off"
|
||||
}
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
ID: nodeID,
|
||||
nodeInfo := p2p.DefaultNodeInfo{
|
||||
ID_: nodeID,
|
||||
Network: chainID,
|
||||
Version: version.Version,
|
||||
Channels: []byte{
|
||||
@@ -772,7 +772,7 @@ func makeNodeInfo(
|
||||
evidence.EvidenceChannel,
|
||||
},
|
||||
Moniker: config.Moniker,
|
||||
Other: p2p.NodeInfoOther{
|
||||
Other: p2p.DefaultNodeInfoOther{
|
||||
AminoVersion: amino.Version,
|
||||
P2PVersion: p2p.Version,
|
||||
ConsensusVersion: cs.Version,
|
||||
|
@@ -42,7 +42,7 @@ func (p *peer) IsPersistent() bool {
|
||||
|
||||
// NodeInfo always returns empty node info.
|
||||
func (p *peer) NodeInfo() p2p.NodeInfo {
|
||||
return p2p.NodeInfo{}
|
||||
return p2p.DefaultNodeInfo{}
|
||||
}
|
||||
|
||||
// RemoteIP always returns localhost.
|
||||
@@ -78,8 +78,3 @@ func (p *peer) Get(key string) interface{} {
|
||||
}
|
||||
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.conn != nil {
|
||||
return fmt.Sprintf(
|
||||
"duplicate CONN<%s>: %s",
|
||||
"duplicate CONN<%s>",
|
||||
e.conn.RemoteAddr().String(),
|
||||
e.err,
|
||||
)
|
||||
}
|
||||
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",
|
||||
Help: "Number of transactions submitted by each peer.",
|
||||
}, []string{"peer_id"}),
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package p2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
@@ -17,12 +18,32 @@ func MaxNodeInfoSize() int {
|
||||
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.
|
||||
type NodeInfo struct {
|
||||
type DefaultNodeInfo struct {
|
||||
// Authenticate
|
||||
// TODO: replace with NetAddress
|
||||
ID ID `json:"id"` // authenticated identifier
|
||||
ID_ ID `json:"id"` // authenticated identifier
|
||||
ListenAddr string `json:"listen_addr"` // accepting incoming
|
||||
|
||||
// Check compatibility.
|
||||
@@ -32,12 +53,12 @@ type NodeInfo struct {
|
||||
Channels cmn.HexBytes `json:"channels"` // channels this node knows about
|
||||
|
||||
// ASCIIText fields
|
||||
Moniker string `json:"moniker"` // arbitrary moniker
|
||||
Other NodeInfoOther `json:"other"` // other application specific data
|
||||
Moniker string `json:"moniker"` // arbitrary moniker
|
||||
Other DefaultNodeInfoOther `json:"other"` // other application specific data
|
||||
}
|
||||
|
||||
// NodeInfoOther is the misc. applcation specific data
|
||||
type NodeInfoOther struct {
|
||||
// DefaultNodeInfoOther is the misc. applcation specific data
|
||||
type DefaultNodeInfoOther struct {
|
||||
AminoVersion string `json:"amino_version"`
|
||||
P2PVersion string `json:"p2p_version"`
|
||||
ConsensusVersion string `json:"consensus_version"`
|
||||
@@ -46,19 +67,12 @@ type NodeInfoOther struct {
|
||||
RPCAddress string `json:"rpc_address"`
|
||||
}
|
||||
|
||||
func (o NodeInfoOther) String() string {
|
||||
return fmt.Sprintf(
|
||||
"{amino_version: %v, p2p_version: %v, consensus_version: %v, rpc_version: %v, tx_index: %v, rpc_address: %v}",
|
||||
o.AminoVersion,
|
||||
o.P2PVersion,
|
||||
o.ConsensusVersion,
|
||||
o.RPCVersion,
|
||||
o.TxIndex,
|
||||
o.RPCAddress,
|
||||
)
|
||||
// ID returns the node's peer ID.
|
||||
func (info DefaultNodeInfo) ID() ID {
|
||||
return info.ID_
|
||||
}
|
||||
|
||||
// Validate checks the self-reported NodeInfo is safe.
|
||||
// ValidateBasic checks the self-reported DefaultNodeInfo is safe.
|
||||
// It returns an error if there
|
||||
// are too many Channels, if there are any duplicate Channels,
|
||||
// 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
|
||||
// url-encoding), and we just need to be careful with how we handle that in our
|
||||
// clients. (e.g. off by default).
|
||||
func (info NodeInfo) Validate() error {
|
||||
func (info DefaultNodeInfo) ValidateBasic() error {
|
||||
if 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
|
||||
_, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
|
||||
_, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
||||
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
|
||||
// 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)
|
||||
oMajor, _, _, oErr := splitVersion(other.Version)
|
||||
|
||||
@@ -164,18 +183,18 @@ OUTER_LOOP:
|
||||
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
|
||||
// ListenAddr. Note that the ListenAddr is not authenticated and
|
||||
// may not match that address actually dialed if its an outbound peer.
|
||||
func (info NodeInfo) NetAddress() *NetAddress {
|
||||
netAddr, err := NewNetAddressString(IDAddressString(info.ID, info.ListenAddr))
|
||||
func (info DefaultNodeInfo) NetAddress() *NetAddress {
|
||||
netAddr, err := NewNetAddressString(IDAddressString(info.ID(), info.ListenAddr))
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case ErrNetAddressLookup:
|
||||
// XXX If the peer provided a host name and the lookup fails here
|
||||
// we're out of luck.
|
||||
// TODO: use a NetAddress in NodeInfo
|
||||
// TODO: use a NetAddress in DefaultNodeInfo
|
||||
default:
|
||||
panic(err) // everything should be well formed by now
|
||||
}
|
||||
@@ -183,11 +202,6 @@ func (info NodeInfo) NetAddress() *NetAddress {
|
||||
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) {
|
||||
spl := strings.Split(version, ".")
|
||||
if len(spl) != 3 {
|
||||
|
107
p2p/peer.go
107
p2p/peer.go
@@ -3,7 +3,6 @@ package p2p
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
@@ -15,19 +14,18 @@ import (
|
||||
|
||||
const metricsTickerDuration = 10 * time.Second
|
||||
|
||||
var testIPSuffix uint32
|
||||
|
||||
// Peer is an interface representing a peer connected on a reactor.
|
||||
type Peer interface {
|
||||
cmn.Service
|
||||
|
||||
ID() ID // peer's cryptographic ID
|
||||
RemoteIP() net.IP // remote IP of the connection
|
||||
ID() ID // peer's cryptographic ID
|
||||
RemoteIP() net.IP // remote IP of the connection
|
||||
|
||||
IsOutbound() bool // did we dial the peer
|
||||
IsPersistent() bool // do we redial this peer when we disconnect
|
||||
|
||||
NodeInfo() NodeInfo // peer's info
|
||||
Status() tmconn.ConnectionStatus
|
||||
OriginalAddr() *NetAddress
|
||||
|
||||
Send(byte, []byte) bool
|
||||
TrySend(byte, []byte) bool
|
||||
@@ -40,12 +38,13 @@ type Peer interface {
|
||||
|
||||
// peerConn contains the raw connection and its config.
|
||||
type peerConn struct {
|
||||
outbound bool
|
||||
persistent bool
|
||||
config *config.P2PConfig
|
||||
conn net.Conn // source connection
|
||||
ip net.IP
|
||||
originalAddr *NetAddress // nil for inbound connections
|
||||
outbound bool
|
||||
persistent bool
|
||||
config *config.P2PConfig
|
||||
conn net.Conn // source connection
|
||||
|
||||
// cached RemoteIP()
|
||||
ip net.IP
|
||||
}
|
||||
|
||||
// ID only exists for SecretConnection.
|
||||
@@ -60,14 +59,6 @@ func (pc peerConn) RemoteIP() net.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())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -120,7 +111,7 @@ func newPeer(
|
||||
p := &peer{
|
||||
peerConn: pc,
|
||||
nodeInfo: nodeInfo,
|
||||
channels: nodeInfo.Channels,
|
||||
channels: nodeInfo.(DefaultNodeInfo).Channels, // TODO
|
||||
Data: cmn.NewCMap(),
|
||||
metricsTicker: time.NewTicker(metricsTickerDuration),
|
||||
metrics: NopMetrics(),
|
||||
@@ -142,6 +133,15 @@ func newPeer(
|
||||
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
|
||||
|
||||
@@ -177,7 +177,7 @@ func (p *peer) OnStop() {
|
||||
|
||||
// ID returns the peer's ID - the hex encoded hash of its pubkey.
|
||||
func (p *peer) ID() ID {
|
||||
return p.nodeInfo.ID
|
||||
return p.nodeInfo.ID()
|
||||
}
|
||||
|
||||
// IsOutbound returns true if the connection is outbound, false otherwise.
|
||||
@@ -195,15 +195,6 @@ func (p *peer) NodeInfo() NodeInfo {
|
||||
return p.nodeInfo
|
||||
}
|
||||
|
||||
// OriginalAddr returns the original address, which was used to connect with
|
||||
// the peer. Returns nil for inbound peers.
|
||||
func (p *peer) OriginalAddr() *NetAddress {
|
||||
if p.peerConn.outbound {
|
||||
return p.peerConn.originalAddr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status returns the peer's ConnectionStatus.
|
||||
func (p *peer) Status() tmconn.ConnectionStatus {
|
||||
return p.mconn.Status()
|
||||
@@ -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
|
||||
// started.
|
||||
// CloseConn closes the underlying connection
|
||||
func (pc *peerConn) CloseConn() {
|
||||
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.
|
||||
func (p *peer) Addr() net.Addr {
|
||||
return p.peerConn.conn.RemoteAddr()
|
||||
@@ -332,14 +284,7 @@ func (p *peer) CanSend(chID byte) bool {
|
||||
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 {
|
||||
return func(p *peer) {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -12,24 +11,34 @@ import (
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// Returns an empty kvstore peer
|
||||
func randPeer(ip net.IP) *peer {
|
||||
// mockPeer for testing the PeerSet
|
||||
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 {
|
||||
ip = net.IP{127, 0, 0, 1}
|
||||
}
|
||||
|
||||
nodeKey := NodeKey{PrivKey: ed25519.GenPrivKey()}
|
||||
p := &peer{
|
||||
nodeInfo: NodeInfo{
|
||||
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(),
|
||||
return &mockPeer{
|
||||
ip: ip,
|
||||
id: nodeKey.ID(),
|
||||
}
|
||||
|
||||
p.ip = ip
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func TestPeerSetAddRemoveOne(t *testing.T) {
|
||||
@@ -39,7 +48,7 @@ func TestPeerSetAddRemoveOne(t *testing.T) {
|
||||
|
||||
var peerList []Peer
|
||||
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 {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -83,7 +92,7 @@ func TestPeerSetAddRemoveMany(t *testing.T) {
|
||||
peers := []Peer{}
|
||||
N := 100
|
||||
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 {
|
||||
t.Errorf("Failed to add new peer")
|
||||
}
|
||||
@@ -107,7 +116,7 @@ func TestPeerSetAddRemoveMany(t *testing.T) {
|
||||
func TestPeerSetAddDuplicate(t *testing.T) {
|
||||
t.Parallel()
|
||||
peerSet := NewPeerSet()
|
||||
peer := randPeer(nil)
|
||||
peer := newMockPeer(nil)
|
||||
|
||||
n := 20
|
||||
errsChan := make(chan error)
|
||||
@@ -149,7 +158,7 @@ func TestPeerSetGet(t *testing.T) {
|
||||
|
||||
var (
|
||||
peerSet = NewPeerSet()
|
||||
peer = randPeer(nil)
|
||||
peer = newMockPeer(nil)
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
const testCh = 0x01
|
||||
|
||||
func TestPeerBasic(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
@@ -81,18 +79,14 @@ func createOutboundPeerAndPerformHandshake(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeInfo, err := pc.HandshakeTimeout(NodeInfo{
|
||||
ID: addr.ID,
|
||||
Moniker: "host_peer",
|
||||
Network: "testing",
|
||||
Version: "123.123.123",
|
||||
Channels: []byte{testCh},
|
||||
}, 1*time.Second)
|
||||
timeout := 1 * time.Second
|
||||
ourNodeInfo := testNodeInfo(addr.ID, "host_peer")
|
||||
peerNodeInfo, err := handshake(pc.conn, timeout, ourNodeInfo)
|
||||
if err != nil {
|
||||
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))
|
||||
return p, nil
|
||||
}
|
||||
@@ -120,7 +114,7 @@ func testOutboundPeerConn(
|
||||
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 cerr := conn.Close(); cerr != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
_, err = handshake(pc.conn, time.Second, NodeInfo{
|
||||
ID: rp.Addr().ID,
|
||||
Moniker: "remote_peer",
|
||||
Network: "testing",
|
||||
Version: "123.123.123",
|
||||
ListenAddr: l.Addr().String(),
|
||||
Channels: rp.channels,
|
||||
})
|
||||
_, err = handshake(pc.conn, time.Second, rp.nodeInfo(l))
|
||||
if err != nil {
|
||||
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)
|
||||
|
||||
pexR, book := createReactor(&PEXReactorConfig{})
|
||||
book.AddPrivateIDs([]string{string(peer.NodeInfo().ID)})
|
||||
book.AddPrivateIDs([]string{string(peer.NodeInfo().ID())})
|
||||
defer teardownReactor(book)
|
||||
|
||||
// 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) IsPersistent() bool { return mp.persistent }
|
||||
func (mp mockPeer) NodeInfo() p2p.NodeInfo {
|
||||
return p2p.NodeInfo{
|
||||
ID: mp.addr.ID,
|
||||
return p2p.DefaultNodeInfo{
|
||||
ID_: mp.addr.ID,
|
||||
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) Set(string, interface{}) {}
|
||||
func (mockPeer) Get(string) interface{} { return nil }
|
||||
func (mockPeer) OriginalAddr() *p2p.NetAddress { return nil }
|
||||
|
||||
func assertPeersWithTimeout(
|
||||
t *testing.T,
|
||||
|
@@ -280,12 +280,9 @@ func (sw *Switch) StopPeerForError(peer Peer, reason interface{}) {
|
||||
sw.stopAndRemovePeer(peer, reason)
|
||||
|
||||
if peer.IsPersistent() {
|
||||
addr := peer.OriginalAddr()
|
||||
if addr == nil {
|
||||
// FIXME: persistent peers can't be inbound right now.
|
||||
// self-reported address for inbound persistent peers
|
||||
addr = peer.NodeInfo().NetAddress()
|
||||
}
|
||||
// TODO: use the original address dialed, not the self reported one
|
||||
// See #2618.
|
||||
addr := peer.NodeInfo().NetAddress()
|
||||
go sw.reconnectToPeer(addr)
|
||||
}
|
||||
}
|
||||
@@ -560,9 +557,13 @@ func (sw *Switch) addOutboundPeerWithConfig(
|
||||
// to avoid dialing in the future.
|
||||
sw.addrBook.RemoveAddress(addr)
|
||||
sw.addrBook.AddOurAddress(addr)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// retry persistent peers after
|
||||
// any dial error besides IsSelf()
|
||||
if persistent {
|
||||
go sw.reconnectToPeer(addr)
|
||||
}
|
||||
|
@@ -143,6 +143,7 @@ func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, r
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
case <-time.After(timeout):
|
||||
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"
|
||||
)
|
||||
|
||||
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) {
|
||||
sw.peers.Add(peer)
|
||||
}
|
||||
@@ -24,12 +37,9 @@ func CreateRandomPeer(outbound bool) *peer {
|
||||
peerConn: peerConn{
|
||||
outbound: outbound,
|
||||
},
|
||||
nodeInfo: NodeInfo{
|
||||
ID: netAddr.ID,
|
||||
ListenAddr: netAddr.DialString(),
|
||||
},
|
||||
mconn: &conn.MConnection{},
|
||||
metrics: NopMetrics(),
|
||||
nodeInfo: mockNodeInfo{netAddr},
|
||||
mconn: &conn.MConnection{},
|
||||
metrics: NopMetrics(),
|
||||
}
|
||||
p.SetLogger(log.TestingLogger().With("peer", addr))
|
||||
return p
|
||||
@@ -159,36 +169,15 @@ func MakeSwitch(
|
||||
initSwitch func(int, *Switch) *Switch,
|
||||
opts ...SwitchOption,
|
||||
) *Switch {
|
||||
var (
|
||||
nodeKey = NodeKey{
|
||||
PrivKey: ed25519.GenPrivKey(),
|
||||
}
|
||||
ni = NodeInfo{
|
||||
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(
|
||||
IDAddressString(nodeKey.ID(), ni.ListenAddr),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
nodeKey := NodeKey{
|
||||
PrivKey: ed25519.GenPrivKey(),
|
||||
}
|
||||
nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i))
|
||||
|
||||
t := NewMultiplexTransport(ni, nodeKey)
|
||||
t := NewMultiplexTransport(nodeInfo, nodeKey)
|
||||
|
||||
addr := nodeInfo.NetAddress()
|
||||
if err := t.Listen(*addr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -198,14 +187,16 @@ func MakeSwitch(
|
||||
sw.SetLogger(log.TestingLogger())
|
||||
sw.SetNodeKey(&nodeKey)
|
||||
|
||||
ni := nodeInfo.(DefaultNodeInfo)
|
||||
for ch := range sw.reactorsByCh {
|
||||
ni.Channels = append(ni.Channels, ch)
|
||||
}
|
||||
nodeInfo = ni
|
||||
|
||||
// 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.
|
||||
t.nodeInfo = ni
|
||||
sw.SetNodeInfo(ni)
|
||||
t.nodeInfo = nodeInfo
|
||||
sw.SetNodeInfo(nodeInfo)
|
||||
|
||||
return sw
|
||||
}
|
||||
@@ -215,7 +206,7 @@ func testInboundPeerConn(
|
||||
config *config.P2PConfig,
|
||||
ourNodePrivKey crypto.PrivKey,
|
||||
) (peerConn, error) {
|
||||
return testPeerConn(conn, config, false, false, ourNodePrivKey, nil)
|
||||
return testPeerConn(conn, config, false, false, ourNodePrivKey)
|
||||
}
|
||||
|
||||
func testPeerConn(
|
||||
@@ -223,7 +214,6 @@ func testPeerConn(
|
||||
cfg *config.P2PConfig,
|
||||
outbound, persistent bool,
|
||||
ourNodePrivKey crypto.PrivKey,
|
||||
originalAddr *NetAddress,
|
||||
) (pc peerConn, err error) {
|
||||
conn := rawConn
|
||||
|
||||
@@ -241,10 +231,27 @@ func testPeerConn(
|
||||
|
||||
// Only the information we already have
|
||||
return peerConn{
|
||||
config: cfg,
|
||||
outbound: outbound,
|
||||
persistent: persistent,
|
||||
conn: conn,
|
||||
originalAddr: originalAddr,
|
||||
config: cfg,
|
||||
outbound: outbound,
|
||||
persistent: persistent,
|
||||
conn: conn,
|
||||
}, 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)
|
||||
if err != nil {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
return nil, nil, ErrRejected{
|
||||
conn: c,
|
||||
err: fmt.Errorf("secrect conn failed: %v", err),
|
||||
isAuthFailure: true,
|
||||
@@ -344,15 +344,15 @@ func (mt *MultiplexTransport) upgrade(
|
||||
|
||||
nodeInfo, err = handshake(secretConn, mt.handshakeTimeout, mt.nodeInfo)
|
||||
if err != nil {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
return nil, nil, ErrRejected{
|
||||
conn: c,
|
||||
err: fmt.Errorf("handshake failed: %v", err),
|
||||
isAuthFailure: true,
|
||||
}
|
||||
}
|
||||
|
||||
if err := nodeInfo.Validate(); err != nil {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
if err := nodeInfo.ValidateBasic(); err != nil {
|
||||
return nil, nil, ErrRejected{
|
||||
conn: c,
|
||||
err: err,
|
||||
isNodeInfoInvalid: true,
|
||||
@@ -360,34 +360,34 @@ func (mt *MultiplexTransport) upgrade(
|
||||
}
|
||||
|
||||
// Ensure connection key matches self reported key.
|
||||
if connID := PubKeyToID(secretConn.RemotePubKey()); connID != nodeInfo.ID {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
if connID := PubKeyToID(secretConn.RemotePubKey()); connID != nodeInfo.ID() {
|
||||
return nil, nil, ErrRejected{
|
||||
conn: c,
|
||||
id: connID,
|
||||
err: fmt.Errorf(
|
||||
"conn.ID (%v) NodeInfo.ID (%v) missmatch",
|
||||
connID,
|
||||
nodeInfo.ID,
|
||||
nodeInfo.ID(),
|
||||
),
|
||||
isAuthFailure: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Reject self.
|
||||
if mt.nodeInfo.ID == nodeInfo.ID {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
addr: *NewNetAddress(nodeInfo.ID, c.RemoteAddr()),
|
||||
if mt.nodeInfo.ID() == nodeInfo.ID() {
|
||||
return nil, nil, ErrRejected{
|
||||
addr: *NewNetAddress(nodeInfo.ID(), c.RemoteAddr()),
|
||||
conn: c,
|
||||
id: nodeInfo.ID,
|
||||
id: nodeInfo.ID(),
|
||||
isSelf: true,
|
||||
}
|
||||
}
|
||||
|
||||
if err := mt.nodeInfo.CompatibleWith(nodeInfo); err != nil {
|
||||
return nil, NodeInfo{}, ErrRejected{
|
||||
return nil, nil, ErrRejected{
|
||||
conn: c,
|
||||
err: err,
|
||||
id: nodeInfo.ID,
|
||||
id: nodeInfo.ID(),
|
||||
isIncompatible: true,
|
||||
}
|
||||
}
|
||||
@@ -430,17 +430,18 @@ func handshake(
|
||||
nodeInfo NodeInfo,
|
||||
) (NodeInfo, error) {
|
||||
if err := c.SetDeadline(time.Now().Add(timeout)); err != nil {
|
||||
return NodeInfo{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
errc = make(chan error, 2)
|
||||
|
||||
peerNodeInfo NodeInfo
|
||||
peerNodeInfo DefaultNodeInfo
|
||||
ourNodeInfo = nodeInfo.(DefaultNodeInfo)
|
||||
)
|
||||
|
||||
go func(errc chan<- error, c net.Conn) {
|
||||
_, err := cdc.MarshalBinaryWriter(c, nodeInfo)
|
||||
_, err := cdc.MarshalBinaryWriter(c, ourNodeInfo)
|
||||
errc <- err
|
||||
}(errc, c)
|
||||
go func(errc chan<- error, c net.Conn) {
|
||||
@@ -455,7 +456,7 @@ func handshake(
|
||||
for i := 0; i < cap(errc); i++ {
|
||||
err := <-errc
|
||||
if err != nil {
|
||||
return NodeInfo{}, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,9 +11,15 @@ import (
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
)
|
||||
|
||||
var defaultNodeName = "host_peer"
|
||||
|
||||
func emptyNodeInfo() NodeInfo {
|
||||
return DefaultNodeInfo{}
|
||||
}
|
||||
|
||||
func TestTransportMultiplexConnFilter(t *testing.T) {
|
||||
mt := NewMultiplexTransport(
|
||||
NodeInfo{},
|
||||
emptyNodeInfo(),
|
||||
NodeKey{
|
||||
PrivKey: ed25519.GenPrivKey(),
|
||||
},
|
||||
@@ -70,7 +76,7 @@ func TestTransportMultiplexConnFilter(t *testing.T) {
|
||||
|
||||
func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
|
||||
mt := NewMultiplexTransport(
|
||||
NodeInfo{},
|
||||
emptyNodeInfo(),
|
||||
NodeKey{
|
||||
PrivKey: ed25519.GenPrivKey(),
|
||||
},
|
||||
@@ -120,6 +126,7 @@ func TestTransportMultiplexConnFilterTimeout(t *testing.T) {
|
||||
t.Errorf("expected ErrFilterTimeout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransportMultiplexAcceptMultiple(t *testing.T) {
|
||||
mt := testSetupMultiplexTransport(t)
|
||||
|
||||
@@ -134,12 +141,7 @@ func TestTransportMultiplexAcceptMultiple(t *testing.T) {
|
||||
var (
|
||||
pv = ed25519.GenPrivKey()
|
||||
dialer = NewMultiplexTransport(
|
||||
NodeInfo{
|
||||
ID: PubKeyToID(pv.PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "dialer",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
testNodeInfo(PubKeyToID(pv.PubKey()), defaultNodeName),
|
||||
NodeKey{
|
||||
PrivKey: pv,
|
||||
},
|
||||
@@ -207,15 +209,10 @@ func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
|
||||
|
||||
var (
|
||||
fastNodePV = ed25519.GenPrivKey()
|
||||
fastNodeInfo = NodeInfo{
|
||||
ID: PubKeyToID(fastNodePV.PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "fastNode",
|
||||
Version: "1.0.0",
|
||||
}
|
||||
errc = make(chan error)
|
||||
fastc = make(chan struct{})
|
||||
slowc = make(chan struct{})
|
||||
fastNodeInfo = testNodeInfo(PubKeyToID(fastNodePV.PubKey()), "fastnode")
|
||||
errc = make(chan error)
|
||||
fastc = make(chan struct{})
|
||||
slowc = make(chan struct{})
|
||||
)
|
||||
|
||||
// Simulate slow Peer.
|
||||
@@ -248,11 +245,11 @@ func TestTransportMultiplexAcceptNonBlocking(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = handshake(sc, 20*time.Millisecond, NodeInfo{
|
||||
ID: PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "slow_peer",
|
||||
})
|
||||
_, err = handshake(sc, 20*time.Millisecond,
|
||||
testNodeInfo(
|
||||
PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
||||
"slow_peer",
|
||||
))
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
@@ -311,12 +308,7 @@ func TestTransportMultiplexValidateNodeInfo(t *testing.T) {
|
||||
var (
|
||||
pv = ed25519.GenPrivKey()
|
||||
dialer = NewMultiplexTransport(
|
||||
NodeInfo{
|
||||
ID: PubKeyToID(pv.PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "", // Should not be empty.
|
||||
Version: "1.0.0",
|
||||
},
|
||||
testNodeInfo(PubKeyToID(pv.PubKey()), ""), // Should not be empty
|
||||
NodeKey{
|
||||
PrivKey: pv,
|
||||
},
|
||||
@@ -359,12 +351,9 @@ func TestTransportMultiplexRejectMissmatchID(t *testing.T) {
|
||||
|
||||
go func() {
|
||||
dialer := NewMultiplexTransport(
|
||||
NodeInfo{
|
||||
ID: PubKeyToID(ed25519.GenPrivKey().PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "dialer",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
testNodeInfo(
|
||||
PubKeyToID(ed25519.GenPrivKey().PubKey()), "dialer",
|
||||
),
|
||||
NodeKey{
|
||||
PrivKey: ed25519.GenPrivKey(),
|
||||
},
|
||||
@@ -408,12 +397,7 @@ func TestTransportMultiplexRejectIncompatible(t *testing.T) {
|
||||
var (
|
||||
pv = ed25519.GenPrivKey()
|
||||
dialer = NewMultiplexTransport(
|
||||
NodeInfo{
|
||||
ID: PubKeyToID(pv.PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "dialer",
|
||||
Version: "2.0.0",
|
||||
},
|
||||
testNodeInfoWithNetwork(PubKeyToID(pv.PubKey()), "dialer", "incompatible-network"),
|
||||
NodeKey{
|
||||
PrivKey: pv,
|
||||
},
|
||||
@@ -521,9 +505,7 @@ func TestTransportHandshake(t *testing.T) {
|
||||
|
||||
var (
|
||||
peerPV = ed25519.GenPrivKey()
|
||||
peerNodeInfo = NodeInfo{
|
||||
ID: PubKeyToID(peerPV.PubKey()),
|
||||
}
|
||||
peerNodeInfo = testNodeInfo(PubKeyToID(peerPV.PubKey()), defaultNodeName)
|
||||
)
|
||||
|
||||
go func() {
|
||||
@@ -534,13 +516,13 @@ func TestTransportHandshake(t *testing.T) {
|
||||
}
|
||||
|
||||
go func(c net.Conn) {
|
||||
_, err := cdc.MarshalBinaryWriter(c, peerNodeInfo)
|
||||
_, err := cdc.MarshalBinaryWriter(c, peerNodeInfo.(DefaultNodeInfo))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}(c)
|
||||
go func(c net.Conn) {
|
||||
ni := NodeInfo{}
|
||||
var ni DefaultNodeInfo
|
||||
|
||||
_, err := cdc.UnmarshalBinaryReader(
|
||||
c,
|
||||
@@ -558,7 +540,7 @@ func TestTransportHandshake(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ni, err := handshake(c, 20*time.Millisecond, NodeInfo{})
|
||||
ni, err := handshake(c, 20*time.Millisecond, emptyNodeInfo())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -572,12 +554,9 @@ func testSetupMultiplexTransport(t *testing.T) *MultiplexTransport {
|
||||
var (
|
||||
pv = ed25519.GenPrivKey()
|
||||
mt = NewMultiplexTransport(
|
||||
NodeInfo{
|
||||
ID: PubKeyToID(pv.PubKey()),
|
||||
ListenAddr: "127.0.0.1:0",
|
||||
Moniker: "transport",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
testNodeInfo(
|
||||
PubKeyToID(pv.PubKey()), "transport",
|
||||
),
|
||||
NodeKey{
|
||||
PrivKey: pv,
|
||||
},
|
||||
|
@@ -25,9 +25,9 @@ const (
|
||||
|
||||
func voteToStep(vote *types.Vote) int8 {
|
||||
switch vote.Type {
|
||||
case types.VoteTypePrevote:
|
||||
case types.PrevoteType:
|
||||
return stepPrevote
|
||||
case types.VoteTypePrecommit:
|
||||
case types.PrecommitType:
|
||||
return stepPrecommit
|
||||
default:
|
||||
cmn.PanicSanity("Unknown vote type")
|
||||
|
@@ -101,7 +101,7 @@ func TestSignVote(t *testing.T) {
|
||||
block1 := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
||||
block2 := types.BlockID{[]byte{3, 2, 1}, types.PartSetHeader{}}
|
||||
height, round := int64(10), 1
|
||||
voteType := types.VoteTypePrevote
|
||||
voteType := byte(types.PrevoteType)
|
||||
|
||||
// sign a vote for first time
|
||||
vote := newVote(privVal.Address, 0, height, round, voteType, block1)
|
||||
@@ -206,7 +206,7 @@ func TestDifferByTimestamp(t *testing.T) {
|
||||
|
||||
// test vote
|
||||
{
|
||||
voteType := types.VoteTypePrevote
|
||||
voteType := byte(types.PrevoteType)
|
||||
blockID := types.BlockID{[]byte{1, 2, 3}, types.PartSetHeader{}}
|
||||
vote := newVote(privVal.Address, 0, height, round, voteType, blockID)
|
||||
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,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: typ,
|
||||
Type: types.SignedMsgType(typ),
|
||||
Timestamp: tmtime.Now(),
|
||||
BlockID: blockID,
|
||||
}
|
||||
|
@@ -79,7 +79,7 @@ func TestSocketPVVote(t *testing.T) {
|
||||
sc, rs = testSetupSocketPair(t, chainID, types.NewMockPV())
|
||||
|
||||
ts = time.Now()
|
||||
vType = types.VoteTypePrecommit
|
||||
vType = types.PrecommitType
|
||||
want = &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())
|
||||
|
||||
ts = time.Now()
|
||||
vType = types.VoteTypePrecommit
|
||||
vType = types.PrecommitType
|
||||
vote = &types.Vote{Timestamp: ts, Type: vType}
|
||||
)
|
||||
defer sc.Stop()
|
||||
|
@@ -2,7 +2,6 @@ package core
|
||||
|
||||
import (
|
||||
cm "github.com/tendermint/tendermint/consensus"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -201,7 +200,7 @@ func DumpConsensusState() (*ctypes.ResultDumpConsensusState, error) {
|
||||
}
|
||||
peerStates[i] = ctypes.PeerStateInfo{
|
||||
// Peer basic info.
|
||||
NodeAddress: p2p.IDAddressString(peer.ID(), peer.NodeInfo().ListenAddr),
|
||||
NodeAddress: peer.NodeInfo().NetAddress().String(),
|
||||
// Peer consensus state.
|
||||
PeerState: peerStateJSON,
|
||||
}
|
||||
|
@@ -1,8 +1,11 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
)
|
||||
|
||||
@@ -37,8 +40,12 @@ import (
|
||||
func NetInfo() (*ctypes.ResultNetInfo, error) {
|
||||
peers := []ctypes.Peer{}
|
||||
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{
|
||||
NodeInfo: peer.NodeInfo(),
|
||||
NodeInfo: nodeInfo,
|
||||
IsOutbound: peer.IsOutbound(),
|
||||
ConnectionStatus: peer.Status(),
|
||||
})
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"time"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -91,7 +92,7 @@ func Status() (*ctypes.ResultStatus, error) {
|
||||
}
|
||||
|
||||
result := &ctypes.ResultStatus{
|
||||
NodeInfo: p2pTransport.NodeInfo(),
|
||||
NodeInfo: p2pTransport.NodeInfo().(p2p.DefaultNodeInfo),
|
||||
SyncInfo: ctypes.SyncInfo{
|
||||
LatestBlockHash: latestBlockHash,
|
||||
LatestAppHash: latestAppHash,
|
||||
|
@@ -74,9 +74,9 @@ type ValidatorInfo struct {
|
||||
|
||||
// Node Status
|
||||
type ResultStatus struct {
|
||||
NodeInfo p2p.NodeInfo `json:"node_info"`
|
||||
SyncInfo SyncInfo `json:"sync_info"`
|
||||
ValidatorInfo ValidatorInfo `json:"validator_info"`
|
||||
NodeInfo p2p.DefaultNodeInfo `json:"node_info"`
|
||||
SyncInfo SyncInfo `json:"sync_info"`
|
||||
ValidatorInfo ValidatorInfo `json:"validator_info"`
|
||||
}
|
||||
|
||||
// Is TxIndexing enabled
|
||||
@@ -107,7 +107,7 @@ type ResultDialPeers struct {
|
||||
|
||||
// A peer
|
||||
type Peer struct {
|
||||
p2p.NodeInfo `json:"node_info"`
|
||||
NodeInfo p2p.DefaultNodeInfo `json:"node_info"`
|
||||
IsOutbound bool `json:"is_outbound"`
|
||||
ConnectionStatus p2p.ConnectionStatus `json:"connection_status"`
|
||||
}
|
||||
|
@@ -15,17 +15,17 @@ func TestStatusIndexer(t *testing.T) {
|
||||
status = &ResultStatus{}
|
||||
assert.False(t, status.TxIndexEnabled())
|
||||
|
||||
status.NodeInfo = p2p.NodeInfo{}
|
||||
status.NodeInfo = p2p.DefaultNodeInfo{}
|
||||
assert.False(t, status.TxIndexEnabled())
|
||||
|
||||
cases := []struct {
|
||||
expected bool
|
||||
other p2p.NodeInfoOther
|
||||
other p2p.DefaultNodeInfoOther
|
||||
}{
|
||||
{false, p2p.NodeInfoOther{}},
|
||||
{false, p2p.NodeInfoOther{TxIndex: "aa"}},
|
||||
{false, p2p.NodeInfoOther{TxIndex: "off"}},
|
||||
{true, p2p.NodeInfoOther{TxIndex: "on"}},
|
||||
{false, p2p.DefaultNodeInfoOther{}},
|
||||
{false, p2p.DefaultNodeInfoOther{TxIndex: "aa"}},
|
||||
{false, p2p.DefaultNodeInfoOther{TxIndex: "off"}},
|
||||
{true, p2p.DefaultNodeInfoOther{TxIndex: "on"}},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
@@ -49,7 +49,7 @@ func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
|
||||
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
|
||||
// Call SetEventBus to provide one.
|
||||
func NewBlockExecutor(db dbm.DB, logger log.Logger, proxyApp proxy.AppConnConsensus,
|
||||
mempool Mempool, evpool EvidencePool, options ...BlockExecutorOption) *BlockExecutor {
|
||||
mempool Mempool, evpool EvidencePool, options ...BlockExecutorOption) *BlockExecutor {
|
||||
res := &BlockExecutor{
|
||||
db: db,
|
||||
proxyApp: proxyApp,
|
||||
@@ -95,7 +95,7 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b
|
||||
startTime := time.Now().UnixNano()
|
||||
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db)
|
||||
endTime := time.Now().UnixNano()
|
||||
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime - startTime) / 1000000)
|
||||
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
|
||||
if err != nil {
|
||||
return state, ErrProxyAppConn(err)
|
||||
}
|
||||
@@ -198,11 +198,11 @@ func (blockExec *BlockExecutor) Commit(
|
||||
// Executes block's transactions on proxyAppConn.
|
||||
// Returns a list of transaction results and updates to the validator set
|
||||
func execBlockOnProxyApp(
|
||||
logger log.Logger,
|
||||
proxyAppConn proxy.AppConnConsensus,
|
||||
block *types.Block,
|
||||
lastValSet *types.ValidatorSet,
|
||||
stateDB dbm.DB,
|
||||
logger log.Logger,
|
||||
proxyAppConn proxy.AppConnConsensus,
|
||||
block *types.Block,
|
||||
lastValSet *types.ValidatorSet,
|
||||
stateDB dbm.DB,
|
||||
) (*ABCIResponses, error) {
|
||||
var validTxs, invalidTxs = 0, 0
|
||||
|
||||
@@ -360,10 +360,10 @@ func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.Validat
|
||||
|
||||
// updateState returns a new State updated according to the header and responses.
|
||||
func updateState(
|
||||
state State,
|
||||
blockID types.BlockID,
|
||||
header *types.Header,
|
||||
abciResponses *ABCIResponses,
|
||||
state State,
|
||||
blockID types.BlockID,
|
||||
header *types.Header,
|
||||
abciResponses *ABCIResponses,
|
||||
) (State, error) {
|
||||
|
||||
// Copy the valset so we can apply changes from EndBlock
|
||||
@@ -448,11 +448,11 @@ func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *ty
|
||||
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
|
||||
// It returns the application root hash (result of abci.Commit).
|
||||
func ExecCommitBlock(
|
||||
appConnConsensus proxy.AppConnConsensus,
|
||||
block *types.Block,
|
||||
logger log.Logger,
|
||||
lastValSet *types.ValidatorSet,
|
||||
stateDB dbm.DB,
|
||||
appConnConsensus proxy.AppConnConsensus,
|
||||
block *types.Block,
|
||||
logger log.Logger,
|
||||
lastValSet *types.ValidatorSet,
|
||||
stateDB dbm.DB,
|
||||
) ([]byte, error) {
|
||||
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, lastValSet, stateDB)
|
||||
if err != nil {
|
||||
|
@@ -64,7 +64,7 @@ func TestBeginBlockValidators(t *testing.T) {
|
||||
prevBlockID := types.BlockID{prevHash, prevParts}
|
||||
|
||||
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}
|
||||
|
||||
testCases := []struct {
|
||||
@@ -135,7 +135,7 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
|
||||
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}
|
||||
votes := []*types.Vote{vote0, vote1}
|
||||
lastCommit := &types.Commit{BlockID: prevBlockID, Precommits: votes}
|
||||
|
@@ -2,9 +2,9 @@ package state
|
||||
|
||||
import (
|
||||
"github.com/go-kit/kit/metrics"
|
||||
"github.com/go-kit/kit/metrics/discard"
|
||||
"github.com/go-kit/kit/metrics/prometheus"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/go-kit/kit/metrics/discard"
|
||||
)
|
||||
|
||||
const MetricsSubsystem = "state"
|
||||
|
@@ -388,7 +388,7 @@ func (commit *Commit) FirstPrecommit() *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
|
||||
func (commit *Commit) Type() byte {
|
||||
return VoteTypePrecommit
|
||||
return byte(PrecommitType)
|
||||
}
|
||||
|
||||
// Size returns the number of votes in the commit
|
||||
@@ -462,7 +462,7 @@ func (commit *Commit) ValidateBasic() error {
|
||||
continue
|
||||
}
|
||||
// Ensure that all votes are precommits.
|
||||
if precommit.Type != VoteTypePrecommit {
|
||||
if precommit.Type != PrecommitType {
|
||||
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
|
||||
precommit.Type)
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ func TestBlockAddEvidence(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -46,7 +46,7 @@ func TestBlockValidateBasic(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -106,7 +106,7 @@ func TestBlockMakePartSetWithEvidence(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -123,7 +123,7 @@ func TestBlockHashesTo(t *testing.T) {
|
||||
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -190,14 +190,14 @@ func TestNilDataHashDoesntCrash(t *testing.T) {
|
||||
func TestCommit(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, commit.FirstPrecommit())
|
||||
assert.Equal(t, h-1, commit.Height())
|
||||
assert.Equal(t, 1, commit.Round())
|
||||
assert.Equal(t, VoteTypePrecommit, commit.Type())
|
||||
assert.Equal(t, PrecommitType, SignedMsgType(commit.Type()))
|
||||
if commit.Size() <= 0 {
|
||||
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},
|
||||
{"Nil precommit", func(com *Commit) { com.Precommits[0] = nil }, 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 round", func(com *Commit) { com.Precommits[0].Round = 100 }, true},
|
||||
}
|
||||
@@ -268,7 +268,7 @@ func TestMaxHeaderBytes(t *testing.T) {
|
||||
func randCommit() *Commit {
|
||||
lastID := makeBlockIDRandom()
|
||||
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)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@@ -13,44 +13,46 @@ import (
|
||||
const TimeFormat = time.RFC3339Nano
|
||||
|
||||
type CanonicalBlockID struct {
|
||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
||||
PartsHeader CanonicalPartSetHeader `json:"parts,omitempty"`
|
||||
Hash cmn.HexBytes
|
||||
PartsHeader CanonicalPartSetHeader
|
||||
}
|
||||
|
||||
type CanonicalPartSetHeader struct {
|
||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
||||
Total int `json:"total,omitempty"`
|
||||
Hash cmn.HexBytes
|
||||
Total int
|
||||
}
|
||||
|
||||
type CanonicalProposal struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
BlockPartsHeader CanonicalPartSetHeader `json:"block_parts_header"`
|
||||
Height int64 `json:"height"`
|
||||
POLBlockID CanonicalBlockID `json:"pol_block_id"`
|
||||
POLRound int `json:"pol_round"`
|
||||
Round int `json:"round"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Version uint64 `binary:"fixed64"`
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
Type SignedMsgType // type alias for byte
|
||||
POLRound int64 `binary:"fixed64"`
|
||||
Timestamp time.Time
|
||||
BlockPartsHeader CanonicalPartSetHeader
|
||||
POLBlockID CanonicalBlockID
|
||||
ChainID string
|
||||
}
|
||||
|
||||
type CanonicalVote struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
BlockID CanonicalBlockID `json:"block_id"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
VoteType byte `json:"type"`
|
||||
Version uint64 `binary:"fixed64"`
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int64 `binary:"fixed64"`
|
||||
Type SignedMsgType // type alias for byte
|
||||
Timestamp time.Time
|
||||
BlockID CanonicalBlockID
|
||||
ChainID string
|
||||
}
|
||||
|
||||
type CanonicalHeartbeat struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Sequence int `json:"sequence"`
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
Version uint64 `binary:"fixed64"`
|
||||
Height int64 `binary:"fixed64"`
|
||||
Round int `binary:"fixed64"`
|
||||
Type byte
|
||||
Sequence int `binary:"fixed64"`
|
||||
ValidatorAddress Address
|
||||
ValidatorIndex int
|
||||
ChainID string
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
@@ -72,38 +74,40 @@ func CanonicalizePartSetHeader(psh PartSetHeader) CanonicalPartSetHeader {
|
||||
|
||||
func CanonicalizeProposal(chainID string, proposal *Proposal) CanonicalProposal {
|
||||
return CanonicalProposal{
|
||||
ChainID: chainID,
|
||||
Type: "proposal",
|
||||
BlockPartsHeader: CanonicalizePartSetHeader(proposal.BlockPartsHeader),
|
||||
Version: 0, // TODO
|
||||
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,
|
||||
BlockPartsHeader: CanonicalizePartSetHeader(proposal.BlockPartsHeader),
|
||||
POLBlockID: CanonicalizeBlockID(proposal.POLBlockID),
|
||||
POLRound: proposal.POLRound,
|
||||
Round: proposal.Round,
|
||||
ChainID: chainID,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalizeVote(chainID string, vote *Vote) CanonicalVote {
|
||||
return CanonicalVote{
|
||||
ChainID: chainID,
|
||||
Type: "vote",
|
||||
BlockID: CanonicalizeBlockID(vote.BlockID),
|
||||
Version: 0, // TODO
|
||||
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,
|
||||
VoteType: vote.Type,
|
||||
BlockID: CanonicalizeBlockID(vote.BlockID),
|
||||
ChainID: chainID,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalizeHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalHeartbeat {
|
||||
return CanonicalHeartbeat{
|
||||
ChainID: chainID,
|
||||
Type: "heartbeat",
|
||||
Version: 0, // TODO
|
||||
Height: heartbeat.Height,
|
||||
Round: heartbeat.Round,
|
||||
Type: byte(HeartbeatType),
|
||||
Sequence: heartbeat.Sequence,
|
||||
ValidatorAddress: heartbeat.ValidatorAddress,
|
||||
ValidatorIndex: heartbeat.ValidatorIndex,
|
||||
ChainID: chainID,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@ func makeVote(val PrivValidator, chainID string, valIndex int, height int64, rou
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: byte(step),
|
||||
Type: SignedMsgType(step),
|
||||
BlockID: blockID,
|
||||
}
|
||||
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,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: VoteTypePrecommit,
|
||||
Type: PrecommitType,
|
||||
BlockID: blockID,
|
||||
Timestamp: tmtime.Now(),
|
||||
}
|
||||
|
@@ -282,7 +282,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
|
||||
if precommit.Round != 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)
|
||||
}
|
||||
_, val := vals.GetByIndex(idx)
|
||||
@@ -361,7 +361,7 @@ func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID strin
|
||||
if precommit.Round != 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)
|
||||
}
|
||||
// See if this validator is in oldVals.
|
||||
|
@@ -385,7 +385,7 @@ func TestValidatorSetVerifyCommit(t *testing.T) {
|
||||
Height: height,
|
||||
Round: 0,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrecommit,
|
||||
Type: PrecommitType,
|
||||
BlockID: blockID,
|
||||
}
|
||||
sig, err := privKey.Sign(vote.SignBytes(chainID))
|
||||
|
@@ -43,37 +43,19 @@ 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.
|
||||
type Address = crypto.Address
|
||||
|
||||
// Represents a prevote, precommit, or commit vote from validators for consensus.
|
||||
type Vote struct {
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Type byte `json:"type"`
|
||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||
Signature []byte `json:"signature"`
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Type SignedMsgType `json:"type"`
|
||||
BlockID BlockID `json:"block_id"` // zero if vote is nil.
|
||||
Signature []byte `json:"signature"`
|
||||
}
|
||||
|
||||
func (vote *Vote) SignBytes(chainID string) []byte {
|
||||
@@ -95,9 +77,9 @@ func (vote *Vote) String() string {
|
||||
}
|
||||
var typeString string
|
||||
switch vote.Type {
|
||||
case VoteTypePrevote:
|
||||
case PrevoteType:
|
||||
typeString = "Prevote"
|
||||
case VoteTypePrecommit:
|
||||
case PrecommitType:
|
||||
typeString = "Precommit"
|
||||
default:
|
||||
cmn.PanicSanity("Unknown vote type")
|
||||
|
@@ -55,7 +55,7 @@ type VoteSet struct {
|
||||
chainID string
|
||||
height int64
|
||||
round int
|
||||
type_ byte
|
||||
type_ SignedMsgType
|
||||
valSet *ValidatorSet
|
||||
|
||||
mtx sync.Mutex
|
||||
@@ -68,7 +68,7 @@ type VoteSet struct {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
cmn.PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.")
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func (voteSet *VoteSet) Type() byte {
|
||||
if voteSet == nil {
|
||||
return 0x00
|
||||
}
|
||||
return voteSet.type_
|
||||
return byte(voteSet.type_)
|
||||
}
|
||||
|
||||
func (voteSet *VoteSet) Size() int {
|
||||
@@ -381,7 +381,7 @@ func (voteSet *VoteSet) IsCommit() bool {
|
||||
if voteSet == nil {
|
||||
return false
|
||||
}
|
||||
if voteSet.type_ != VoteTypePrecommit {
|
||||
if voteSet.type_ != PrecommitType {
|
||||
return false
|
||||
}
|
||||
voteSet.mtx.Lock()
|
||||
@@ -529,8 +529,8 @@ func (voteSet *VoteSet) sumTotalFrac() (int64, int64, float64) {
|
||||
// Commit
|
||||
|
||||
func (voteSet *VoteSet) MakeCommit() *Commit {
|
||||
if voteSet.type_ != VoteTypePrecommit {
|
||||
cmn.PanicSanity("Cannot MakeCommit() unless VoteSet.Type is VoteTypePrecommit")
|
||||
if voteSet.type_ != PrecommitType {
|
||||
cmn.PanicSanity("Cannot MakeCommit() unless VoteSet.Type is PrecommitType")
|
||||
}
|
||||
voteSet.mtx.Lock()
|
||||
defer voteSet.mtx.Unlock()
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// 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)
|
||||
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
|
||||
func withType(vote *Vote, type_ byte) *Vote {
|
||||
vote = vote.Copy()
|
||||
vote.Type = type_
|
||||
vote.Type = SignedMsgType(type_)
|
||||
return vote
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func withBlockPartsHeader(vote *Vote, blockPartsHeader PartSetHeader) *Vote {
|
||||
|
||||
func TestAddVote(t *testing.T) {
|
||||
height, round := int64(1), 0
|
||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
||||
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||
val0 := privValidators[0]
|
||||
|
||||
// t.Logf(">> %v", voteSet)
|
||||
@@ -82,7 +82,7 @@ func TestAddVote(t *testing.T) {
|
||||
ValidatorIndex: 0, // since privValidators are in order
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
Timestamp: tmtime.Now(),
|
||||
BlockID: BlockID{nil, PartSetHeader{}},
|
||||
}
|
||||
@@ -105,14 +105,14 @@ func TestAddVote(t *testing.T) {
|
||||
|
||||
func Test2_3Majority(t *testing.T) {
|
||||
height, round := int64(1), 0
|
||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
||||
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||
|
||||
voteProto := &Vote{
|
||||
ValidatorAddress: nil, // NOTE: must fill in
|
||||
ValidatorIndex: -1, // NOTE: must fill in
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
Timestamp: tmtime.Now(),
|
||||
BlockID: BlockID{nil, PartSetHeader{}},
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func Test2_3Majority(t *testing.T) {
|
||||
|
||||
func Test2_3MajorityRedux(t *testing.T) {
|
||||
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)
|
||||
blockPartsTotal := 123
|
||||
@@ -170,7 +170,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
Height: height,
|
||||
Round: round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
BlockID: BlockID{blockHash, blockPartsHeader},
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||
|
||||
func TestBadVotes(t *testing.T) {
|
||||
height, round := int64(1), 0
|
||||
voteSet, _, privValidators := randVoteSet(height, round, VoteTypePrevote, 10, 1)
|
||||
voteSet, _, privValidators := randVoteSet(height, round, PrevoteType, 10, 1)
|
||||
|
||||
voteProto := &Vote{
|
||||
ValidatorAddress: nil,
|
||||
@@ -265,7 +265,7 @@ func TestBadVotes(t *testing.T) {
|
||||
Height: height,
|
||||
Round: round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
BlockID: BlockID{nil, PartSetHeader{}},
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ func TestBadVotes(t *testing.T) {
|
||||
// val3 votes of another type.
|
||||
{
|
||||
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 {
|
||||
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
||||
}
|
||||
@@ -317,7 +317,7 @@ func TestBadVotes(t *testing.T) {
|
||||
|
||||
func TestConflicts(t *testing.T) {
|
||||
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)
|
||||
blockHash2 := cmn.RandBytes(32)
|
||||
|
||||
@@ -327,7 +327,7 @@ func TestConflicts(t *testing.T) {
|
||||
Height: height,
|
||||
Round: round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
BlockID: BlockID{nil, PartSetHeader{}},
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ func TestConflicts(t *testing.T) {
|
||||
|
||||
func TestMakeCommit(t *testing.T) {
|
||||
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)}
|
||||
|
||||
voteProto := &Vote{
|
||||
@@ -456,7 +456,7 @@ func TestMakeCommit(t *testing.T) {
|
||||
Height: height,
|
||||
Round: round,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrecommit,
|
||||
Type: PrecommitType,
|
||||
BlockID: BlockID{blockHash, blockPartsHeader},
|
||||
}
|
||||
|
||||
|
@@ -13,11 +13,11 @@ import (
|
||||
)
|
||||
|
||||
func examplePrevote() *Vote {
|
||||
return exampleVote(VoteTypePrevote)
|
||||
return exampleVote(byte(PrevoteType))
|
||||
}
|
||||
|
||||
func examplePrecommit() *Vote {
|
||||
return exampleVote(VoteTypePrecommit)
|
||||
return exampleVote(byte(PrecommitType))
|
||||
}
|
||||
|
||||
func exampleVote(t byte) *Vote {
|
||||
@@ -32,7 +32,7 @@ func exampleVote(t byte) *Vote {
|
||||
Height: 12345,
|
||||
Round: 2,
|
||||
Timestamp: stamp,
|
||||
Type: t,
|
||||
Type: SignedMsgType(t),
|
||||
BlockID: BlockID{
|
||||
Hash: tmhash.Sum([]byte("blockID_hash")),
|
||||
PartsHeader: PartSetHeader{
|
||||
@@ -53,6 +53,98 @@ func TestVoteSignable(t *testing.T) {
|
||||
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) {
|
||||
privVal := NewMockPV()
|
||||
pubkey := privVal.GetPubKey()
|
||||
@@ -85,12 +177,12 @@ func TestVoteVerifySignature(t *testing.T) {
|
||||
func TestIsVoteTypeValid(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
in byte
|
||||
in SignedMsgType
|
||||
out bool
|
||||
}{
|
||||
{"Prevote", VoteTypePrevote, true},
|
||||
{"Precommit", VoteTypePrecommit, true},
|
||||
{"InvalidType", byte(3), false},
|
||||
{"Prevote", PrevoteType, true},
|
||||
{"Precommit", PrecommitType, true},
|
||||
{"InvalidType", SignedMsgType(0x3), false},
|
||||
}
|
||||
|
||||
for _, tt := range tc {
|
||||
@@ -128,7 +220,7 @@ func TestMaxVoteBytes(t *testing.T) {
|
||||
Height: math.MaxInt64,
|
||||
Round: math.MaxInt64,
|
||||
Timestamp: tmtime.Now(),
|
||||
Type: VoteTypePrevote,
|
||||
Type: PrevoteType,
|
||||
BlockID: BlockID{
|
||||
Hash: tmhash.Sum([]byte("blockID_hash")),
|
||||
PartsHeader: PartSetHeader{
|
||||
|
Reference in New Issue
Block a user