Unverified Commit 7ea03fb2 authored by vipwzw's avatar vipwzw Committed by GitHub

Merge pull request #674 from caopingcp/issue615_tendermint

tendermint save local state
parents a413a97a 152ba70e
...@@ -83,13 +83,13 @@ powLimitBits = "0x1f2fffff" ...@@ -83,13 +83,13 @@ powLimitBits = "0x1f2fffff"
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394 genesisBlockTime=1514533394
timeoutTxAvail=1000 timeoutTxAvail=1000
timeoutPropose=3000 timeoutPropose=1000
timeoutProposeDelta=500 timeoutProposeDelta=500
timeoutPrevote=1000 timeoutPrevote=1000
timeoutPrevoteDelta=500 timeoutPrevoteDelta=500
timeoutPrecommit=1000 timeoutPrecommit=1000
timeoutPrecommitDelta=500 timeoutPrecommitDelta=500
timeoutCommit=1000 timeoutCommit=500
skipTimeoutCommit=false skipTimeoutCommit=false
createEmptyBlocks=false createEmptyBlocks=false
createEmptyBlocksInterval=0 createEmptyBlocksInterval=0
......
This diff is collapsed.
...@@ -21,16 +21,14 @@ import ( ...@@ -21,16 +21,14 @@ import (
// BlockExecutor provides the context and accessories for properly executing a block. // BlockExecutor provides the context and accessories for properly executing a block.
type BlockExecutor struct { type BlockExecutor struct {
// save state, validators, consensus params, abci responses here // save state, validators, consensus params, abci responses here
db *CSStateDB db *CSStateDB
evpool ttypes.EvidencePool
} }
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus. // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
// Call SetEventBus to provide one. // Call SetEventBus to provide one.
func NewBlockExecutor(db *CSStateDB, evpool ttypes.EvidencePool) *BlockExecutor { func NewBlockExecutor(db *CSStateDB) *BlockExecutor {
return &BlockExecutor{ return &BlockExecutor{
db: db, db: db,
evpool: evpool,
} }
} }
...@@ -59,12 +57,6 @@ func (blockExec *BlockExecutor) ApplyBlock(s State, blockID ttypes.BlockID, bloc ...@@ -59,12 +57,6 @@ func (blockExec *BlockExecutor) ApplyBlock(s State, blockID ttypes.BlockID, bloc
} }
blockExec.db.SaveState(s) blockExec.db.SaveState(s)
// Update evpool now that state is saved
// TODO: handle the crash/recover scenario
// ie. (may need to call Update for last block)
blockExec.evpool.Update(block)
return s, nil return s, nil
} }
...@@ -191,7 +183,10 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *ttypes.ValidatorSet, u ...@@ -191,7 +183,10 @@ func changeInVotingPowerMoreOrEqualToOneThird(currentSet *ttypes.ValidatorSet, u
} }
func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error { func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error {
newTxs := b.Header.NumTxs // Validate internal consistency.
if err := b.ValidateBasic(); err != nil {
return err
}
// validate basic info // validate basic info
if b.Header.ChainID != s.ChainID { if b.Header.ChainID != s.ChainID {
...@@ -206,6 +201,7 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error ...@@ -206,6 +201,7 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error
return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.Header.LastBlockID) return fmt.Errorf("Wrong Block.Header.LastBlockID. Expected %v, got %v", s.LastBlockID, b.Header.LastBlockID)
} }
newTxs := b.Header.NumTxs
if b.Header.TotalTxs != s.LastBlockTotalTx+newTxs { if b.Header.TotalTxs != s.LastBlockTotalTx+newTxs {
return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.Header.TotalTxs) return fmt.Errorf("Wrong Block.Header.TotalTxs. Expected %v, got %v", s.LastBlockTotalTx+newTxs, b.Header.TotalTxs)
} }
...@@ -242,13 +238,5 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error ...@@ -242,13 +238,5 @@ func validateBlock(stateDB *CSStateDB, s State, b *ttypes.TendermintBlock) error
} }
} }
for _, ev := range b.Evidence.Evidence {
evidence := ttypes.EvidenceEnvelope2Evidence(ev)
if evidence != nil {
if err := VerifyEvidence(stateDB, s, evidence); err != nil {
return ttypes.NewEvidenceInvalidErr(evidence, err)
}
}
}
return nil return nil
} }
...@@ -17,8 +17,6 @@ import ( ...@@ -17,8 +17,6 @@ import (
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types" ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/golang/protobuf/proto"
) )
const ( const (
...@@ -44,8 +42,6 @@ const ( ...@@ -44,8 +42,6 @@ const (
minReadBufferSize = 1024 minReadBufferSize = 1024
minWriteBufferSize = 65536 minWriteBufferSize = 65536
broadcastEvidenceIntervalS = 60 // broadcast uncommitted evidence this often
) )
// Parallel method // Parallel method
...@@ -132,7 +128,6 @@ type Node struct { ...@@ -132,7 +128,6 @@ type Node struct {
lAddr string lAddr string
state *ConsensusState state *ConsensusState
evpool *EvidencePool
broadcastChannel chan MsgInfo broadcastChannel chan MsgInfo
started uint32 // atomic started uint32 // atomic
stopped uint32 // atomic stopped uint32 // atomic
...@@ -140,7 +135,7 @@ type Node struct { ...@@ -140,7 +135,7 @@ type Node struct {
} }
// NewNode method // NewNode method
func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState, evpool *EvidencePool) *Node { func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState) *Node {
address := GenAddressByPubKey(privKey.PubKey()) address := GenAddressByPubKey(privKey.PubKey())
node := &Node{ node := &Node{
...@@ -158,7 +153,6 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK ...@@ -158,7 +153,6 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK
reconnecting: NewMutexMap(), reconnecting: NewMutexMap(),
broadcastChannel: make(chan MsgInfo, maxSendQueueSize), broadcastChannel: make(chan MsgInfo, maxSendQueueSize),
state: state, state: state,
evpool: evpool,
localIPs: make(map[string]net.IP), localIPs: make(map[string]net.IP),
} }
...@@ -219,7 +213,6 @@ func (node *Node) Start() { ...@@ -219,7 +213,6 @@ func (node *Node) Start() {
go node.StartConsensusRoutine() go node.StartConsensusRoutine()
go node.BroadcastRoutine() go node.BroadcastRoutine()
go node.evidenceBroadcastRoutine()
} }
} }
...@@ -234,7 +227,7 @@ func (node *Node) DialPeerWithAddress(addr string) error { ...@@ -234,7 +227,7 @@ func (node *Node) DialPeerWithAddress(addr string) error {
func (node *Node) addOutboundPeerWithConfig(addr string) error { func (node *Node) addOutboundPeerWithConfig(addr string) error {
tendermintlog.Info("Dialing peer", "address", addr) tendermintlog.Info("Dialing peer", "address", addr)
peerConn, err := newOutboundPeerConn(addr, node.privKey, node.StopPeerForError, node.state, node.evpool) peerConn, err := newOutboundPeerConn(addr, node.privKey, node.StopPeerForError, node.state)
if err != nil { if err != nil {
go node.reconnectToPeer(addr) go node.reconnectToPeer(addr)
return err return err
...@@ -307,66 +300,6 @@ func (node *Node) StartConsensusRoutine() { ...@@ -307,66 +300,6 @@ func (node *Node) StartConsensusRoutine() {
} }
} }
func (node *Node) evidenceBroadcastRoutine() {
ticker := time.NewTicker(time.Second * broadcastEvidenceIntervalS)
for {
select {
case evidence := <-node.evpool.EvidenceChan():
// broadcast some new evidence
data, err := proto.Marshal(evidence.Child())
if err != nil {
msg := MsgInfo{TypeID: ttypes.EvidenceListID,
Msg: &tmtypes.EvidenceData{
Evidence: []*tmtypes.EvidenceEnvelope{
{
TypeName: evidence.TypeName(),
Data: data,
},
},
},
PeerID: node.ID, PeerIP: node.IP,
}
node.Broadcast(msg)
// TODO: Broadcast runs asynchronously, so this should wait on the successChan
// in another routine before marking to be proper.
node.evpool.evidenceStore.MarkEvidenceAsBroadcasted(evidence)
}
case <-ticker.C:
// broadcast all pending evidence
var eData tmtypes.EvidenceData
evidence := node.evpool.PendingEvidence()
for _, item := range evidence {
ev := item.Child()
if ev != nil {
data, err := proto.Marshal(ev)
if err != nil {
panic("AddEvidence marshal failed")
}
env := &tmtypes.EvidenceEnvelope{
TypeName: item.TypeName(),
Data: data,
}
eData.Evidence = append(eData.Evidence, env)
}
}
msg := MsgInfo{TypeID: ttypes.EvidenceListID,
Msg: &eData,
PeerID: node.ID,
PeerIP: node.IP,
}
node.Broadcast(msg)
case _, ok := <-node.quit:
if !ok {
node.quit = nil
tendermintlog.Info("evidenceBroadcastRoutine quit")
return
}
}
}
}
// BroadcastRoutine receive to broadcast // BroadcastRoutine receive to broadcast
func (node *Node) BroadcastRoutine() { func (node *Node) BroadcastRoutine() {
for { for {
...@@ -413,7 +346,7 @@ func (node *Node) StopPeerForError(peer Peer, reason interface{}) { ...@@ -413,7 +346,7 @@ func (node *Node) StopPeerForError(peer Peer, reason interface{}) {
} }
func (node *Node) addInboundPeer(conn net.Conn) error { func (node *Node) addInboundPeer(conn net.Conn) error {
peerConn, err := newInboundPeerConn(conn, node.privKey, node.StopPeerForError, node.state, node.evpool) peerConn, err := newInboundPeerConn(conn, node.privKey, node.StopPeerForError, node.state)
if err != nil { if err != nil {
if er := conn.Close(); er != nil { if er := conn.Close(); er != nil {
tendermintlog.Error("addInboundPeer close conn failed", "er", er) tendermintlog.Error("addInboundPeer close conn failed", "er", er)
...@@ -481,11 +414,6 @@ func (node *Node) addPeer(pc *peerConn) error { ...@@ -481,11 +414,6 @@ func (node *Node) addPeer(pc *peerConn) error {
return fmt.Errorf("get remote ip failed:%v", rErr) return fmt.Errorf("get remote ip failed:%v", rErr)
} }
// Filter peer against ID white list
//if err := node.FilterConnByID(peerID); err != nil {
//return err
//}
// Check version, chain id // Check version, chain id
if err := node.CompatibleWith(peerNodeInfo); err != nil { if err := node.CompatibleWith(peerNodeInfo); err != nil {
return err return err
...@@ -507,7 +435,6 @@ func (node *Node) addPeer(pc *peerConn) error { ...@@ -507,7 +435,6 @@ func (node *Node) addPeer(pc *peerConn) error {
if err := node.peerSet.Add(pc); err != nil { if err := node.peerSet.Add(pc); err != nil {
return err return err
} }
//node.metrics.Peers.Add(float64(1))
tendermintlog.Info("Added peer", "peer", pc.ip) tendermintlog.Info("Added peer", "peer", pc.ip)
return nil return nil
...@@ -710,13 +637,13 @@ func dial(addr string) (net.Conn, error) { ...@@ -710,13 +637,13 @@ func dial(addr string) (net.Conn, error) {
return conn, nil return conn, nil
} }
func newOutboundPeerConn(addr string, ourNodePrivKey crypto.PrivKey, onPeerError func(Peer, interface{}), state *ConsensusState, evpool *EvidencePool) (*peerConn, error) { func newOutboundPeerConn(addr string, ourNodePrivKey crypto.PrivKey, onPeerError func(Peer, interface{}), state *ConsensusState) (*peerConn, error) {
conn, err := dial(addr) conn, err := dial(addr)
if err != nil { if err != nil {
return &peerConn{}, fmt.Errorf("Error creating peer:%v", err) return &peerConn{}, fmt.Errorf("Error creating peer:%v", err)
} }
pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state, evpool) pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state)
if err != nil { if err != nil {
if cerr := conn.Close(); cerr != nil { if cerr := conn.Close(); cerr != nil {
return &peerConn{}, fmt.Errorf("newPeerConn failed:%v, connection close failed:%v", err, cerr) return &peerConn{}, fmt.Errorf("newPeerConn failed:%v, connection close failed:%v", err, cerr)
...@@ -732,12 +659,11 @@ func newInboundPeerConn( ...@@ -732,12 +659,11 @@ func newInboundPeerConn(
ourNodePrivKey crypto.PrivKey, ourNodePrivKey crypto.PrivKey,
onPeerError func(Peer, interface{}), onPeerError func(Peer, interface{}),
state *ConsensusState, state *ConsensusState,
evpool *EvidencePool,
) (*peerConn, error) { ) (*peerConn, error) {
// TODO: issue PoW challenge // TODO: issue PoW challenge
return newPeerConn(conn, false, false, ourNodePrivKey, onPeerError, state, evpool) return newPeerConn(conn, false, false, ourNodePrivKey, onPeerError, state)
} }
func newPeerConn( func newPeerConn(
...@@ -746,7 +672,6 @@ func newPeerConn( ...@@ -746,7 +672,6 @@ func newPeerConn(
ourNodePrivKey crypto.PrivKey, ourNodePrivKey crypto.PrivKey,
onPeerError func(Peer, interface{}), onPeerError func(Peer, interface{}),
state *ConsensusState, state *ConsensusState,
evpool *EvidencePool,
) (pc *peerConn, err error) { ) (pc *peerConn, err error) {
conn := rawConn conn := rawConn
...@@ -769,6 +694,5 @@ func newPeerConn( ...@@ -769,6 +694,5 @@ func newPeerConn(
conn: conn, conn: conn,
onPeerError: onPeerError, onPeerError: onPeerError,
myState: state, myState: state,
myevpool: evpool,
}, nil }, nil
} }
package tendermint
import (
"encoding/hex"
"fmt"
"sync"
"testing"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
var (
secureConnCrypto crypto.Crypto
sum = 0
mutx sync.Mutex
privKey = "B3DC4C0725884EBB7264B92F1D8D37584A64ADE1799D997EC64B4FE3973E08DE220ACBE680DF2473A0CB48987A00FCC1812F106A7390BE6B8E2D31122C992A19"
expectAddress = "02A13174B92727C4902DB099E51A3339F48BD45E"
)
func init() {
cr2, err := crypto.New(types.GetSignName("", types.ED25519))
if err != nil {
fmt.Println("crypto.New failed for types.ED25519")
return
}
secureConnCrypto = cr2
}
func TestParallel(t *testing.T) {
Parallel(
func() {
mutx.Lock()
sum++
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 2
mutx.Unlock()
},
func() {
mutx.Lock()
sum += 3
mutx.Unlock()
},
)
fmt.Println("TestParallel ok")
assert.Equal(t, 6, sum)
}
func TestGenAddressByPubKey(t *testing.T) {
tmp, err := hex.DecodeString(privKey)
assert.Nil(t, err)
priv, err := secureConnCrypto.PrivKeyFromBytes(tmp)
assert.Nil(t, err)
addr := GenAddressByPubKey(priv.PubKey())
strAddr := fmt.Sprintf("%X", addr)
assert.Equal(t, expectAddress, strAddr)
fmt.Println("TestGenAddressByPubKey ok")
}
func TestIP2IPPort(t *testing.T) {
testMap := NewMutexMap()
assert.Equal(t, false, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.1", "1.1.1.1:80")
assert.Equal(t, true, testMap.Has("1.1.1.1"))
testMap.Set("1.1.1.2", "1.1.1.2:80")
assert.Equal(t, true, testMap.Has("1.1.1.2"))
testMap.Delete("1.1.1.1")
assert.Equal(t, false, testMap.Has("1.1.1.1"))
fmt.Println("TestIP2IPPort ok")
}
func TestPeerSet(t *testing.T) {
testSet := NewPeerSet()
assert.Equal(t, false, testSet.Has("1"))
peer1 := &peerConn{id: "1", ip: []byte("1.1.1.1")}
testSet.Add(peer1)
assert.Equal(t, true, testSet.Has("1"))
assert.Equal(t, true, testSet.HasIP([]byte("1.1.1.1")))
err := testSet.Add(peer1)
assert.NotNil(t, err)
peer2 := &peerConn{id: "2", ip: []byte("1.1.1.2")}
testSet.Add(peer2)
assert.Equal(t, true, testSet.Has("2"))
assert.Equal(t, 2, testSet.Size())
testSet.Remove(peer1)
assert.Equal(t, 1, testSet.Size())
assert.Equal(t, false, testSet.Has("1"))
assert.Equal(t, false, testSet.HasIP([]byte("1.1.1.1")))
fmt.Println("TestPeerSet ok")
}
This diff is collapsed.
...@@ -133,7 +133,6 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) { ...@@ -133,7 +133,6 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) {
// encrypt the frame // encrypt the frame
var sealedFrame = make([]byte, sealedFrameSize) var sealedFrame = make([]byte, sealedFrameSize)
secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret) secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
// fmt.Printf("secretbox.Seal(sealed:%X,sendNonce:%X,shrSecret:%X\n", sealedFrame, sc.sendNonce, sc.shrSecret)
incr2Nonce(sc.sendNonce) incr2Nonce(sc.sendNonce)
// end encryption // end encryption
...@@ -162,7 +161,6 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) { ...@@ -162,7 +161,6 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
// decrypt the frame // decrypt the frame
var frame = make([]byte, totalFrameSize) var frame = make([]byte, totalFrameSize)
// fmt.Printf("secretbox.Open(sealed:%X,recvNonce:%X,shrSecret:%X\n", sealedFrame, sc.recvNonce, sc.shrSecret)
_, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret) _, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret)
if !ok { if !ok {
return n, errors.New("Failed to decrypt SecretConnection") return n, errors.New("Failed to decrypt SecretConnection")
...@@ -298,9 +296,7 @@ func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto ...@@ -298,9 +296,7 @@ func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto
if err2 != nil { if err2 != nil {
return return
} }
//n := int(0) // not used.
//recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), authSigMsgSize, &n, &err2).(authSigMessage)
//secret.Info("shareAuthSignature", "readBuffer", readBuffer)
recvMsg.Key, err2 = types.ConsensusCrypto.PubKeyFromBytes(readBuffer[:32]) recvMsg.Key, err2 = types.ConsensusCrypto.PubKeyFromBytes(readBuffer[:32])
if err2 != nil { if err2 != nil {
return return
......
...@@ -118,9 +118,9 @@ func (s State) GetValidators() (last *ttypes.ValidatorSet, current *ttypes.Valid ...@@ -118,9 +118,9 @@ func (s State) GetValidators() (last *ttypes.ValidatorSet, current *ttypes.Valid
// Create a block from the latest state // Create a block from the latest state
// MakeBlock builds a block with the given txs and commit from the current state. // MakeBlock builds a block with the given txs and commit from the current state.
func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, commit *tmtypes.TendermintCommit) *ttypes.TendermintBlock { func (s State) MakeBlock(height int64, round int64, pblock *types.Block, commit *tmtypes.TendermintCommit, proposerAddr []byte) *ttypes.TendermintBlock {
// build base block // build base block
block := ttypes.MakeBlock(height, round, Txs, commit) block := ttypes.MakeBlock(height, round, pblock, commit)
// fill header with state data // fill header with state data
block.Header.ChainID = s.ChainID block.Header.ChainID = s.ChainID
...@@ -130,6 +130,7 @@ func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, co ...@@ -130,6 +130,7 @@ func (s State) MakeBlock(height int64, round int64, Txs []*types.Transaction, co
block.Header.AppHash = s.AppHash block.Header.AppHash = s.AppHash
block.Header.ConsensusHash = s.ConsensusParams.Hash() block.Header.ConsensusHash = s.ConsensusParams.Hash()
block.Header.LastResultsHash = s.LastResultsHash block.Header.LastResultsHash = s.LastResultsHash
block.Header.ProposerAddr = proposerAddr
return block return block
} }
...@@ -226,6 +227,7 @@ func LoadState(state *tmtypes.State) State { ...@@ -226,6 +227,7 @@ func LoadState(state *tmtypes.State) State {
ChainID: state.GetChainID(), ChainID: state.GetChainID(),
LastBlockHeight: state.GetLastBlockHeight(), LastBlockHeight: state.GetLastBlockHeight(),
LastBlockTotalTx: state.GetLastBlockTotalTx(), LastBlockTotalTx: state.GetLastBlockTotalTx(),
LastBlockID: ttypes.BlockID{BlockID: *state.LastBlockID},
LastBlockTime: state.LastBlockTime, LastBlockTime: state.LastBlockTime,
Validators: nil, Validators: nil,
LastValidators: nil, LastValidators: nil,
...@@ -307,7 +309,7 @@ func (csdb *CSStateDB) LoadValidators(height int64) (*ttypes.ValidatorSet, error ...@@ -307,7 +309,7 @@ func (csdb *CSStateDB) LoadValidators(height int64) (*ttypes.ValidatorSet, error
if height == 0 { if height == 0 {
return nil, nil return nil, nil
} }
if csdb.state.LastBlockHeight+1 == height { if csdb.state.LastBlockHeight == height {
return csdb.state.Validators, nil return csdb.state.Validators, nil
} }
...@@ -374,6 +376,7 @@ func SaveState(state State) *tmtypes.State { ...@@ -374,6 +376,7 @@ func SaveState(state State) *tmtypes.State {
ChainID: state.ChainID, ChainID: state.ChainID,
LastBlockHeight: state.LastBlockHeight, LastBlockHeight: state.LastBlockHeight,
LastBlockTotalTx: state.LastBlockTotalTx, LastBlockTotalTx: state.LastBlockTotalTx,
LastBlockID: &state.LastBlockID.BlockID,
LastBlockTime: state.LastBlockTime, LastBlockTime: state.LastBlockTime,
Validators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}}, Validators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}},
LastValidators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}}, LastValidators: &tmtypes.ValidatorSet{Validators: make([]*tmtypes.Validator, 0), Proposer: &tmtypes.Validator{}},
...@@ -458,17 +461,14 @@ func LoadProposer(source *tmtypes.Validator) (*ttypes.Validator, error) { ...@@ -458,17 +461,14 @@ func LoadProposer(source *tmtypes.Validator) (*ttypes.Validator, error) {
} }
// CreateBlockInfoTx make blockInfo to the first transaction of the block and execer is valnode // CreateBlockInfoTx make blockInfo to the first transaction of the block and execer is valnode
func CreateBlockInfoTx(pubkey string, lastCommit *tmtypes.TendermintCommit, seenCommit *tmtypes.TendermintCommit, state *tmtypes.State, proposal *tmtypes.Proposal, block *tmtypes.TendermintBlock) *types.Transaction { func CreateBlockInfoTx(pubkey string, state *tmtypes.State, block *tmtypes.TendermintBlock) *types.Transaction {
blockNoTxs := *block blockSave := *block
blockNoTxs.Txs = make([]*types.Transaction, 0) blockSave.Data = nil
blockInfo := &tmtypes.TendermintBlockInfo{ blockInfo := &tmtypes.TendermintBlockInfo{
SeenCommit: seenCommit, State: state,
LastCommit: lastCommit, Block: &blockSave,
State: state,
Proposal: proposal,
Block: &blockNoTxs,
} }
tendermintlog.Debug("CreateBlockInfoTx", "validators", blockInfo.State.Validators.Validators, "block", block, "block-notxs", blockNoTxs) tendermintlog.Debug("CreateBlockInfoTx", "blockInfo", blockInfo)
nput := &tmtypes.ValNodeAction_BlockInfo{BlockInfo: blockInfo} nput := &tmtypes.ValNodeAction_BlockInfo{BlockInfo: blockInfo}
action := &tmtypes.ValNodeAction{Value: nput, Ty: tmtypes.ValNodeActionBlockInfo} action := &tmtypes.ValNodeAction{Value: nput, Ty: tmtypes.ValNodeActionBlockInfo}
......
package tendermint
import (
"fmt"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/gogo/protobuf/proto"
)
var (
stateKey = []byte("stateKey")
)
type ConsensusStore struct {
db dbm.DB
}
// NewConsensusStore returns a new ConsensusStore with the given DB
func NewConsensusStore() *ConsensusStore {
db := DefaultDBProvider("state")
db.SetCacheSize(100)
return &ConsensusStore{
db: db,
}
}
// LoadStateFromStore
func (cs *ConsensusStore) LoadStateFromStore() *tmtypes.State {
buf, err := cs.db.Get(stateKey)
if err != nil {
tendermintlog.Error("LoadStateFromStore", "err", err)
return nil
}
state := &tmtypes.State{}
err = types.Decode(buf, state)
if err != nil {
panic(err)
}
return state
}
// LoadStateHeight
func (cs *ConsensusStore) LoadStateHeight() int64 {
state := cs.LoadStateFromStore()
if state == nil {
return int64(0)
}
return state.LastBlockHeight
}
// LoadSeenCommit by height
func (cs *ConsensusStore) LoadSeenCommit(height int64) *tmtypes.TendermintCommit {
buf, err := cs.db.Get(calcSeenCommitKey(height))
if err != nil {
tendermintlog.Error("LoadSeenCommit", "err", err)
return nil
}
commit := &tmtypes.TendermintCommit{}
err = types.Decode(buf, commit)
if err != nil {
panic(err)
}
return commit
}
// SaveConsensusState save state and seenCommit
func (cs *ConsensusStore) SaveConsensusState(height int64, state *tmtypes.State, sc proto.Message) error {
seenCommitBytes := types.Encode(sc)
stateBytes := types.Encode(state)
batch := cs.db.NewBatch(true)
batch.Set(calcSeenCommitKey(height), seenCommitBytes)
batch.Set(stateKey, stateBytes)
err := batch.Write()
if err != nil {
tendermintlog.Error("SaveConsensusState batch.Write", "err", err)
return err
}
return nil
}
func calcSeenCommitKey(height int64) []byte {
return []byte(fmt.Sprintf("SC:%v", height))
}
This diff is collapsed.
...@@ -7,6 +7,7 @@ package tendermint ...@@ -7,6 +7,7 @@ package tendermint
import ( import (
"context" "context"
"encoding/binary" "encoding/binary"
"encoding/hex"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
...@@ -15,6 +16,8 @@ import ( ...@@ -15,6 +16,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/33cn/chain33/blockchain" "github.com/33cn/chain33/blockchain"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/limits" "github.com/33cn/chain33/common/limits"
...@@ -27,6 +30,7 @@ import ( ...@@ -27,6 +30,7 @@ import (
"github.com/33cn/chain33/store" "github.com/33cn/chain33/store"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
pty "github.com/33cn/plugin/plugin/dapp/norm/types" pty "github.com/33cn/plugin/plugin/dapp/norm/types"
ty "github.com/33cn/plugin/plugin/dapp/valnode/types"
"google.golang.org/grpc" "google.golang.org/grpc"
_ "github.com/33cn/chain33/system" _ "github.com/33cn/chain33/system"
...@@ -36,7 +40,7 @@ import ( ...@@ -36,7 +40,7 @@ import (
var ( var (
random *rand.Rand random *rand.Rand
loopCount = 10 loopCount = 3
conn *grpc.ClientConn conn *grpc.ClientConn
c types.Chain33Client c types.Chain33Client
) )
...@@ -50,12 +54,12 @@ func init() { ...@@ -50,12 +54,12 @@ func init() {
log.SetLogLevel("info") log.SetLogLevel("info")
} }
func TestTendermintPerf(t *testing.T) { func TestTendermintPerf(t *testing.T) {
TendermintPerf() TendermintPerf(t)
fmt.Println("=======start clear test data!=======") fmt.Println("=======start clear test data!=======")
clearTestData() clearTestData()
} }
func TendermintPerf() { func TendermintPerf(t *testing.T) {
q, chain, s, mem, exec, cs, p2p := initEnvTendermint() q, chain, s, mem, exec, cs, p2p := initEnvTendermint()
defer chain.Close() defer chain.Close()
defer mem.Close() defer mem.Close()
...@@ -68,12 +72,18 @@ func TendermintPerf() { ...@@ -68,12 +72,18 @@ func TendermintPerf() {
for err != nil { for err != nil {
err = createConn() err = createConn()
} }
time.Sleep(10 * time.Second) time.Sleep(2 * time.Second)
for i := 0; i < loopCount; i++ { for i := 0; i < loopCount; i++ {
NormPut() NormPut()
time.Sleep(time.Second) time.Sleep(time.Second)
} }
time.Sleep(10 * time.Second) CheckState(t, cs.(*Client))
AddNode()
for i := 0; i < loopCount*3; i++ {
NormPut()
time.Sleep(time.Second)
}
time.Sleep(2 * time.Second)
} }
func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) { func initEnvTendermint() (queue.Queue, *blockchain.BlockChain, queue.Module, queue.Module, *executor.Executor, queue.Module, queue.Module) {
...@@ -177,3 +187,38 @@ func NormPut() { ...@@ -177,3 +187,38 @@ func NormPut() {
return return
} }
} }
func AddNode() {
pubkey := "788657125A5A547B499F8B74239092EBB6466E8A205348D9EA645D510235A671"
pubkeybyte, err := hex.DecodeString(pubkey)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
nput := &ty.ValNodeAction_Node{Node: &ty.ValNode{PubKey: pubkeybyte, Power: int64(2)}}
action := &ty.ValNodeAction{Value: nput, Ty: ty.ValNodeActionUpdate}
tx := &types.Transaction{Execer: []byte("valnode"), Payload: types.Encode(action), Fee: fee}
tx.To = address.ExecAddress("valnode")
tx.Nonce = random.Int63()
tx.Sign(types.SECP256K1, getprivkey("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"))
reply, err := c.SendTransaction(context.Background(), tx)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
if !reply.IsOk {
fmt.Fprintln(os.Stderr, errors.New(string(reply.GetMsg())))
return
}
}
func CheckState(t *testing.T, client *Client) {
msg1, err := client.Query_IsHealthy(&types.ReqNil{})
assert.Nil(t, err)
flag := msg1.(*ty.IsHealthy).IsHealthy
assert.Equal(t, true, flag)
_, err = client.Query_NodeInfo(&types.ReqNil{})
assert.Nil(t, err)
}
...@@ -17,7 +17,6 @@ import ( ...@@ -17,7 +17,6 @@ import (
"github.com/33cn/chain33/common/merkle" "github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types" tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/golang/protobuf/proto"
) )
var ( var (
...@@ -58,67 +57,62 @@ type TendermintBlock struct { ...@@ -58,67 +57,62 @@ type TendermintBlock struct {
// MakeBlock returns a new block with an empty header, except what can be computed from itself. // MakeBlock returns a new block with an empty header, except what can be computed from itself.
// It populates the same set of fields validated by ValidateBasic // It populates the same set of fields validated by ValidateBasic
func MakeBlock(height int64, round int64, Txs []*types.Transaction, commit *tmtypes.TendermintCommit) *TendermintBlock { func MakeBlock(height int64, round int64, pblock *types.Block, commit *tmtypes.TendermintCommit) *TendermintBlock {
block := &TendermintBlock{&tmtypes.TendermintBlock{ block := &TendermintBlock{
Header: &tmtypes.TendermintBlockHeader{ &tmtypes.TendermintBlock{
Height: height, Header: &tmtypes.TendermintBlockHeader{
Round: round, Height: height,
Time: time.Now().UnixNano(), Round: round,
NumTxs: int64(len(Txs)), Time: pblock.BlockTime,
NumTxs: int64(len(pblock.Txs)),
},
Data: pblock,
LastCommit: commit,
}, },
Txs: Txs,
LastCommit: commit,
Evidence: &tmtypes.EvidenceData{Evidence: make([]*tmtypes.EvidenceEnvelope, 0)},
},
} }
block.FillHeader() block.FillHeader()
return block return block
} }
// AddEvidence appends the given evidence to the block
func (b *TendermintBlock) AddEvidence(evidence []Evidence) {
for _, item := range evidence {
ev := item.Child()
if ev != nil {
data, err := proto.Marshal(ev)
if err != nil {
blocklog.Error("AddEvidence marshal failed", "error", err)
panic("AddEvidence marshal failed")
}
env := &tmtypes.EvidenceEnvelope{
TypeName: item.TypeName(),
Data: data,
}
b.Evidence.Evidence = append(b.Evidence.Evidence, env)
}
}
}
// ValidateBasic performs basic validation that doesn't involve state data. // ValidateBasic performs basic validation that doesn't involve state data.
// It checks the internal consistency of the block. // It checks the internal consistency of the block.
func (b *TendermintBlock) ValidateBasic() (int64, error) { // Further validation is done using state#ValidateBlock.
newTxs := int64(len(b.Txs)) func (b *TendermintBlock) ValidateBasic() error {
if b == nil {
return errors.New("nil block")
}
if b.Header.Height < 0 {
return errors.New("Negative Header.Height")
} else if b.Header.Height == 0 {
return errors.New("Zero Header.Height")
}
newTxs := int64(len(b.Data.Txs))
if b.Header.NumTxs != newTxs { if b.Header.NumTxs != newTxs {
return 0, fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs) return fmt.Errorf("Wrong Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs)
} }
if b.Header.TotalTxs < 0 {
return errors.New("Negative Header.TotalTxs")
}
lastCommit := Commit{ lastCommit := Commit{
TendermintCommit: b.LastCommit, TendermintCommit: b.LastCommit,
} }
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) { if b.Header.Height > 1 {
return 0, fmt.Errorf("Wrong Block.Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash()) if b.LastCommit == nil {
} return errors.New("nil LastCommit")
if b.Header.Height != 1 { }
if err := lastCommit.ValidateBasic(); err != nil { if err := lastCommit.ValidateBasic(); err != nil {
return 0, err return err
} }
} }
if !bytes.Equal(b.Header.LastCommitHash, lastCommit.Hash()) {
evidence := &EvidenceData{EvidenceData: b.Evidence} return fmt.Errorf("Wrong Header.LastCommitHash. Expected %v, got %v", b.Header.LastCommitHash, lastCommit.Hash())
if !bytes.Equal(b.Header.EvidenceHash, evidence.Hash()) {
return 0, errors.New(Fmt("Wrong Block.Header.EvidenceHash. Expected %v, got %v", b.Header.EvidenceHash, evidence.Hash()))
} }
return newTxs, nil
return nil
} }
// FillHeader fills in any remaining header fields that are a function of the block data // FillHeader fills in any remaining header fields that are a function of the block data
...@@ -129,10 +123,6 @@ func (b *TendermintBlock) FillHeader() { ...@@ -129,10 +123,6 @@ func (b *TendermintBlock) FillHeader() {
} }
b.Header.LastCommitHash = lastCommit.Hash() b.Header.LastCommitHash = lastCommit.Hash()
} }
if b.Header.EvidenceHash == nil {
evidence := &EvidenceData{EvidenceData: b.Evidence}
b.Header.EvidenceHash = evidence.Hash()
}
} }
// Hash computes and returns the block hash. // Hash computes and returns the block hash.
...@@ -173,10 +163,8 @@ func (b *TendermintBlock) StringIndented(indent string) string { ...@@ -173,10 +163,8 @@ func (b *TendermintBlock) StringIndented(indent string) string {
return Fmt(`Block{ return Fmt(`Block{
%s %v %s %v
%s %v %s %v
%s %v
%s}#%v`, %s}#%v`,
indent, header.StringIndented(indent+" "), indent, header.StringIndented(indent+" "),
// indent, b.Evidence.StringIndented(indent+" "),
indent, lastCommit.StringIndented(indent+" "), indent, lastCommit.StringIndented(indent+" "),
indent, b.Hash()) indent, b.Hash())
} }
...@@ -227,7 +215,6 @@ func (h *Header) StringIndented(indent string) string { ...@@ -227,7 +215,6 @@ func (h *Header) StringIndented(indent string) string {
%s App: %v %s App: %v
%s Conensus: %v %s Conensus: %v
%s Results: %v %s Results: %v
%s Evidence: %v
%s}#%v`, %s}#%v`,
indent, h.ChainID, indent, h.ChainID,
indent, h.Height, indent, h.Height,
...@@ -240,24 +227,19 @@ func (h *Header) StringIndented(indent string) string { ...@@ -240,24 +227,19 @@ func (h *Header) StringIndented(indent string) string {
indent, h.AppHash, indent, h.AppHash,
indent, h.ConsensusHash, indent, h.ConsensusHash,
indent, h.LastResultsHash, indent, h.LastResultsHash,
indent, h.EvidenceHash,
indent, h.Hash()) indent, h.Hash())
} }
// Commit struct // Commit struct
type Commit struct { type Commit struct {
*tmtypes.TendermintCommit *tmtypes.TendermintCommit
firstPrecommit *tmtypes.Vote
hash []byte hash []byte
bitArray *BitArray bitArray *BitArray
firstPrecommit *tmtypes.Vote
} }
// FirstPrecommit returns the first non-nil precommit in the commit // FirstPrecommit returns the first non-nil precommit in the commit
func (commit *Commit) FirstPrecommit() *tmtypes.Vote { func (commit *Commit) FirstPrecommit() *tmtypes.Vote {
if len(commit.Precommits) == 0 {
return nil
}
if commit.firstPrecommit != nil { if commit.firstPrecommit != nil {
return commit.firstPrecommit return commit.firstPrecommit
} }
...@@ -334,13 +316,14 @@ func (commit *Commit) ValidateBasic() error { ...@@ -334,13 +316,14 @@ func (commit *Commit) ValidateBasic() error {
height, round := commit.Height(), commit.Round() height, round := commit.Height(), commit.Round()
// validate the precommits // validate the precommits
for _, precommit := range commit.Precommits { for _, item := range commit.Precommits {
// It's OK for precommits to be missing. // may be nil if validator skipped.
if precommit == nil { if item == nil || len(item.Signature) == 0 {
continue continue
} }
precommit := &Vote{Vote: item}
// Ensure that all votes are precommits // Ensure that all votes are precommits
if byte(precommit.Type) != VoteTypePrecommit { if precommit.Type != uint32(VoteTypePrecommit) {
return fmt.Errorf("Invalid commit vote. Expected precommit, got %v", return fmt.Errorf("Invalid commit vote. Expected precommit, got %v",
precommit.Type) precommit.Type)
} }
...@@ -394,113 +377,3 @@ type SignedHeader struct { ...@@ -394,113 +377,3 @@ type SignedHeader struct {
Header *Header `json:"header"` Header *Header `json:"header"`
Commit *Commit `json:"commit"` Commit *Commit `json:"commit"`
} }
// EvidenceEnvelope ...
type EvidenceEnvelope struct {
*tmtypes.EvidenceEnvelope
}
// EvidenceEnvelopeList contains any evidence of malicious wrong-doing by validators
type EvidenceEnvelopeList []EvidenceEnvelope
// Hash ...
func (env EvidenceEnvelope) Hash() []byte {
penv := env.EvidenceEnvelope
evidence := EvidenceEnvelope2Evidence(penv)
if evidence != nil {
return evidence.Hash()
}
return nil
}
func (env EvidenceEnvelope) String() string {
penv := env.EvidenceEnvelope
evidence := EvidenceEnvelope2Evidence(penv)
if evidence != nil {
return evidence.String()
}
return ""
}
// Hash returns the simple merkle root hash of the EvidenceList.
func (evl EvidenceEnvelopeList) Hash() []byte {
// Recursive impl.
// Copied from tmlibs/merkle to avoid allocations
switch len(evl) {
case 0:
return nil
case 1:
return evl[0].Hash()
default:
left := evl[:(len(evl)+1)/2].Hash()
right := evl[(len(evl)+1)/2:].Hash()
cache := make([]byte, len(left)+len(right))
return merkle.GetHashFromTwoHash(cache, left, right)
}
}
func (evl EvidenceEnvelopeList) String() string {
s := ""
for _, e := range evl {
s += Fmt("%s\t\t", e)
}
return s
}
// Has returns true if the evidence is in the EvidenceList.
func (evl EvidenceEnvelopeList) Has(evidence Evidence) bool {
for _, ev := range evl {
penv := ev.EvidenceEnvelope
tmp := EvidenceEnvelope2Evidence(penv)
if tmp != nil {
if tmp.Equal(evidence) {
return true
}
}
}
return false
}
// EvidenceData ...
type EvidenceData struct {
*tmtypes.EvidenceData
hash []byte
}
// Hash returns the hash of the data.
func (data *EvidenceData) Hash() []byte {
if data.hash == nil {
if data.EvidenceData == nil {
return nil
}
var evidence EvidenceEnvelopeList
for _, item := range data.Evidence {
elem := EvidenceEnvelope{
EvidenceEnvelope: item,
}
evidence = append(evidence, elem)
}
data.hash = evidence.Hash()
}
return data.hash
}
// StringIndented returns a string representation of the evidence.
func (data *EvidenceData) StringIndented(indent string) string {
if data == nil {
return "nil-Evidence"
}
evStrings := make([]string, MinInt(len(data.Evidence), 21))
for i, ev := range data.Evidence {
if i == 20 {
evStrings[i] = Fmt("... (%v total)", len(data.Evidence))
break
}
evStrings[i] = Fmt("Evidence:%v", ev)
}
return Fmt(`Data{
%s %v
%s}#%v`,
indent, strings.Join(evStrings, "\n"+indent+" "),
indent, data.hash)
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package types
import "errors"
var (
// ErrBaseTxType error type
ErrBaseTxType = errors.New("ErrBaseTxType")
// ErrBlockInfoTx error type
ErrBlockInfoTx = errors.New("ErrBlockInfoTx")
// ErrBaseExecErr error type
ErrBaseExecErr = errors.New("ErrBaseExecErr")
// ErrLastBlockID error type
ErrLastBlockID = errors.New("ErrLastBlockID")
)
This diff is collapsed.
...@@ -100,9 +100,8 @@ func (hvs *HeightVoteSet) SetRound(round int) { ...@@ -100,9 +100,8 @@ func (hvs *HeightVoteSet) SetRound(round int) {
func (hvs *HeightVoteSet) addRound(round int) { func (hvs *HeightVoteSet) addRound(round int) {
if _, ok := hvs.roundVoteSets[round]; ok { if _, ok := hvs.roundVoteSets[round]; ok {
panic(Fmt("Panicked on a Sanity Check: %v", "addRound() for an existing round")) panic("addRound() for an existing round")
} }
// log.Debug("addRound(round)", "round", round)
prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet) prevotes := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrevote, hvs.valSet)
precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet) precommits := NewVoteSet(hvs.chainID, hvs.height, round, VoteTypePrecommit, hvs.valSet)
hvs.roundVoteSets[round] = RoundVoteSet{ hvs.roundVoteSets[round] = RoundVoteSet{
...@@ -179,7 +178,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, voteType byte) *VoteSet { ...@@ -179,7 +178,7 @@ func (hvs *HeightVoteSet) getVoteSet(round int, voteType byte) *VoteSet {
case VoteTypePrecommit: case VoteTypePrecommit:
return rvs.Precommits return rvs.Precommits
default: default:
panic(Fmt("Panicked on a Sanity Check: %v", Fmt("Unexpected vote type %X", voteType))) panic(Fmt("Unexpected vote type %X", voteType))
} }
} }
......
...@@ -440,7 +440,7 @@ func (pv *PrivValidatorImp) SignHeartbeat(chainID string, heartbeat *Heartbeat) ...@@ -440,7 +440,7 @@ func (pv *PrivValidatorImp) SignHeartbeat(chainID string, heartbeat *Heartbeat)
// String returns a string representation of the PrivValidatorImp. // String returns a string representation of the PrivValidatorImp.
func (pv *PrivValidatorImp) String() string { func (pv *PrivValidatorImp) String() string {
return Fmt("PrivValidator{%v LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep) return Fmt("PrivValidator{%X LH:%v, LR:%v, LS:%v}", pv.GetAddress(), pv.LastHeight, pv.LastRound, pv.LastStep)
} }
// GetLastHeight ... // GetLastHeight ...
......
...@@ -32,7 +32,6 @@ const ( ...@@ -32,7 +32,6 @@ const (
RoundStepCommit = RoundStepType(0x08) // Entered commit state machine RoundStepCommit = RoundStepType(0x08) // Entered commit state machine
// NOTE: RoundStepNewHeight acts as RoundStepCommitWait. // NOTE: RoundStepNewHeight acts as RoundStepCommitWait.
EvidenceListID = byte(0x01)
NewRoundStepID = byte(0x02) NewRoundStepID = byte(0x02)
CommitStepID = byte(0x03) CommitStepID = byte(0x03)
ProposalID = byte(0x04) ProposalID = byte(0x04)
...@@ -43,6 +42,7 @@ const ( ...@@ -43,6 +42,7 @@ const (
VoteSetBitsID = byte(0x09) VoteSetBitsID = byte(0x09)
ProposalHeartbeatID = byte(0x0a) ProposalHeartbeatID = byte(0x0a)
ProposalBlockID = byte(0x0b) ProposalBlockID = byte(0x0b)
ValidBlockID = byte(0x0c)
PacketTypePing = byte(0xff) PacketTypePing = byte(0xff)
PacketTypePong = byte(0xfe) PacketTypePong = byte(0xfe)
...@@ -51,7 +51,6 @@ const ( ...@@ -51,7 +51,6 @@ const (
// InitMessageMap ... // InitMessageMap ...
func InitMessageMap() { func InitMessageMap() {
MsgMap = map[byte]reflect.Type{ MsgMap = map[byte]reflect.Type{
EvidenceListID: reflect.TypeOf(tmtypes.EvidenceData{}),
NewRoundStepID: reflect.TypeOf(tmtypes.NewRoundStepMsg{}), NewRoundStepID: reflect.TypeOf(tmtypes.NewRoundStepMsg{}),
CommitStepID: reflect.TypeOf(tmtypes.CommitStepMsg{}), CommitStepID: reflect.TypeOf(tmtypes.CommitStepMsg{}),
ProposalID: reflect.TypeOf(tmtypes.Proposal{}), ProposalID: reflect.TypeOf(tmtypes.Proposal{}),
...@@ -62,6 +61,7 @@ func InitMessageMap() { ...@@ -62,6 +61,7 @@ func InitMessageMap() {
VoteSetBitsID: reflect.TypeOf(tmtypes.VoteSetBitsMsg{}), VoteSetBitsID: reflect.TypeOf(tmtypes.VoteSetBitsMsg{}),
ProposalHeartbeatID: reflect.TypeOf(tmtypes.Heartbeat{}), ProposalHeartbeatID: reflect.TypeOf(tmtypes.Heartbeat{}),
ProposalBlockID: reflect.TypeOf(tmtypes.TendermintBlock{}), ProposalBlockID: reflect.TypeOf(tmtypes.TendermintBlock{}),
ValidBlockID: reflect.TypeOf(tmtypes.ValidBlockMsg{}),
} }
} }
...@@ -108,6 +108,8 @@ type RoundState struct { ...@@ -108,6 +108,8 @@ type RoundState struct {
ProposalBlock *TendermintBlock ProposalBlock *TendermintBlock
LockedRound int LockedRound int
LockedBlock *TendermintBlock LockedBlock *TendermintBlock
ValidRound int // Last known round with POL for non-nil valid block.
ValidBlock *TendermintBlock // Last known block of POL mentioned above.
Votes *HeightVoteSet Votes *HeightVoteSet
CommitRound int CommitRound int
LastCommit *VoteSet // Last precommits at Height-1 LastCommit *VoteSet // Last precommits at Height-1
...@@ -141,6 +143,8 @@ func (rs *RoundState) StringIndented(indent string) string { ...@@ -141,6 +143,8 @@ func (rs *RoundState) StringIndented(indent string) string {
%s ProposalBlock: %v %s ProposalBlock: %v
%s LockedRound: %v %s LockedRound: %v
%s LockedBlock: %v %s LockedBlock: %v
%s ValidRound: %v
%s ValidBlock: %v
%s Votes: %v %s Votes: %v
%s LastCommit: %v %s LastCommit: %v
%s LastValidators:%v %s LastValidators:%v
...@@ -153,6 +157,8 @@ func (rs *RoundState) StringIndented(indent string) string { ...@@ -153,6 +157,8 @@ func (rs *RoundState) StringIndented(indent string) string {
indent, rs.ProposalBlock.StringShort(), indent, rs.ProposalBlock.StringShort(),
indent, rs.LockedRound, indent, rs.LockedRound,
indent, rs.LockedBlock.StringShort(), indent, rs.LockedBlock.StringShort(),
indent, rs.ValidRound,
indent, rs.ValidBlock.StringShort(),
indent, rs.Votes.StringIndented(indent+" "), indent, rs.Votes.StringIndented(indent+" "),
indent, rs.LastCommit.StringShort(), indent, rs.LastCommit.StringShort(),
indent, rs.LastValidators.StringIndented(indent+" "), indent, rs.LastValidators.StringIndented(indent+" "),
...@@ -173,14 +179,15 @@ type PeerRoundState struct { ...@@ -173,14 +179,15 @@ type PeerRoundState struct {
StartTime time.Time // Estimated start of round 0 at this height StartTime time.Time // Estimated start of round 0 at this height
Proposal bool // True if peer has proposal for this round Proposal bool // True if peer has proposal for this round
ProposalBlock bool // True if peer has proposal block for this round ProposalBlock bool // True if peer has proposal block for this round
ProposalPOLRound int // Proposal's POL round. -1 if none. ProposalBlockHash []byte
ProposalPOL *BitArray // nil until ProposalPOLMessage received. ProposalPOLRound int // Proposal's POL round. -1 if none.
Prevotes *BitArray // All votes peer has for this round ProposalPOL *BitArray // nil until ProposalPOLMessage received.
Precommits *BitArray // All precommits peer has for this round Prevotes *BitArray // All votes peer has for this round
LastCommitRound int // Round of commit for last height. -1 if none. Precommits *BitArray // All precommits peer has for this round
LastCommit *BitArray // All commit precommits of commit for last height. LastCommitRound int // Round of commit for last height. -1 if none.
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none. LastCommit *BitArray // All commit precommits of commit for last height.
CatchupCommit *BitArray // All commit precommits peer has for this height & CatchupCommitRound CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none.
CatchupCommit *BitArray // All commit precommits peer has for this height & CatchupCommitRound
} }
// String returns a string representation of the PeerRoundState // String returns a string representation of the PeerRoundState
...@@ -194,6 +201,7 @@ func (prs PeerRoundState) StringIndented(indent string) string { ...@@ -194,6 +201,7 @@ func (prs PeerRoundState) StringIndented(indent string) string {
%s %v/%v/%v @%v %s %v/%v/%v @%v
%s Proposal %v %s Proposal %v
%s ProposalBlock %v %s ProposalBlock %v
%s ProposalBlockHash %X
%s POL %v (round %v) %s POL %v (round %v)
%s Prevotes %v %s Prevotes %v
%s Precommits %v %s Precommits %v
...@@ -203,6 +211,7 @@ func (prs PeerRoundState) StringIndented(indent string) string { ...@@ -203,6 +211,7 @@ func (prs PeerRoundState) StringIndented(indent string) string {
indent, prs.Height, prs.Round, prs.Step, prs.StartTime, indent, prs.Height, prs.Round, prs.Step, prs.StartTime,
indent, prs.Proposal, indent, prs.Proposal,
indent, prs.ProposalBlock, indent, prs.ProposalBlock,
indent, prs.ProposalBlock,
indent, prs.ProposalPOL, prs.ProposalPOLRound, indent, prs.ProposalPOL, prs.ProposalPOLRound,
indent, prs.Prevotes, indent, prs.Prevotes,
indent, prs.Precommits, indent, prs.Precommits,
......
...@@ -25,6 +25,7 @@ var ( ...@@ -25,6 +25,7 @@ var (
ErrVoteInvalidSignature = errors.New("Invalid signature") ErrVoteInvalidSignature = errors.New("Invalid signature")
ErrVoteInvalidBlockHash = errors.New("Invalid block hash") ErrVoteInvalidBlockHash = errors.New("Invalid block hash")
ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature") ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature")
ErrVoteConflict = errors.New("Conflicting vote")
ErrVoteNil = errors.New("Nil vote") ErrVoteNil = errors.New("Nil vote")
votelog = log15.New("module", "tendermint-vote") votelog = log15.New("module", "tendermint-vote")
) )
...@@ -70,7 +71,7 @@ func NewProposal(height int64, round int, blockhash []byte, polRound int, polBlo ...@@ -70,7 +71,7 @@ func NewProposal(height int64, round int, blockhash []byte, polRound int, polBlo
// String returns a string representation of the Proposal. // String returns a string representation of the Proposal.
func (p *Proposal) String() string { func (p *Proposal) String() string {
return fmt.Sprintf("Proposal{%v/%v (%v,%v) %X %v @ %s}", return fmt.Sprintf("Proposal{%v/%v (%v, %X) %X %X @ %s}",
p.Height, p.Round, p.POLRound, p.POLBlockID, p.Height, p.Round, p.POLRound, p.POLBlockID,
p.Blockhash, p.Signature, CanonicalTime(time.Unix(0, p.Timestamp))) p.Blockhash, p.Signature, CanonicalTime(time.Unix(0, p.Timestamp)))
} }
...@@ -119,34 +120,6 @@ func (heartbeat *Heartbeat) WriteSignBytes(chainID string, w io.Writer, n *int, ...@@ -119,34 +120,6 @@ func (heartbeat *Heartbeat) WriteSignBytes(chainID string, w io.Writer, n *int,
*err = writeErr *err = writeErr
} }
// ErrVoteConflictingVotes ...
type ErrVoteConflictingVotes struct {
*DuplicateVoteEvidence
}
func (err *ErrVoteConflictingVotes) Error() string {
pubkey, error := PubKeyFromString(err.PubKey)
if error != nil {
return fmt.Sprintf("Conflicting votes from validator PubKey:%v,error:%v", err.PubKey, error)
}
addr := GenAddressByPubKey(pubkey)
return fmt.Sprintf("Conflicting votes from validator %v", addr)
}
// NewConflictingVoteError ...
func NewConflictingVoteError(val *Validator, voteA, voteB *tmtypes.Vote) *ErrVoteConflictingVotes {
keyString := fmt.Sprintf("%X", val.PubKey)
return &ErrVoteConflictingVotes{
&DuplicateVoteEvidence{
&tmtypes.DuplicateVoteEvidence{
PubKey: keyString,
VoteA: voteA,
VoteB: voteB,
},
},
}
}
// Types of votes // Types of votes
// TODO Make a new type "VoteType" // TODO Make a new type "VoteType"
const ( const (
...@@ -211,7 +184,7 @@ func (vote *Vote) String() string { ...@@ -211,7 +184,7 @@ func (vote *Vote) String() string {
PanicSanity("Unknown vote type") PanicSanity("Unknown vote type")
} }
return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %v @ %s}", return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
vote.ValidatorIndex, Fingerprint(vote.ValidatorAddress), vote.ValidatorIndex, Fingerprint(vote.ValidatorAddress),
vote.Height, vote.Round, vote.Type, typeString, vote.Height, vote.Round, vote.Type, typeString,
Fingerprint(vote.BlockID.Hash), vote.Signature, Fingerprint(vote.BlockID.Hash), vote.Signature,
...@@ -240,7 +213,6 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { ...@@ -240,7 +213,6 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
// Hash ... // Hash ...
func (vote *Vote) Hash() []byte { func (vote *Vote) Hash() []byte {
if vote == nil { if vote == nil {
//votelog.Error("vote hash is nil")
return nil return nil
} }
bytes, err := json.Marshal(vote) bytes, err := json.Marshal(vote)
......
...@@ -70,7 +70,7 @@ func (v *Validator) String() string { ...@@ -70,7 +70,7 @@ func (v *Validator) String() string {
if v == nil { if v == nil {
return "nil-Validator" return "nil-Validator"
} }
return Fmt("Validator{%v %v VP:%v A:%v}", return Fmt("Validator{ADDR:%X PUB:%X VP:%v A:%v}",
v.Address, v.Address,
v.PubKey, v.PubKey,
v.VotingPower, v.VotingPower,
......
...@@ -200,7 +200,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { ...@@ -200,7 +200,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
// Add vote and get conflicting vote if any // Add vote and get conflicting vote if any
added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower) added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
if conflicting != nil { if conflicting != nil {
return added, NewConflictingVoteError(val, conflicting.Vote, vote.Vote) return added, errors.Wrapf(ErrVoteConflict, "Conflicting vote: %v; New vote: %v", conflicting, vote)
} }
if !added { if !added {
PanicSanity("Expected to add non-conflicting vote") PanicSanity("Expected to add non-conflicting vote")
......
syntax = "proto3"; syntax = "proto3";
import "transaction.proto"; import "blockchain.proto";
package types; package types;
...@@ -30,11 +30,9 @@ message TendermintCommit { ...@@ -30,11 +30,9 @@ message TendermintCommit {
} }
message TendermintBlockInfo { message TendermintBlockInfo {
TendermintCommit SeenCommit = 1; State State = 2;
TendermintCommit LastCommit = 2; Proposal Proposal = 3;
State State = 3; TendermintBlock block = 4;
Proposal Proposal = 4;
TendermintBlock block = 5;
} }
message BlockSize { message BlockSize {
...@@ -89,20 +87,6 @@ message State { ...@@ -89,20 +87,6 @@ message State {
bytes AppHash = 12; bytes AppHash = 12;
} }
message DuplicateVoteEvidence {
string pubKey = 1;
Vote voteA = 2;
Vote voteB = 3;
}
message EvidenceEnvelope {
string typeName = 1;
bytes data = 2;
}
message EvidenceData {
repeated EvidenceEnvelope evidence = 1;
}
message TendermintBlockHeader { message TendermintBlockHeader {
string chainID = 1; string chainID = 1;
...@@ -117,15 +101,13 @@ message TendermintBlockHeader { ...@@ -117,15 +101,13 @@ message TendermintBlockHeader {
bytes consensusHash = 10; bytes consensusHash = 10;
bytes appHash = 11; bytes appHash = 11;
bytes lastResultsHash = 12; bytes lastResultsHash = 12;
bytes evidenceHash = 13; bytes proposerAddr = 13;
} }
message TendermintBlock { message TendermintBlock {
TendermintBlockHeader header = 1; TendermintBlockHeader header = 1;
repeated Transaction txs = 2; Block data = 2;
EvidenceData evidence = 3; TendermintCommit lastCommit = 4;
TendermintCommit lastCommit = 4;
bytes proposerAddr = 5;
} }
message Proposal { message Proposal {
...@@ -146,6 +128,13 @@ message NewRoundStepMsg { ...@@ -146,6 +128,13 @@ message NewRoundStepMsg {
int32 lastCommitRound = 5; int32 lastCommitRound = 5;
} }
message ValidBlockMsg {
int64 height = 1;
int32 round = 2;
bytes blockhash = 3;
bool isCommit = 4;
}
message CommitStepMsg { message CommitStepMsg {
int64 height = 1; int64 height = 1;
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment