Unverified Commit 34c89f73 authored by vipwzw's avatar vipwzw Committed by GitHub

Merge pull request #852 from caopingcp/issue774_tendermint

tendermint add aggregate signature
parents 4b5cd0a0 b23f5c28
...@@ -23,6 +23,7 @@ require ( ...@@ -23,6 +23,7 @@ require (
github.com/miguelmota/go-solidity-sha3 v0.1.0 github.com/miguelmota/go-solidity-sha3 v0.1.0
github.com/mr-tron/base58 v1.1.3 github.com/mr-tron/base58 v1.1.3
github.com/pborman/uuid v1.2.0 github.com/pborman/uuid v1.2.0
github.com/phoreproject/bls v0.0.0-20200525203911-a88a5ae26844
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v0.9.2 // indirect github.com/prometheus/client_golang v0.9.2 // indirect
github.com/prometheus/common v0.4.1 github.com/prometheus/common v0.4.1
......
This diff is collapsed.
...@@ -43,6 +43,8 @@ dbPath="datadir/addrbook" ...@@ -43,6 +43,8 @@ dbPath="datadir/addrbook"
dbCache=4 dbCache=4
grpcLogFile="grpc33.log" grpcLogFile="grpc33.log"
[p2p.sub.dht]
channel=123
[rpc] [rpc]
jrpcBindAddr="localhost:8801" jrpcBindAddr="localhost:8801"
...@@ -73,6 +75,7 @@ powLimitBits = "0x1f2fffff" ...@@ -73,6 +75,7 @@ powLimitBits = "0x1f2fffff"
[consensus.sub.tendermint] [consensus.sub.tendermint]
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisAmount=100000000
genesisBlockTime=1514533394 genesisBlockTime=1514533394
timeoutTxAvail=1000 timeoutTxAvail=1000
timeoutPropose=1000 timeoutPropose=1000
...@@ -86,14 +89,21 @@ skipTimeoutCommit=false ...@@ -86,14 +89,21 @@ skipTimeoutCommit=false
createEmptyBlocks=true createEmptyBlocks=true
createEmptyBlocksInterval=1 createEmptyBlocksInterval=1
validatorNodes=["127.0.0.1:46656", "127.0.0.2:46656"] validatorNodes=["127.0.0.1:46656", "127.0.0.2:46656"]
fastSync=false
# Propose阶段是否预执行区块
preExec=false
# 签名算法,支持"secp256k1","ed25519","sm2","bls",默认为"ed25519"
signName="ed25519"
# 是否使用聚合签名,签名算法需支持该特性,比如"bls"
useAggregateSignature=false
[store] [store]
name="mavl" name="kvmvcc"
driver="leveldb" driver="leveldb"
dbPath="datadir/mavltree" dbPath="datadir/kvmvcc"
dbCache=128 dbCache=128
[store.sub.mavl] [store.sub.kvmvcc]
enableMavlPrefix=false enableMavlPrefix=false
enableMVCC=false enableMVCC=false
...@@ -126,3 +136,9 @@ signType="auth_ecdsa" ...@@ -126,3 +136,9 @@ signType="auth_ecdsa"
superManager=[ superManager=[
"14KEKbYtKKQm4wMthSK9J4La4nAiidGozt", "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt",
] ]
[metrics]
#是否使能发送metrics数据的发送
enableMetrics=false
#数据保存模式
dataEmitMode="influxdb"
...@@ -25,6 +25,7 @@ const ( ...@@ -25,6 +25,7 @@ const (
tryListenSeconds = 5 tryListenSeconds = 5
handshakeTimeout = 20 // * time.Second, handshakeTimeout = 20 // * time.Second,
maxSendQueueSize = 1024 maxSendQueueSize = 1024
minSendQueueSize = 10
defaultSendTimeout = 60 * time.Second defaultSendTimeout = 60 * time.Second
//MaxMsgPacketPayloadSize define //MaxMsgPacketPayloadSize define
MaxMsgPacketPayloadSize = 10 * 1024 * 1024 MaxMsgPacketPayloadSize = 10 * 1024 * 1024
...@@ -57,11 +58,12 @@ func Parallel(tasks ...func()) { ...@@ -57,11 +58,12 @@ func Parallel(tasks ...func()) {
wg.Wait() wg.Wait()
} }
// GenAddressByPubKey method // GenIDByPubKey method
func GenAddressByPubKey(pubkey crypto.PubKey) []byte { func GenIDByPubKey(pubkey crypto.PubKey) ID {
//must add 3 bytes ahead to make compatibly //must add 3 bytes ahead to make compatibly
typeAddr := append([]byte{byte(0x01), byte(0x01), byte(0x20)}, pubkey.Bytes()...) typeAddr := append([]byte{byte(0x01), byte(0x01), byte(0x20)}, pubkey.Bytes()[:32]...)
return crypto.Ripemd160(typeAddr) address := crypto.Ripemd160(typeAddr)
return ID(hex.EncodeToString(address))
} }
// IP2IPPort struct // IP2IPPort struct
...@@ -129,6 +131,7 @@ type Node struct { ...@@ -129,6 +131,7 @@ type Node struct {
state *ConsensusState state *ConsensusState
broadcastChannel chan MsgInfo broadcastChannel chan MsgInfo
unicastChannel chan MsgInfo
started uint32 // atomic started uint32 // atomic
stopped uint32 // atomic stopped uint32 // atomic
quit chan struct{} quit chan struct{}
...@@ -136,8 +139,6 @@ type Node struct { ...@@ -136,8 +139,6 @@ type Node struct {
// NewNode method // NewNode method
func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState) *Node { func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivKey, network string, version string, state *ConsensusState) *Node {
address := GenAddressByPubKey(privKey.PubKey())
node := &Node{ node := &Node{
peerSet: NewPeerSet(), peerSet: NewPeerSet(),
seeds: seeds, seeds: seeds,
...@@ -148,16 +149,18 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK ...@@ -148,16 +149,18 @@ func NewNode(seeds []string, protocol string, lAddr string, privKey crypto.PrivK
privKey: privKey, privKey: privKey,
Network: network, Network: network,
Version: version, Version: version,
ID: ID(hex.EncodeToString(address)), ID: GenIDByPubKey(privKey.PubKey()),
dialing: NewMutexMap(), dialing: NewMutexMap(),
reconnecting: NewMutexMap(), reconnecting: NewMutexMap(),
broadcastChannel: make(chan MsgInfo, maxSendQueueSize), broadcastChannel: make(chan MsgInfo, maxSendQueueSize),
unicastChannel: make(chan MsgInfo, minSendQueueSize),
state: state, state: state,
localIPs: make(map[string]net.IP), localIPs: make(map[string]net.IP),
} }
state.SetOurID(node.ID) state.SetOurID(node.ID)
state.SetBroadcastChannel(node.broadcastChannel) state.SetBroadcastChannel(node.broadcastChannel)
state.SetUnicastChannel(node.unicastChannel)
localIPs := getNaiveExternalAddress(true) localIPs := getNaiveExternalAddress(true)
if len(localIPs) > 0 { if len(localIPs) > 0 {
...@@ -179,7 +182,7 @@ func (node *Node) Start() { ...@@ -179,7 +182,7 @@ func (node *Node) Start() {
if err == nil { if err == nil {
break break
} else if i < tryListenSeconds-1 { } else if i < tryListenSeconds-1 {
time.Sleep(time.Second * 1) time.Sleep(time.Second)
} }
} }
if err != nil { if err != nil {
...@@ -213,6 +216,7 @@ func (node *Node) Start() { ...@@ -213,6 +216,7 @@ func (node *Node) Start() {
go node.StartConsensusRoutine() go node.StartConsensusRoutine()
go node.BroadcastRoutine() go node.BroadcastRoutine()
go node.UnicastRoutine()
} }
} }
...@@ -305,13 +309,33 @@ func (node *Node) BroadcastRoutine() { ...@@ -305,13 +309,33 @@ func (node *Node) BroadcastRoutine() {
for { for {
msg, ok := <-node.broadcastChannel msg, ok := <-node.broadcastChannel
if !ok { if !ok {
tendermintlog.Debug("broadcastChannel closed") tendermintlog.Info("broadcastChannel closed")
return return
} }
node.Broadcast(msg) node.Broadcast(msg)
} }
} }
// BroadcastRoutine receive to broadcast
func (node *Node) UnicastRoutine() {
for {
msg, ok := <-node.unicastChannel
if !ok {
tendermintlog.Info("unicastChannel closed")
return
}
for _, peer := range node.peerSet.List() {
if peer.ID() == msg.PeerID {
success := peer.Send(msg)
if !success {
tendermintlog.Error("send failure in UnicastRoutine")
}
break
}
}
}
}
func (node *Node) connectComming(inConn net.Conn) { func (node *Node) connectComming(inConn net.Conn) {
maxPeers := maxNumPeers maxPeers := maxNumPeers
if maxPeers <= node.peerSet.Size() { if maxPeers <= node.peerSet.Size() {
...@@ -640,7 +664,7 @@ func dial(addr string) (net.Conn, error) { ...@@ -640,7 +664,7 @@ func dial(addr string) (net.Conn, error) {
func newOutboundPeerConn(addr string, ourNodePrivKey crypto.PrivKey, onPeerError func(Peer, interface{}), state *ConsensusState) (*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("newOutboundPeerConn dial fail:%v", err)
} }
pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state) pc, err := newPeerConn(conn, true, true, ourNodePrivKey, onPeerError, state)
...@@ -684,7 +708,7 @@ func newPeerConn( ...@@ -684,7 +708,7 @@ func newPeerConn(
// Encrypt connection // Encrypt connection
conn, err = MakeSecretConnection(conn, ourNodePrivKey) conn, err = MakeSecretConnection(conn, ourNodePrivKey)
if err != nil { if err != nil {
return pc, fmt.Errorf("Error creating peer:%v", err) return pc, fmt.Errorf("MakeSecretConnection fail:%v", err)
} }
// Only the information we already have // Only the information we already have
......
...@@ -54,17 +54,19 @@ func TestParallel(t *testing.T) { ...@@ -54,17 +54,19 @@ func TestParallel(t *testing.T) {
assert.Equal(t, 6, sum) assert.Equal(t, 6, sum)
} }
func TestGenAddressByPubKey(t *testing.T) { func TestGenIDByPubKey(t *testing.T) {
tmp, err := hex.DecodeString(privKey) tmp, err := hex.DecodeString(privKey)
assert.Nil(t, err) assert.Nil(t, err)
priv, err := secureConnCrypto.PrivKeyFromBytes(tmp) priv, err := secureConnCrypto.PrivKeyFromBytes(tmp)
assert.Nil(t, err) assert.Nil(t, err)
addr := GenAddressByPubKey(priv.PubKey()) id := GenIDByPubKey(priv.PubKey())
addr, err := hex.DecodeString(string(id))
assert.Nil(t, err)
strAddr := fmt.Sprintf("%X", addr) strAddr := fmt.Sprintf("%X", addr)
assert.Equal(t, expectAddress, strAddr) assert.Equal(t, expectAddress, strAddr)
fmt.Println("TestGenAddressByPubKey ok") fmt.Println("TestGenIDByPubKey ok")
} }
func TestIP2IPPort(t *testing.T) { func TestIP2IPPort(t *testing.T) {
...@@ -154,7 +156,6 @@ func testUpdateStateRoutine(t *testing.T, pc *peerConn) { ...@@ -154,7 +156,6 @@ func testUpdateStateRoutine(t *testing.T, pc *peerConn) {
}, },
} }
ps := pc.state ps := pc.state
pc.waitQuit.Add(1)
go pc.updateStateRoutine() go pc.updateStateRoutine()
//NewRoundStepID msg //NewRoundStepID msg
...@@ -249,7 +250,6 @@ func testUpdateStateRoutine(t *testing.T, pc *peerConn) { ...@@ -249,7 +250,6 @@ func testUpdateStateRoutine(t *testing.T, pc *peerConn) {
assert.NotNil(t, ps.getVoteBitArray(3, 2, ttypes.VoteTypePrecommit)) assert.NotNil(t, ps.getVoteBitArray(3, 2, ttypes.VoteTypePrecommit))
pc.quitUpdate <- struct{}{} pc.quitUpdate <- struct{}{}
pc.waitQuit.Wait()
fmt.Println("testUpdateStateRoutine ok") fmt.Println("testUpdateStateRoutine ok")
} }
...@@ -8,13 +8,11 @@ import ( ...@@ -8,13 +8,11 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"net" "net"
"reflect" "reflect"
"runtime/debug"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
...@@ -56,8 +54,6 @@ type Peer interface { ...@@ -56,8 +54,6 @@ type Peer interface {
Stop() Stop()
SetTransferChannel(chan MsgInfo) SetTransferChannel(chan MsgInfo)
//Set(string, interface{})
//Get(string) interface{}
} }
// PeerConnState struct // PeerConnState struct
...@@ -85,10 +81,8 @@ type peerConn struct { ...@@ -85,10 +81,8 @@ type peerConn struct {
started uint32 //atomic started uint32 //atomic
stopped uint32 // atomic stopped uint32 // atomic
quitSend chan struct{}
quitUpdate chan struct{} quitUpdate chan struct{}
quitBeat chan struct{} quitBeat chan struct{}
waitQuit sync.WaitGroup
transferChannel chan MsgInfo transferChannel chan MsgInfo
...@@ -222,8 +216,7 @@ func (pc *peerConn) ID() ID { ...@@ -222,8 +216,7 @@ func (pc *peerConn) ID() ID {
if len(pc.id) != 0 { if len(pc.id) != 0 {
return pc.id return pc.id
} }
address := GenAddressByPubKey(pc.conn.(*SecretConnection).RemotePubKey()) pc.id = GenIDByPubKey(pc.conn.(*SecretConnection).RemotePubKey())
pc.id = ID(hex.EncodeToString(address))
return pc.id return pc.id
} }
...@@ -265,6 +258,11 @@ func (pc *peerConn) SetTransferChannel(transferChannel chan MsgInfo) { ...@@ -265,6 +258,11 @@ func (pc *peerConn) SetTransferChannel(transferChannel chan MsgInfo) {
pc.transferChannel = transferChannel pc.transferChannel = transferChannel
} }
func (pc *peerConn) String() string {
return fmt.Sprintf("PeerConn{outbound:%v persistent:%v ip:%s id:%s started:%v stopped:%v}",
pc.outbound, pc.persistent, pc.ip.String(), pc.id, pc.started, pc.stopped)
}
func (pc *peerConn) CloseConn() { func (pc *peerConn) CloseConn() {
err := pc.conn.Close() // nolint: errcheck err := pc.conn.Close() // nolint: errcheck
if err != nil { if err != nil {
...@@ -358,7 +356,7 @@ func (pc *peerConn) Send(msg MsgInfo) bool { ...@@ -358,7 +356,7 @@ func (pc *peerConn) Send(msg MsgInfo) bool {
atomic.AddInt32(&pc.sendQueueSize, 1) atomic.AddInt32(&pc.sendQueueSize, 1)
return true return true
case <-time.After(defaultSendTimeout): case <-time.After(defaultSendTimeout):
tendermintlog.Error("send msg timeout", "peerip", msg.PeerIP, "msg", msg.Msg) tendermintlog.Error("send msg timeout", "peerip", msg.PeerIP, "msg", msg)
return false return false
} }
} }
...@@ -379,9 +377,25 @@ func (pc *peerConn) TrySend(msg MsgInfo) bool { ...@@ -379,9 +377,25 @@ func (pc *peerConn) TrySend(msg MsgInfo) bool {
// PickSendVote picks a vote and sends it to the peer. // PickSendVote picks a vote and sends it to the peer.
// Returns true if vote was sent. // Returns true if vote was sent.
func (pc *peerConn) PickSendVote(votes ttypes.VoteSetReader) bool { func (pc *peerConn) PickSendVote(votes ttypes.VoteSetReader) bool {
if vote, ok := pc.state.PickVoteToSend(votes); ok { if useAggSig {
if pc.state.AggPrecommit {
time.Sleep(pc.myState.PeerGossipSleep())
return false
}
aggVote := votes.GetAggVote()
if aggVote != nil {
msg := MsgInfo{TypeID: ttypes.AggVoteID, Msg: aggVote.AggVote, PeerID: pc.id, PeerIP: pc.ip.String()}
tendermintlog.Debug("Sending aggregate vote message", "msg", msg)
if pc.Send(msg) {
pc.state.SetHasAggPrecommit(aggVote)
time.Sleep(pc.myState.PeerGossipSleep())
return true
}
}
return false
} else if vote, ok := pc.state.PickVoteToSend(votes); ok {
msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()} msg := MsgInfo{TypeID: ttypes.VoteID, Msg: vote.Vote, PeerID: pc.id, PeerIP: pc.ip.String()}
tendermintlog.Debug("Sending vote message", "vote", msg) tendermintlog.Debug("Sending vote message", "msg", msg)
if pc.Send(msg) { if pc.Send(msg) {
pc.state.SetHasVote(vote) pc.state.SetHasVote(vote)
return true return true
...@@ -406,7 +420,6 @@ func (pc *peerConn) Start() error { ...@@ -406,7 +420,6 @@ func (pc *peerConn) Start() error {
pc.pongChannel = make(chan struct{}) pc.pongChannel = make(chan struct{})
pc.sendQueue = make(chan MsgInfo, maxSendQueueSize) pc.sendQueue = make(chan MsgInfo, maxSendQueueSize)
pc.sendBuffer = make([]byte, 0, MaxMsgPacketPayloadSize) pc.sendBuffer = make([]byte, 0, MaxMsgPacketPayloadSize)
pc.quitSend = make(chan struct{})
pc.quitUpdate = make(chan struct{}) pc.quitUpdate = make(chan struct{})
pc.quitBeat = make(chan struct{}) pc.quitBeat = make(chan struct{})
pc.state = &PeerConnState{ip: pc.ip, PeerRoundState: ttypes.PeerRoundState{ pc.state = &PeerConnState{ip: pc.ip, PeerRoundState: ttypes.PeerRoundState{
...@@ -417,7 +430,6 @@ func (pc *peerConn) Start() error { ...@@ -417,7 +430,6 @@ func (pc *peerConn) Start() error {
}} }}
pc.updateStateQueue = make(chan MsgInfo, maxSendQueueSize) pc.updateStateQueue = make(chan MsgInfo, maxSendQueueSize)
pc.heartbeatQueue = make(chan proto.Message, 100) pc.heartbeatQueue = make(chan proto.Message, 100)
pc.waitQuit.Add(5) //heartbeatRoutine, updateStateRoutine,gossipDataRoutine,gossipVotesRoutine,queryMaj23Routine
go pc.sendRoutine() go pc.sendRoutine()
go pc.recvRoutine() go pc.recvRoutine()
...@@ -434,27 +446,8 @@ func (pc *peerConn) Start() error { ...@@ -434,27 +446,8 @@ func (pc *peerConn) Start() error {
func (pc *peerConn) Stop() { func (pc *peerConn) Stop() {
if atomic.CompareAndSwapUint32(&pc.stopped, 0, 1) { if atomic.CompareAndSwapUint32(&pc.stopped, 0, 1) {
pc.quitSend <- struct{}{}
pc.quitUpdate <- struct{}{}
pc.quitBeat <- struct{}{}
pc.waitQuit.Wait()
tendermintlog.Info("peerConn stop waitQuit", "peerIP", pc.ip.String())
close(pc.sendQueue)
pc.sendQueue = nil
pc.transferChannel = nil
pc.CloseConn() pc.CloseConn()
tendermintlog.Info("peerConn stop finish", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn close connection", "peerIP", pc.ip.String())
}
}
// Catch panics, usually caused by remote disconnects.
func (pc *peerConn) _recover() {
if r := recover(); r != nil {
stack := debug.Stack()
err := StackError{r, stack}
pc.stopForError(err)
} }
} }
...@@ -468,12 +461,9 @@ func (pc *peerConn) stopForError(r interface{}) { ...@@ -468,12 +461,9 @@ func (pc *peerConn) stopForError(r interface{}) {
} }
func (pc *peerConn) sendRoutine() { func (pc *peerConn) sendRoutine() {
defer pc._recover()
FOR_LOOP: FOR_LOOP:
for { for {
select { select {
case <-pc.quitSend:
break FOR_LOOP
case msg := <-pc.sendQueue: case msg := <-pc.sendQueue:
bytes, err := proto.Marshal(msg.Msg) bytes, err := proto.Marshal(msg.Msg)
if err != nil { if err != nil {
...@@ -525,7 +515,6 @@ FOR_LOOP: ...@@ -525,7 +515,6 @@ FOR_LOOP:
} }
func (pc *peerConn) recvRoutine() { func (pc *peerConn) recvRoutine() {
defer pc._recover()
FOR_LOOP: FOR_LOOP:
for { for {
//typeID+msgLen+msg //typeID+msgLen+msg
...@@ -563,7 +552,7 @@ FOR_LOOP: ...@@ -563,7 +552,7 @@ FOR_LOOP:
continue continue
} }
if pc.transferChannel != nil && (pkt.TypeID == ttypes.ProposalID || pkt.TypeID == ttypes.VoteID || if pc.transferChannel != nil && (pkt.TypeID == ttypes.ProposalID || pkt.TypeID == ttypes.VoteID ||
pkt.TypeID == ttypes.ProposalBlockID) { pkt.TypeID == ttypes.ProposalBlockID || pkt.TypeID == ttypes.AggVoteID) {
pc.transferChannel <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()} pc.transferChannel <- MsgInfo{pkt.TypeID, realMsg.(proto.Message), pc.ID(), pc.ip.String()}
if pkt.TypeID == ttypes.ProposalID { if pkt.TypeID == ttypes.ProposalID {
proposal := realMsg.(*tmtypes.Proposal) proposal := realMsg.(*tmtypes.Proposal)
...@@ -577,6 +566,9 @@ FOR_LOOP: ...@@ -577,6 +566,9 @@ FOR_LOOP:
block := &ttypes.TendermintBlock{TendermintBlock: realMsg.(*tmtypes.TendermintBlock)} block := &ttypes.TendermintBlock{TendermintBlock: realMsg.(*tmtypes.TendermintBlock)}
tendermintlog.Debug("Receiving proposal block", "block-height", block.Header.Height, "peerip", pc.ip.String()) tendermintlog.Debug("Receiving proposal block", "block-height", block.Header.Height, "peerip", pc.ip.String())
pc.state.SetHasProposalBlock(block) pc.state.SetHasProposalBlock(block)
} else if pkt.TypeID == ttypes.AggVoteID {
aggVote := &ttypes.AggVote{AggVote: realMsg.(*tmtypes.AggVote)}
tendermintlog.Debug("Receiving aggregate vote", "aggVote-height", aggVote.Height, "peerip", pc.ip.String())
} }
} else if pkt.TypeID == ttypes.ProposalHeartbeatID { } else if pkt.TypeID == ttypes.ProposalHeartbeatID {
pc.heartbeatQueue <- realMsg.(*tmtypes.Heartbeat) pc.heartbeatQueue <- realMsg.(*tmtypes.Heartbeat)
...@@ -591,10 +583,8 @@ FOR_LOOP: ...@@ -591,10 +583,8 @@ FOR_LOOP:
} }
} }
} }
pc.quitUpdate <- struct{}{}
close(pc.pongChannel) pc.quitBeat <- struct{}{}
close(pc.heartbeatQueue)
close(pc.updateStateQueue)
tendermintlog.Info("peerConn stop recvRoutine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop recvRoutine", "peerIP", pc.ip.String())
} }
...@@ -603,7 +593,6 @@ FOR_LOOP: ...@@ -603,7 +593,6 @@ FOR_LOOP:
for { for {
select { select {
case <-pc.quitUpdate: case <-pc.quitUpdate:
pc.waitQuit.Done()
break FOR_LOOP break FOR_LOOP
case msg := <-pc.updateStateQueue: case msg := <-pc.updateStateQueue:
typeID := msg.TypeID typeID := msg.TypeID
...@@ -662,6 +651,7 @@ FOR_LOOP: ...@@ -662,6 +651,7 @@ FOR_LOOP:
} }
} }
} }
close(pc.updateStateQueue)
tendermintlog.Info("peerConn stop updateStateRoutine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop updateStateRoutine", "peerIP", pc.ip.String())
} }
...@@ -670,15 +660,17 @@ FOR_LOOP: ...@@ -670,15 +660,17 @@ FOR_LOOP:
for { for {
select { select {
case <-pc.quitBeat: case <-pc.quitBeat:
pc.waitQuit.Done()
break FOR_LOOP break FOR_LOOP
case heartbeat := <-pc.heartbeatQueue: case heartbeat := <-pc.heartbeatQueue:
msg := heartbeat.(*tmtypes.Heartbeat) msg, ok := heartbeat.(*tmtypes.Heartbeat)
if ok {
tendermintlog.Debug("Received proposal heartbeat message", tendermintlog.Debug("Received proposal heartbeat message",
"height", msg.Height, "round", msg.Round, "sequence", msg.Sequence, "height", msg.Height, "round", msg.Round, "sequence", msg.Sequence,
"valIdx", msg.ValidatorIndex, "valAddr", msg.ValidatorAddress) "valIdx", msg.ValidatorIndex, "valAddr", msg.ValidatorAddress)
} }
} }
}
close(pc.heartbeatQueue)
tendermintlog.Info("peerConn stop heartbeatRoutine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop heartbeatRoutine", "peerIP", pc.ip.String())
} }
...@@ -687,7 +679,6 @@ OUTER_LOOP: ...@@ -687,7 +679,6 @@ OUTER_LOOP:
for { for {
// Manage disconnects from self or peer. // Manage disconnects from self or peer.
if !pc.IsRunning() { if !pc.IsRunning() {
pc.waitQuit.Done()
tendermintlog.Info("peerConn stop gossipDataRoutine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop gossipDataRoutine", "peerIP", pc.ip.String())
return return
} }
...@@ -789,7 +780,6 @@ OUTER_LOOP: ...@@ -789,7 +780,6 @@ OUTER_LOOP:
for { for {
// Manage disconnects from self or peer. // Manage disconnects from self or peer.
if !pc.IsRunning() { if !pc.IsRunning() {
pc.waitQuit.Done()
tendermintlog.Info("peerConn stop gossipVotesRoutine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop gossipVotesRoutine", "peerIP", pc.ip.String())
return return
} }
...@@ -806,7 +796,7 @@ OUTER_LOOP: ...@@ -806,7 +796,7 @@ OUTER_LOOP:
// If height matches, then send LastCommit, Prevotes, Precommits. // If height matches, then send LastCommit, Prevotes, Precommits.
if rs.Height == prs.Height { if rs.Height == prs.Height {
if pc.gossipVotesForHeight(rs, &prs.PeerRoundState) { if !useAggSig && pc.gossipVotesForHeight(rs, &prs.PeerRoundState) {
continue OUTER_LOOP continue OUTER_LOOP
} }
} }
...@@ -914,7 +904,6 @@ OUTER_LOOP: ...@@ -914,7 +904,6 @@ OUTER_LOOP:
for { for {
// Manage disconnects from self or peer. // Manage disconnects from self or peer.
if !pc.IsRunning() { if !pc.IsRunning() {
pc.waitQuit.Done()
tendermintlog.Info("peerConn stop queryMaj23Routine", "peerIP", pc.ip.String()) tendermintlog.Info("peerConn stop queryMaj23Routine", "peerIP", pc.ip.String())
return return
} }
...@@ -1003,20 +992,6 @@ OUTER_LOOP: ...@@ -1003,20 +992,6 @@ OUTER_LOOP:
} }
} }
// StackError struct
type StackError struct {
Err interface{}
Stack []byte
}
func (se StackError) String() string {
return fmt.Sprintf("Error: %v\nStack: %s", se.Err, se.Stack)
}
func (se StackError) Error() string {
return se.String()
}
// GetRoundState returns an atomic snapshot of the PeerRoundState. // GetRoundState returns an atomic snapshot of the PeerRoundState.
// There's no point in mutating it since it won't change PeerState. // There's no point in mutating it since it won't change PeerState.
func (ps *PeerConnState) GetRoundState() *ttypes.PeerRoundState { func (ps *PeerConnState) GetRoundState() *ttypes.PeerRoundState {
...@@ -1073,6 +1048,23 @@ func (ps *PeerConnState) SetHasProposalBlock(block *ttypes.TendermintBlock) { ...@@ -1073,6 +1048,23 @@ func (ps *PeerConnState) SetHasProposalBlock(block *ttypes.TendermintBlock) {
ps.ProposalBlock = true ps.ProposalBlock = true
} }
// SetHasAggPrecommit sets the given aggregate precommit as known for the peer.
func (ps *PeerConnState) SetHasAggPrecommit(aggVote *ttypes.AggVote) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
if ps.Height != aggVote.Height || ps.Round != int(aggVote.Round) {
return
}
if ps.AggPrecommit {
return
}
tendermintlog.Debug("Peer set aggregate precommit", "peerip", ps.ip.String(),
"peer-state", fmt.Sprintf("%v/%v/%v", ps.Height, ps.Round, ps.Step),
"aggVote(H/R)", fmt.Sprintf("%v/%v", aggVote.Height, aggVote.Round))
ps.AggPrecommit = true
}
// PickVoteToSend picks a vote to send to the peer. // PickVoteToSend picks a vote to send to the peer.
// Returns true if a vote was picked. // Returns true if a vote was picked.
// NOTE: `votes` must be the correct Size() for the Height(). // NOTE: `votes` must be the correct Size() for the Height().
...@@ -1266,6 +1258,7 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg) ...@@ -1266,6 +1258,7 @@ func (ps *PeerConnState) ApplyNewRoundStepMessage(msg *tmtypes.NewRoundStepMsg)
// We'll update the BitArray capacity later. // We'll update the BitArray capacity later.
ps.Prevotes = nil ps.Prevotes = nil
ps.Precommits = nil ps.Precommits = nil
ps.AggPrecommit = false
} }
if psHeight == msg.Height && psRound != int(msg.Round) && int(msg.Round) == psCatchupCommitRound { if psHeight == msg.Height && psRound != int(msg.Round) && int(msg.Round) == psCatchupCommitRound {
// Peer caught up to CatchupCommitRound. // Peer caught up to CatchupCommitRound.
......
...@@ -16,12 +16,13 @@ import ( ...@@ -16,12 +16,13 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io" "io"
"net" "net"
"time" "time"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
"github.com/33cn/plugin/plugin/consensus/tendermint/types" ttypes "github.com/33cn/plugin/plugin/consensus/tendermint/types"
"golang.org/x/crypto/nacl/box" "golang.org/x/crypto/nacl/box"
"golang.org/x/crypto/nacl/secretbox" "golang.org/x/crypto/nacl/secretbox"
"golang.org/x/crypto/ripemd160" "golang.org/x/crypto/ripemd160"
...@@ -33,7 +34,6 @@ const ( ...@@ -33,7 +34,6 @@ const (
dataMaxSize = 1024 dataMaxSize = 1024
totalFrameSize = dataMaxSize + dataLenSize totalFrameSize = dataMaxSize + dataLenSize
sealedFrameSize = totalFrameSize + secretbox.Overhead sealedFrameSize = totalFrameSize + secretbox.Overhead
authSigMsgSize = (32) + (64)
) // fixed size (length prefixed) byte arrays ) // fixed size (length prefixed) byte arrays
// SecretConnection Implements net.Conn // SecretConnection Implements net.Conn
...@@ -62,7 +62,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (* ...@@ -62,7 +62,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
// (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf) // (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf)
remEphPub, err := shareEphPubKey(conn, locEphPub) remEphPub, err := shareEphPubKey(conn, locEphPub)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("shareEphPubKey: %v", err)
} }
// Compute common shared secret. // Compute common shared secret.
...@@ -96,7 +96,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (* ...@@ -96,7 +96,7 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKey) (*
// Share (in secret) each other's pubkey & challenge signature // Share (in secret) each other's pubkey & challenge signature
authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature) authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("shareAuthSignature: %v", err)
} }
remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig
if !remPubKey.VerifyBytes(challenge[:], remSignature) { if !remPubKey.VerifyBytes(challenge[:], remSignature) {
...@@ -205,7 +205,7 @@ func genEphKeys() (ephPub, ephPriv *[32]byte) { ...@@ -205,7 +205,7 @@ func genEphKeys() (ephPub, ephPriv *[32]byte) {
var err error var err error
ephPub, ephPriv, err = box.GenerateKey(crand.Reader) ephPub, ephPriv, err = box.GenerateKey(crand.Reader)
if err != nil { if err != nil {
types.PanicCrisis("Could not generate ephemeral keypairs") ttypes.PanicCrisis("Could not generate ephemeral keypairs")
} }
return return
} }
...@@ -282,26 +282,28 @@ type authSigMessage struct { ...@@ -282,26 +282,28 @@ type authSigMessage struct {
func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto.Signature) (*authSigMessage, error) { func shareAuthSignature(sc io.ReadWriter, pubKey crypto.PubKey, signature crypto.Signature) (*authSigMessage, error) {
var recvMsg authSigMessage var recvMsg authSigMessage
var err1, err2 error var err1, err2 error
pubLen := len(pubKey.Bytes())
sigLen := len(signature.Bytes())
Parallel( Parallel(
func() { func() {
msgByte := make([]byte, len(pubKey.Bytes())+len(signature.Bytes())) msgByte := make([]byte, pubLen+sigLen)
copy(msgByte, pubKey.Bytes()) copy(msgByte, pubKey.Bytes()[:pubLen])
copy(msgByte[len(pubKey.Bytes()):], signature.Bytes()) copy(msgByte[pubLen:], signature.Bytes())
_, err1 = sc.Write(msgByte) _, err1 = sc.Write(msgByte)
}, },
func() { func() {
readBuffer := make([]byte, authSigMsgSize) readBuffer := make([]byte, pubLen+sigLen)
_, err2 = io.ReadFull(sc, readBuffer) _, err2 = io.ReadFull(sc, readBuffer)
if err2 != nil { if err2 != nil {
return return
} }
recvMsg.Key, err2 = types.ConsensusCrypto.PubKeyFromBytes(readBuffer[:32]) recvMsg.Key, err2 = ttypes.ConsensusCrypto.PubKeyFromBytes(readBuffer[:pubLen])
if err2 != nil { if err2 != nil {
return return
} }
recvMsg.Sig, err2 = types.ConsensusCrypto.SignatureFromBytes(readBuffer[32:]) recvMsg.Sig, err2 = ttypes.ConsensusCrypto.SignatureFromBytes(readBuffer[pubLen:])
if err2 != nil { if err2 != nil {
return return
} }
......
...@@ -385,7 +385,7 @@ func getprivkey(key string) crypto.PrivKey { ...@@ -385,7 +385,7 @@ func getprivkey(key string) crypto.PrivKey {
if err != nil { if err != nil {
panic(err) panic(err)
} }
priv, err := cr.PrivKeyFromBytes(bkey) priv, err := cr.PrivKeyFromBytes(bkey[:32])
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
// 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 tendermint package tendermint
import ( import (
......
...@@ -24,11 +24,14 @@ import ( ...@@ -24,11 +24,14 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
const tendermintVersion = "0.1.0" const (
tendermintVersion = "0.1.0"
)
var ( var (
tendermintlog = log15.New("module", "tendermint") tendermintlog = log15.New("module", "tendermint")
genesis string genesis string
genesisAmount int64 = 1e8
genesisBlockTime int64 genesisBlockTime int64
timeoutTxAvail int32 = 1000 timeoutTxAvail int32 = 1000
timeoutPropose int32 = 3000 // millisecond timeoutPropose int32 = 3000 // millisecond
...@@ -41,12 +44,15 @@ var ( ...@@ -41,12 +44,15 @@ var (
skipTimeoutCommit = false skipTimeoutCommit = false
createEmptyBlocks = false createEmptyBlocks = false
fastSync = false fastSync = false
preExec = false
createEmptyBlocksInterval int32 // second createEmptyBlocksInterval int32 // second
validatorNodes = []string{"127.0.0.1:46656"} validatorNodes = []string{"127.0.0.1:46656"}
peerGossipSleepDuration int32 = 100 peerGossipSleepDuration int32 = 200
peerQueryMaj23SleepDuration int32 = 2000 peerQueryMaj23SleepDuration int32 = 2000
zeroHash [32]byte zeroHash [32]byte
random *rand.Rand random *rand.Rand
signName = "ed25519"
useAggSig = false
) )
func init() { func init() {
...@@ -65,7 +71,6 @@ type Client struct { ...@@ -65,7 +71,6 @@ type Client struct {
pubKey string pubKey string
csState *ConsensusState csState *ConsensusState
csStore *ConsensusStore // save consensus state csStore *ConsensusStore // save consensus state
crypto crypto.Crypto
node *Node node *Node
txsAvailable chan int64 txsAvailable chan int64
stopC chan struct{} stopC chan struct{}
...@@ -73,6 +78,7 @@ type Client struct { ...@@ -73,6 +78,7 @@ type Client struct {
type subConfig struct { type subConfig struct {
Genesis string `json:"genesis"` Genesis string `json:"genesis"`
GenesisAmount int64 `json:"genesisAmount"`
GenesisBlockTime int64 `json:"genesisBlockTime"` GenesisBlockTime int64 `json:"genesisBlockTime"`
TimeoutTxAvail int32 `json:"timeoutTxAvail"` TimeoutTxAvail int32 `json:"timeoutTxAvail"`
TimeoutPropose int32 `json:"timeoutPropose"` TimeoutPropose int32 `json:"timeoutPropose"`
...@@ -87,9 +93,12 @@ type subConfig struct { ...@@ -87,9 +93,12 @@ type subConfig struct {
CreateEmptyBlocksInterval int32 `json:"createEmptyBlocksInterval"` CreateEmptyBlocksInterval int32 `json:"createEmptyBlocksInterval"`
ValidatorNodes []string `json:"validatorNodes"` ValidatorNodes []string `json:"validatorNodes"`
FastSync bool `json:"fastSync"` FastSync bool `json:"fastSync"`
PreExec bool `json:"preExec"`
SignName string `json:"signName"`
UseAggregateSignature bool `json:"useAggregateSignature"`
} }
func (client *Client) applyConfig(sub []byte) { func applyConfig(sub []byte) {
var subcfg subConfig var subcfg subConfig
if sub != nil { if sub != nil {
types.MustDecode(sub, &subcfg) types.MustDecode(sub, &subcfg)
...@@ -97,6 +106,9 @@ func (client *Client) applyConfig(sub []byte) { ...@@ -97,6 +106,9 @@ func (client *Client) applyConfig(sub []byte) {
if subcfg.Genesis != "" { if subcfg.Genesis != "" {
genesis = subcfg.Genesis genesis = subcfg.Genesis
} }
if subcfg.GenesisAmount > 0 {
genesisAmount = subcfg.GenesisAmount
}
if subcfg.GenesisBlockTime > 0 { if subcfg.GenesisBlockTime > 0 {
genesisBlockTime = subcfg.GenesisBlockTime genesisBlockTime = subcfg.GenesisBlockTime
} }
...@@ -133,6 +145,11 @@ func (client *Client) applyConfig(sub []byte) { ...@@ -133,6 +145,11 @@ func (client *Client) applyConfig(sub []byte) {
validatorNodes = subcfg.ValidatorNodes validatorNodes = subcfg.ValidatorNodes
} }
fastSync = subcfg.FastSync fastSync = subcfg.FastSync
preExec = subcfg.PreExec
if subcfg.SignName != "" {
signName = subcfg.SignName
}
useAggSig = subcfg.UseAggregateSignature
} }
// DefaultDBProvider returns a database using the DBBackend and DBDir // DefaultDBProvider returns a database using the DBBackend and DBDir
...@@ -144,37 +161,47 @@ func DefaultDBProvider(name string) dbm.DB { ...@@ -144,37 +161,47 @@ func DefaultDBProvider(name string) dbm.DB {
// New ... // New ...
func New(cfg *types.Consensus, sub []byte) queue.Module { func New(cfg *types.Consensus, sub []byte) queue.Module {
tendermintlog.Info("Start to create tendermint client") tendermintlog.Info("Start to create tendermint client")
applyConfig(sub)
//init rand //init rand
ttypes.Init() ttypes.Init()
genDoc, err := ttypes.GenesisDocFromFile("genesis.json") signType, ok := ttypes.SignMap[signName]
if err != nil { if !ok {
tendermintlog.Error("NewTendermintClient", "msg", "GenesisDocFromFile failded", "error", err) tendermintlog.Error("Invalid sign name")
return nil return nil
} }
cr, err := crypto.New(types.GetSignName("", types.ED25519)) ttypes.CryptoName = types.GetSignName("", signType)
cr, err := crypto.New(ttypes.CryptoName)
if err != nil { if err != nil {
tendermintlog.Error("NewTendermintClient", "err", err) tendermintlog.Error("NewTendermintClient", "err", err)
return nil return nil
} }
ttypes.ConsensusCrypto = cr ttypes.ConsensusCrypto = cr
priv, err := cr.GenKey() if useAggSig {
_, err = crypto.ToAggregate(ttypes.ConsensusCrypto)
if err != nil { if err != nil {
tendermintlog.Error("NewTendermintClient", "GenKey err", err) tendermintlog.Error("ConsensusCrypto not support aggregate signature", "name", ttypes.CryptoName)
return nil
}
}
genDoc, err := ttypes.GenesisDocFromFile("genesis.json")
if err != nil {
tendermintlog.Error("NewTendermintClient", "msg", "GenesisDocFromFile fail", "error", err)
return nil return nil
} }
privValidator := ttypes.LoadOrGenPrivValidatorFS("priv_validator.json") privValidator := ttypes.LoadOrGenPrivValidatorFS("priv_validator.json")
if privValidator == nil { if privValidator == nil {
tendermintlog.Error("NewTendermintClient create priv_validator file failed") tendermintlog.Error("NewTendermintClient create priv_validator file fail")
return nil return nil
} }
ttypes.InitMessageMap() ttypes.InitMessageMap()
priv := privValidator.PrivKey
pubkey := privValidator.GetPubKey().KeyString() pubkey := privValidator.GetPubKey().KeyString()
c := drivers.NewBaseClient(cfg) c := drivers.NewBaseClient(cfg)
client := &Client{ client := &Client{
...@@ -184,21 +211,13 @@ func New(cfg *types.Consensus, sub []byte) queue.Module { ...@@ -184,21 +211,13 @@ func New(cfg *types.Consensus, sub []byte) queue.Module {
privKey: priv, privKey: priv,
pubKey: pubkey, pubKey: pubkey,
csStore: NewConsensusStore(), csStore: NewConsensusStore(),
crypto: cr,
txsAvailable: make(chan int64, 1), txsAvailable: make(chan int64, 1),
stopC: make(chan struct{}, 1), stopC: make(chan struct{}, 1),
} }
c.SetChild(client) c.SetChild(client)
client.applyConfig(sub)
return client return client
} }
// PrivValidator returns the Node's PrivValidator.
func (client *Client) PrivValidator() ttypes.PrivValidator {
return client.privValidator
}
// GenesisDoc returns the Node's GenesisDoc. // GenesisDoc returns the Node's GenesisDoc.
func (client *Client) GenesisDoc() *ttypes.GenesisDoc { func (client *Client) GenesisDoc() *ttypes.GenesisDoc {
return client.genesisDoc return client.genesisDoc
...@@ -216,6 +235,7 @@ func (client *Client) GenesisState() *State { ...@@ -216,6 +235,7 @@ func (client *Client) GenesisState() *State {
// Close TODO:may need optimize // Close TODO:may need optimize
func (client *Client) Close() { func (client *Client) Close() {
client.BaseClient.Close()
client.node.Stop() client.node.Stop()
client.stopC <- struct{}{} client.stopC <- struct{}{}
tendermintlog.Info("consensus tendermint closed") tendermintlog.Info("consensus tendermint closed")
...@@ -335,7 +355,7 @@ func (client *Client) CreateGenesisTx() (ret []*types.Transaction) { ...@@ -335,7 +355,7 @@ func (client *Client) CreateGenesisTx() (ret []*types.Transaction) {
//gen payload //gen payload
g := &cty.CoinsAction_Genesis{} g := &cty.CoinsAction_Genesis{}
g.Genesis = &types.AssetsGenesis{} g.Genesis = &types.AssetsGenesis{}
g.Genesis.Amount = 1e8 * types.Coin g.Genesis.Amount = genesisAmount * types.Coin
tx.Payload = types.Encode(&cty.CoinsAction{Value: g, Ty: cty.CoinsActionGenesis}) tx.Payload = types.Encode(&cty.CoinsAction{Value: g, Ty: cty.CoinsActionGenesis})
ret = append(ret, &tx) ret = append(ret, &tx)
return return
...@@ -405,10 +425,13 @@ func (client *Client) ProcEvent(msg *queue.Message) bool { ...@@ -405,10 +425,13 @@ func (client *Client) ProcEvent(msg *queue.Message) bool {
// CreateBlock a routine monitor whether some transactions available and tell client by available channel // CreateBlock a routine monitor whether some transactions available and tell client by available channel
func (client *Client) CreateBlock() { func (client *Client) CreateBlock() {
issleep := true issleep := true
for { for {
if client.IsClosed() {
tendermintlog.Info("CreateBlock quit")
break
}
if !client.csState.IsRunning() { if !client.csState.IsRunning() {
tendermintlog.Error("consensus not running now") tendermintlog.Info("consensus not running")
time.Sleep(time.Second) time.Sleep(time.Second)
continue continue
} }
...@@ -483,7 +506,6 @@ func (client *Client) BuildBlock() *types.Block { ...@@ -483,7 +506,6 @@ func (client *Client) BuildBlock() *types.Block {
client.AddTxsToBlock(&newblock, txs) client.AddTxsToBlock(&newblock, txs)
//固定难度 //固定难度
newblock.Difficulty = cfg.GetP(0).PowLimitBits newblock.Difficulty = cfg.GetP(0).PowLimitBits
//newblock.TxHash = merkle.CalcMerkleRoot(newblock.Txs)
newblock.BlockTime = types.Now().Unix() newblock.BlockTime = types.Now().Unix()
if lastBlock.BlockTime >= newblock.BlockTime { if lastBlock.BlockTime >= newblock.BlockTime {
newblock.BlockTime = lastBlock.BlockTime + 1 newblock.BlockTime = lastBlock.BlockTime + 1
...@@ -498,6 +520,9 @@ func (client *Client) CommitBlock(block *types.Block) error { ...@@ -498,6 +520,9 @@ func (client *Client) CommitBlock(block *types.Block) error {
if retErr != nil { if retErr != nil {
tendermintlog.Info("CommitBlock fail", "err", retErr) tendermintlog.Info("CommitBlock fail", "err", retErr)
if client.WaitBlock(block.Height) { if client.WaitBlock(block.Height) {
if !preExec {
return nil
}
curBlock, err := client.RequestBlock(block.Height) curBlock, err := client.RequestBlock(block.Height)
if err == nil { if err == nil {
if bytes.Equal(curBlock.Hash(cfg), block.Hash(cfg)) { if bytes.Equal(curBlock.Hash(cfg), block.Hash(cfg)) {
...@@ -636,7 +661,7 @@ func (client *Client) Query_NodeInfo(req *types.ReqNil) (types.Message, error) { ...@@ -636,7 +661,7 @@ func (client *Client) Query_NodeInfo(req *types.ReqNil) (types.Message, error) {
return &tmtypes.ValidatorSet{Validators: validators, Proposer: &tmtypes.Validator{}}, nil return &tmtypes.ValidatorSet{Validators: validators, Proposer: &tmtypes.Validator{}}, nil
} }
//比较newBlock是不是最优区块 // CmpBestBlock 比较newBlock是不是最优区块
func (client *Client) CmpBestBlock(newBlock *types.Block, cmpBlock *types.Block) bool { func (client *Client) CmpBestBlock(newBlock *types.Block, cmpBlock *types.Block) bool {
return false return false
} }
...@@ -272,13 +272,12 @@ func CheckState(t *testing.T, client *Client) { ...@@ -272,13 +272,12 @@ func CheckState(t *testing.T, client *Client) {
assert.Equal(t, client.csState.Prevote(0), 1000*time.Millisecond) assert.Equal(t, client.csState.Prevote(0), 1000*time.Millisecond)
assert.Equal(t, client.csState.Precommit(0), 1000*time.Millisecond) assert.Equal(t, client.csState.Precommit(0), 1000*time.Millisecond)
assert.Equal(t, client.csState.PeerGossipSleep(), 100*time.Millisecond) assert.Equal(t, client.csState.PeerGossipSleep(), 200*time.Millisecond)
assert.Equal(t, client.csState.PeerQueryMaj23Sleep(), 2000*time.Millisecond) assert.Equal(t, client.csState.PeerQueryMaj23Sleep(), 2000*time.Millisecond)
assert.Equal(t, client.csState.IsProposer(), true) assert.Equal(t, client.csState.IsProposer(), true)
assert.Nil(t, client.csState.GetPrevotesState(state.LastBlockHeight, 0, nil)) assert.Nil(t, client.csState.GetPrevotesState(state.LastBlockHeight, 0, nil))
assert.Nil(t, client.csState.GetPrecommitsState(state.LastBlockHeight, 0, nil)) assert.Nil(t, client.csState.GetPrecommitsState(state.LastBlockHeight, 0, nil))
assert.NotEmpty(t, client.csState.GetPrivValidator())
assert.NotEmpty(t, client.PrivValidator())
assert.Len(t, client.GenesisDoc().Validators, 1) assert.Len(t, client.GenesisDoc().Validators, 1)
msg1, err := client.Query_IsHealthy(&types.ReqNil{}) msg1, err := client.Query_IsHealthy(&types.ReqNil{})
......
...@@ -139,7 +139,7 @@ func Put(ip string, size string, privkey string) { ...@@ -139,7 +139,7 @@ func Put(ip string, size string, privkey string) {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
return return
} }
url := "http://" + ip + ":9801" url := "http://" + ip + ":8801"
if privkey == "" { if privkey == "" {
_, priv := genaddress() _, priv := genaddress()
privkey = common.ToHex(priv.Bytes()) privkey = common.ToHex(priv.Bytes())
......
...@@ -13,18 +13,11 @@ import ( ...@@ -13,18 +13,11 @@ import (
"time" "time"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/log/log15"
"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"
) )
var (
blocklog = log15.New("module", "tendermint-block")
// ConsensusCrypto define
ConsensusCrypto crypto.Crypto
)
// BlockID struct // BlockID struct
type BlockID struct { type BlockID struct {
tmtypes.BlockID tmtypes.BlockID
...@@ -88,11 +81,6 @@ func (b *TendermintBlock) ValidateBasic() error { ...@@ -88,11 +81,6 @@ func (b *TendermintBlock) ValidateBasic() error {
return errors.New("Zero Header.Height") return errors.New("Zero Header.Height")
} }
newTxs := int64(len(b.Data.Txs))
if b.Header.NumTxs != newTxs {
return fmt.Errorf("Wrong Header.NumTxs. Expected %v, got %v", newTxs, b.Header.NumTxs)
}
if b.Header.TotalTxs < 0 { if b.Header.TotalTxs < 0 {
return errors.New("Negative Header.TotalTxs") return errors.New("Negative Header.TotalTxs")
} }
...@@ -192,7 +180,7 @@ func (h *Header) Hash() []byte { ...@@ -192,7 +180,7 @@ func (h *Header) Hash() []byte {
} }
bytes, err := json.Marshal(h) bytes, err := json.Marshal(h)
if err != nil { if err != nil {
blocklog.Error("block header Hash() marshal failed", "error", err) ttlog.Error("block header Hash() marshal failed", "error", err)
return nil return nil
} }
return crypto.Ripemd160(bytes) return crypto.Ripemd160(bytes)
...@@ -254,6 +242,9 @@ func (commit *Commit) FirstPrecommit() *tmtypes.Vote { ...@@ -254,6 +242,9 @@ func (commit *Commit) FirstPrecommit() *tmtypes.Vote {
// Height returns the height of the commit // Height returns the height of the commit
func (commit *Commit) Height() int64 { func (commit *Commit) Height() int64 {
if commit.AggVote != nil {
return commit.AggVote.Height
}
if len(commit.Precommits) == 0 { if len(commit.Precommits) == 0 {
return 0 return 0
} }
...@@ -262,6 +253,9 @@ func (commit *Commit) Height() int64 { ...@@ -262,6 +253,9 @@ func (commit *Commit) Height() int64 {
// Round returns the round of the commit // Round returns the round of the commit
func (commit *Commit) Round() int { func (commit *Commit) Round() int {
if commit.AggVote != nil {
return int(commit.AggVote.Round)
}
if len(commit.Precommits) == 0 { if len(commit.Precommits) == 0 {
return 0 return 0
} }
...@@ -283,6 +277,10 @@ func (commit *Commit) Size() int { ...@@ -283,6 +277,10 @@ func (commit *Commit) Size() int {
// BitArray returns a BitArray of which validators voted in this commit // BitArray returns a BitArray of which validators voted in this commit
func (commit *Commit) BitArray() *BitArray { func (commit *Commit) BitArray() *BitArray {
if commit.AggVote != nil {
bitArray := &BitArray{TendermintBitArray: commit.AggVote.ValidatorArray}
return bitArray.copy()
}
if commit.bitArray == nil { if commit.bitArray == nil {
commit.bitArray = NewBitArray(len(commit.Precommits)) commit.bitArray = NewBitArray(len(commit.Precommits))
for i, precommit := range commit.Precommits { for i, precommit := range commit.Precommits {
...@@ -301,7 +299,16 @@ func (commit *Commit) GetByIndex(index int) *Vote { ...@@ -301,7 +299,16 @@ func (commit *Commit) GetByIndex(index int) *Vote {
// IsCommit returns true if there is at least one vote // IsCommit returns true if there is at least one vote
func (commit *Commit) IsCommit() bool { func (commit *Commit) IsCommit() bool {
return len(commit.Precommits) != 0 return len(commit.Precommits) != 0 || commit.AggVote != nil
}
// GetAggVote ...
func (commit *Commit) GetAggVote() *AggVote {
if commit == nil {
return nil
}
aggVote := &AggVote{commit.AggVote}
return aggVote.Copy()
} }
// ValidateBasic performs basic validation that doesn't involve state data. // ValidateBasic performs basic validation that doesn't involve state data.
...@@ -338,12 +345,28 @@ func (commit *Commit) ValidateBasic() error { ...@@ -338,12 +345,28 @@ func (commit *Commit) ValidateBasic() error {
round, precommit.Round) round, precommit.Round)
} }
} }
// validate the aggVote
if commit.AggVote != nil {
if commit.AggVote.Type != uint32(VoteTypePrecommit) {
return fmt.Errorf("Invalid aggVote type. Expected Precommit, got %v", commit.AggVote.Type)
}
if commit.AggVote.Height != height {
return fmt.Errorf("Invalid aggVote height. Expected %v, got %v", height, commit.AggVote.Height)
}
if int(commit.AggVote.Round) != round {
return fmt.Errorf("Invalid aggVote round. Expected %v, got %v", round, commit.AggVote.Round)
}
}
return nil return nil
} }
// Hash returns the hash of the commit // Hash returns the hash of the commit
func (commit *Commit) Hash() []byte { func (commit *Commit) Hash() []byte {
if commit.hash == nil { if commit.hash == nil {
if commit.AggVote != nil {
aggVote := &AggVote{AggVote: commit.AggVote}
commit.hash = aggVote.Hash()
} else {
bs := make([][]byte, len(commit.Precommits)) bs := make([][]byte, len(commit.Precommits))
for i, item := range commit.Precommits { for i, item := range commit.Precommits {
precommit := Vote{Vote: item} precommit := Vote{Vote: item}
...@@ -351,6 +374,7 @@ func (commit *Commit) Hash() []byte { ...@@ -351,6 +374,7 @@ func (commit *Commit) Hash() []byte {
} }
commit.hash = merkle.GetMerkleRoot(bs) commit.hash = merkle.GetMerkleRoot(bs)
} }
}
return commit.hash return commit.hash
} }
...@@ -366,9 +390,11 @@ func (commit *Commit) StringIndented(indent string) string { ...@@ -366,9 +390,11 @@ func (commit *Commit) StringIndented(indent string) string {
return Fmt(`Commit{ return Fmt(`Commit{
%s BlockID: %v %s BlockID: %v
%s Precommits: %v %s Precommits: %v
%s AggVote: %v
%s}#%v`, %s}#%v`,
indent, commit.BlockID, indent, commit.BlockID,
indent, strings.Join(precommitStrings, "\n"+indent+" "), indent, strings.Join(precommitStrings, "\n"+indent+" "),
indent, commit.AggVote.String(),
indent, commit.hash) indent, commit.hash)
} }
......
...@@ -4,7 +4,17 @@ ...@@ -4,7 +4,17 @@
package types package types
import "errors" import (
"errors"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
const (
AuthBLS = 259
)
var ( var (
// ErrHeightLessThanOne error type // ErrHeightLessThanOne error type
...@@ -18,3 +28,17 @@ var ( ...@@ -18,3 +28,17 @@ var (
// ErrLastBlockID error type // ErrLastBlockID error type
ErrLastBlockID = errors.New("ErrLastBlockID") ErrLastBlockID = errors.New("ErrLastBlockID")
) )
var (
ttlog = log15.New("module", "tendermint-types")
// ConsensusCrypto define
ConsensusCrypto crypto.Crypto
CryptoName string
// SignMap define sign type
SignMap = map[string]int{
"secp256k1": types.SECP256K1,
"ed25519": types.ED25519,
"sm2": types.SM2,
"bls": AuthBLS,
}
)
...@@ -138,6 +138,30 @@ func (hvs *HeightVoteSet) AddVote(vote *Vote, peerID string) (added bool, err er ...@@ -138,6 +138,30 @@ func (hvs *HeightVoteSet) AddVote(vote *Vote, peerID string) (added bool, err er
return return
} }
// AddAggVote Duplicate votes return added=false, err=nil.
// By convention, peerKey is "" if origin is self.
func (hvs *HeightVoteSet) AddAggVote(vote *AggVote, peerID string) (added bool, err error) {
hvs.mtx.Lock()
defer hvs.mtx.Unlock()
if !IsVoteTypeValid(byte(vote.Type)) {
return
}
round := int(vote.Round)
voteSet := hvs.getVoteSet(round, byte(vote.Type))
if voteSet == nil {
if rndz := hvs.peerCatchupRounds[peerID]; len(rndz) < 2 {
hvs.addRound(int(vote.Round))
voteSet = hvs.getVoteSet(round, byte(vote.Type))
hvs.peerCatchupRounds[peerID] = append(rndz, round)
} else {
err = errors.New("Peer has sent a aggregate vote that does not match our round for more than one round")
return
}
}
added, err = voteSet.AddAggVote(vote)
return
}
// Prevotes ... // Prevotes ...
func (hvs *HeightVoteSet) Prevotes(round int) *VoteSet { func (hvs *HeightVoteSet) Prevotes(round int) *VoteSet {
hvs.mtx.Lock() hvs.mtx.Lock()
......
...@@ -113,7 +113,7 @@ func (params *ConsensusParams) Validate() error { ...@@ -113,7 +113,7 @@ func (params *ConsensusParams) Validate() error {
func (params *ConsensusParams) Hash() []byte { func (params *ConsensusParams) Hash() []byte {
bytes, err := json.Marshal(params) bytes, err := json.Marshal(params)
if err != nil { if err != nil {
blocklog.Error("block header Hash() marshal failed", "error", err) ttlog.Error("block header Hash() marshal failed", "error", err)
return nil return nil
} }
return crypto.Ripemd160(bytes) return crypto.Ripemd160(bytes)
......
...@@ -6,6 +6,7 @@ package types ...@@ -6,6 +6,7 @@ package types
import ( import (
"bytes" "bytes"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
...@@ -14,8 +15,6 @@ import ( ...@@ -14,8 +15,6 @@ import (
"sync" "sync"
"time" "time"
"encoding/hex"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
) )
...@@ -296,15 +295,15 @@ func (pv *PrivValidatorImp) save() { ...@@ -296,15 +295,15 @@ func (pv *PrivValidatorImp) save() {
LastStep: pv.LastStep, LastStep: pv.LastStep,
LastSignature: nil, LastSignature: nil,
} }
privValFS.PrivKey = KeyText{Kind: "ed25519", Data: Fmt("%X", pv.PrivKey.Bytes()[:])} privValFS.PrivKey = KeyText{Kind: CryptoName, Data: Fmt("%X", pv.PrivKey.Bytes()[:])}
privValFS.PubKey = KeyText{Kind: "ed25519", Data: pv.PubKey.KeyString()} privValFS.PubKey = KeyText{Kind: CryptoName, Data: pv.PubKey.KeyString()}
if len(pv.LastSignBytes) != 0 { if len(pv.LastSignBytes) != 0 {
tmp := Fmt("%X", pv.LastSignBytes[:]) tmp := Fmt("%X", pv.LastSignBytes[:])
privValFS.LastSignBytes = tmp privValFS.LastSignBytes = tmp
} }
if pv.LastSignature != nil { if pv.LastSignature != nil {
sig := Fmt("%X", pv.LastSignature.Bytes()[:]) sig := Fmt("%X", pv.LastSignature.Bytes()[:])
privValFS.LastSignature = &KeyText{Kind: "ed25519", Data: sig} privValFS.LastSignature = &KeyText{Kind: CryptoName, Data: sig}
} }
jsonBytes, err := json.Marshal(privValFS) jsonBytes, err := json.Marshal(privValFS)
if err != nil { if err != nil {
......
...@@ -42,6 +42,7 @@ const ( ...@@ -42,6 +42,7 @@ const (
ProposalHeartbeatID = byte(0x08) ProposalHeartbeatID = byte(0x08)
ProposalBlockID = byte(0x09) ProposalBlockID = byte(0x09)
ValidBlockID = byte(0x0a) ValidBlockID = byte(0x0a)
AggVoteID = byte(0x0b)
PacketTypePing = byte(0xff) PacketTypePing = byte(0xff)
PacketTypePong = byte(0xfe) PacketTypePong = byte(0xfe)
...@@ -60,6 +61,7 @@ func InitMessageMap() { ...@@ -60,6 +61,7 @@ func InitMessageMap() {
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{}), ValidBlockID: reflect.TypeOf(tmtypes.ValidBlockMsg{}),
AggVoteID: reflect.TypeOf(tmtypes.AggVote{}),
} }
} }
...@@ -186,6 +188,7 @@ type PeerRoundState struct { ...@@ -186,6 +188,7 @@ type PeerRoundState struct {
LastCommit *BitArray // All commit precommits of commit for last height. LastCommit *BitArray // All commit precommits of commit for last height.
CatchupCommitRound int // Round that we have commit for. Not necessarily unique. -1 if none. 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 CatchupCommit *BitArray // All commit precommits peer has for this height & CatchupCommitRound
AggPrecommit bool // True if peer has aggregate precommit for this round
} }
// String returns a string representation of the PeerRoundState // String returns a string representation of the PeerRoundState
...@@ -204,17 +207,19 @@ func (prs PeerRoundState) StringIndented(indent string) string { ...@@ -204,17 +207,19 @@ func (prs PeerRoundState) StringIndented(indent string) string {
%s Prevotes %v %s Prevotes %v
%s Precommits %v %s Precommits %v
%s LastCommit %v (round %v) %s LastCommit %v (round %v)
%s Catchup %v (round %v) %s CatchupCommit %v (round %v)
%s AggPrecommit %v
%s}`, %s}`,
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.ProposalBlockHash,
indent, prs.ProposalPOL, prs.ProposalPOLRound, indent, prs.ProposalPOL, prs.ProposalPOLRound,
indent, prs.Prevotes, indent, prs.Prevotes,
indent, prs.Precommits, indent, prs.Precommits,
indent, prs.LastCommit, prs.LastCommitRound, indent, prs.LastCommit, prs.LastCommitRound,
indent, prs.CatchupCommit, prs.CatchupCommitRound, indent, prs.CatchupCommit, prs.CatchupCommitRound,
indent, prs.AggPrecommit,
indent) indent)
} }
...@@ -274,6 +279,12 @@ type CanonicalJSONOnceVote struct { ...@@ -274,6 +279,12 @@ type CanonicalJSONOnceVote struct {
Vote CanonicalJSONVote `json:"vote"` Vote CanonicalJSONVote `json:"vote"`
} }
// CanonicalJSONOnceAggVote ...
type CanonicalJSONOnceAggVote struct {
ChainID string `json:"chain_id"`
AggVote CanonicalJSONVote `json:"agg_vote"`
}
// CanonicalJSONOnceHeartbeat ... // CanonicalJSONOnceHeartbeat ...
type CanonicalJSONOnceHeartbeat struct { type CanonicalJSONOnceHeartbeat struct {
ChainID string `json:"chain_id"` ChainID string `json:"chain_id"`
...@@ -305,11 +316,26 @@ func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal { ...@@ -305,11 +316,26 @@ func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal {
// CanonicalVote ... // CanonicalVote ...
func CanonicalVote(vote *Vote) CanonicalJSONVote { func CanonicalVote(vote *Vote) CanonicalJSONVote {
timestamp := ""
if !vote.UseAggSig {
timestamp = CanonicalTime(time.Unix(0, vote.Timestamp))
}
return CanonicalJSONVote{
BlockID: CanonicalJSONBlockID{Hash: vote.BlockID.Hash},
Height: vote.Height,
Round: int(vote.Round),
Timestamp: timestamp,
Type: byte(vote.Type),
}
}
// CanonicalAggVote ...
func CanonicalAggVote(vote *AggVote) CanonicalJSONVote {
return CanonicalJSONVote{ return CanonicalJSONVote{
BlockID: CanonicalJSONBlockID{Hash: vote.BlockID.Hash}, BlockID: CanonicalJSONBlockID{Hash: vote.BlockID.Hash},
Height: vote.Height, Height: vote.Height,
Round: int(vote.Round), Round: int(vote.Round),
Timestamp: CanonicalTime(time.Unix(0, vote.Timestamp)), Timestamp: "",
Type: byte(vote.Type), Type: byte(vote.Type),
} }
} }
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"time" "time"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/log/log15"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types" tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
) )
...@@ -27,7 +26,7 @@ var ( ...@@ -27,7 +26,7 @@ var (
ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature") ErrVoteNonDeterministicSignature = errors.New("Non-deterministic signature")
ErrVoteConflict = errors.New("Conflicting vote") ErrVoteConflict = errors.New("Conflicting vote")
ErrVoteNil = errors.New("Nil vote") ErrVoteNil = errors.New("Nil vote")
votelog = log15.New("module", "tendermint-vote") ErrAggVoteNil = errors.New("Nil aggregate vote")
) )
// Signable is an interface for all signable things. // Signable is an interface for all signable things.
...@@ -156,7 +155,7 @@ func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error ...@@ -156,7 +155,7 @@ func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error
byteVote, e := json.Marshal(&canonical) byteVote, e := json.Marshal(&canonical)
if e != nil { if e != nil {
*err = e *err = e
votelog.Error("vote WriteSignBytes marshal failed", "err", e) ttlog.Error("vote WriteSignBytes marshal failed", "err", e)
return return
} }
number, writeErr := w.Write(byteVote) number, writeErr := w.Write(byteVote)
...@@ -200,7 +199,7 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error { ...@@ -200,7 +199,7 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
sig, err := ConsensusCrypto.SignatureFromBytes(vote.Signature) sig, err := ConsensusCrypto.SignatureFromBytes(vote.Signature)
if err != nil { if err != nil {
votelog.Error("vote Verify failed", "err", err) ttlog.Error("vote Verify fail", "err", err)
return err return err
} }
...@@ -217,7 +216,109 @@ func (vote *Vote) Hash() []byte { ...@@ -217,7 +216,109 @@ func (vote *Vote) Hash() []byte {
} }
bytes, err := json.Marshal(vote) bytes, err := json.Marshal(vote)
if err != nil { if err != nil {
votelog.Error("vote hash marshal failed", "err", err) ttlog.Error("vote hash marshal failed", "err", err)
return nil
}
return crypto.Ripemd160(bytes)
}
// AggVote Represents a prevote, precommit, or commit vote from validators for consensus.
type AggVote struct {
*tmtypes.AggVote
}
// WriteSignBytes ...
func (aggVote *AggVote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
if *err != nil {
return
}
canonical := CanonicalJSONOnceAggVote{
chainID,
CanonicalAggVote(aggVote),
}
byteVote, e := json.Marshal(&canonical)
if e != nil {
*err = e
ttlog.Error("aggVote WriteSignBytes marshal failed", "err", e)
return
}
number, writeErr := w.Write(byteVote)
*n = number
*err = writeErr
}
// Verify ...
func (aggVote *AggVote) Verify(chainID string, valSet *ValidatorSet) error {
aggSig, err := ConsensusCrypto.SignatureFromBytes(aggVote.Signature)
if err != nil {
return errors.New("invalid aggregate signature")
}
pubs := make([]crypto.PubKey, 0)
arr := &BitArray{TendermintBitArray: aggVote.ValidatorArray}
for i, val := range valSet.Validators {
if arr.GetIndex(i) {
pub, _ := ConsensusCrypto.PubKeyFromBytes(val.PubKey)
pubs = append(pubs, pub)
}
}
origVote := &Vote{&tmtypes.Vote{
BlockID: aggVote.BlockID,
Height: aggVote.Height,
Round: aggVote.Round,
Timestamp: aggVote.Timestamp,
Type: aggVote.Type,
UseAggSig: true,
}}
aggr, err := crypto.ToAggregate(ConsensusCrypto)
if err != nil {
return err
}
err = aggr.VerifyAggregatedOne(pubs, SignBytes(chainID, origVote), aggSig)
if err != nil {
ttlog.Error("aggVote Verify fail", "err", err, "aggVote", aggVote, "aggSig", aggSig)
return err
}
return nil
}
// Copy ...
func (aggVote *AggVote) Copy() *AggVote {
copy := *aggVote
return &copy
}
func (aggVote *AggVote) String() string {
if aggVote == nil {
return "nil-AggVote"
}
var typeString string
switch byte(aggVote.Type) {
case VoteTypePrevote:
typeString = "Prevote"
case VoteTypePrecommit:
typeString = "Precommit"
default:
PanicSanity("Unknown vote type")
}
bitArray := &BitArray{TendermintBitArray: aggVote.ValidatorArray}
return fmt.Sprintf("AggVote{%X %v/%02d/%v(%v) %X %X @ %s %v}",
Fingerprint(aggVote.ValidatorAddress),
aggVote.Height, aggVote.Round, aggVote.Type, typeString,
Fingerprint(aggVote.BlockID.Hash), aggVote.Signature,
CanonicalTime(time.Unix(0, aggVote.Timestamp)),
bitArray)
}
// Hash ...
func (aggVote *AggVote) Hash() []byte {
if aggVote == nil {
return nil
}
bytes, err := json.Marshal(aggVote)
if err != nil {
ttlog.Error("aggVote hash marshal failed", "err", err)
return nil return nil
} }
......
...@@ -12,13 +12,10 @@ import ( ...@@ -12,13 +12,10 @@ import (
"strings" "strings"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/common/merkle" "github.com/33cn/chain33/common/merkle"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
var validatorsetlog = log15.New("module", "tendermint-val")
// Validator ... // Validator ...
type Validator struct { type Validator struct {
Address []byte `json:"address"` Address []byte `json:"address"`
...@@ -313,7 +310,7 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height ...@@ -313,7 +310,7 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
if valSet.Size() != len(commit.Precommits) { if valSet.Size() != len(commit.Precommits) {
return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", valSet.Size(), len(commit.Precommits)) return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", valSet.Size(), len(commit.Precommits))
} }
validatorsetlog.Debug("VerifyCommit will get commit height", "height", commit.Height()) ttlog.Debug("VerifyCommit will get commit height", "height", commit.Height())
commitHeight := commit.Height() commitHeight := commit.Height()
if height != commitHeight { if height != commitHeight {
return fmt.Errorf("VerifyCommit 1 Invalid commit -- wrong height: %v vs %v", height, commitHeight) return fmt.Errorf("VerifyCommit 1 Invalid commit -- wrong height: %v vs %v", height, commitHeight)
...@@ -322,6 +319,29 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height ...@@ -322,6 +319,29 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
talliedVotingPower := int64(0) talliedVotingPower := int64(0)
round := commit.Round() round := commit.Round()
if commit.AggVote != nil {
aggVote := &AggVote{AggVote: commit.AggVote}
// Make sure the step matches
if (aggVote.Height != height) ||
(int(aggVote.Round) != round) ||
(aggVote.Type != uint32(VoteTypePrecommit)) {
return errors.Wrapf(ErrVoteUnexpectedStep, "Got %d/%d/%d, expected %d/%d/%d",
height, round, VoteTypePrecommit,
aggVote.Height, aggVote.Round, aggVote.Type)
}
// Check signature
err := aggVote.Verify(chainID, valSet)
if err != nil {
return err
}
// calc voting power
arr := &BitArray{TendermintBitArray: aggVote.ValidatorArray}
for i, val := range valSet.Validators {
if arr.GetIndex(i) {
talliedVotingPower += val.VotingPower
}
}
} else {
for idx, item := range commit.Precommits { for idx, item := range commit.Precommits {
// may be nil if validator skipped. // may be nil if validator skipped.
if item == nil || len(item.Signature) == 0 { if item == nil || len(item.Signature) == 0 {
...@@ -338,8 +358,8 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height ...@@ -338,8 +358,8 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx) return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
} }
_, val := valSet.GetByIndex(idx) _, val := valSet.GetByIndex(idx)
// Validate signature
// Validate signature
precommitSignBytes := SignBytes(chainID, precommit) precommitSignBytes := SignBytes(chainID, precommit)
sig, err := ConsensusCrypto.SignatureFromBytes(precommit.Signature) sig, err := ConsensusCrypto.SignatureFromBytes(precommit.Signature)
if err != nil { if err != nil {
...@@ -358,6 +378,7 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height ...@@ -358,6 +378,7 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
// Good precommit! // Good precommit!
talliedVotingPower += val.VotingPower talliedVotingPower += val.VotingPower
} }
}
if talliedVotingPower > valSet.TotalVotingPower()*2/3 { if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
return nil return nil
......
...@@ -8,7 +8,9 @@ import ( ...@@ -8,7 +8,9 @@ import (
"bytes" "bytes"
"strings" "strings"
"sync" "sync"
"time"
"github.com/33cn/chain33/common/crypto"
tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types" tmtypes "github.com/33cn/plugin/plugin/dapp/valnode/types"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
...@@ -63,6 +65,7 @@ type VoteSet struct { ...@@ -63,6 +65,7 @@ type VoteSet struct {
maj23 *tmtypes.BlockID // First 2/3 majority seen maj23 *tmtypes.BlockID // First 2/3 majority seen
votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes
peerMaj23s map[string]*tmtypes.BlockID // Maj23 for each peer peerMaj23s map[string]*tmtypes.BlockID // Maj23 for each peer
aggVote *AggVote // aggregate vote
} }
// NewVoteSet Constructs a new VoteSet struct used to accumulate votes for given height/round. // NewVoteSet Constructs a new VoteSet struct used to accumulate votes for given height/round.
...@@ -82,6 +85,7 @@ func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet * ...@@ -82,6 +85,7 @@ func NewVoteSet(chainID string, height int64, round int, voteType byte, valSet *
maj23: nil, maj23: nil,
votesByBlock: make(map[string]*blockVotes, valSet.Size()), votesByBlock: make(map[string]*blockVotes, valSet.Size()),
peerMaj23s: make(map[string]*tmtypes.BlockID), peerMaj23s: make(map[string]*tmtypes.BlockID),
aggVote: nil,
} }
} }
...@@ -133,7 +137,7 @@ func (voteSet *VoteSet) Size() int { ...@@ -133,7 +137,7 @@ func (voteSet *VoteSet) Size() int {
// NOTE: Vote must not be nil // NOTE: Vote must not be nil
func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) { func (voteSet *VoteSet) AddVote(vote *Vote) (added bool, err error) {
if voteSet == nil { if voteSet == nil {
PanicSanity("AddVote() on nil VoteSet") return false, errors.New("nil vote set")
} }
voteSet.mtx.Lock() voteSet.mtx.Lock()
defer voteSet.mtx.Unlock() defer voteSet.mtx.Unlock()
...@@ -291,6 +295,146 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower ...@@ -291,6 +295,146 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower
return true, conflicting return true, conflicting
} }
// AddAggVote Returns added=true if aggVote is valid and new
func (voteSet *VoteSet) AddAggVote(vote *AggVote) (bool, error) {
if voteSet == nil {
return false, errors.New("nil vote set")
}
if vote == nil {
return false, ErrAggVoteNil
}
voteSet.mtx.Lock()
defer voteSet.mtx.Unlock()
valAddr := vote.ValidatorAddress
valset := voteSet.valSet
if len(valAddr) == 0 {
return false, errors.Wrap(ErrVoteInvalidValidatorAddress, "Empty address")
}
// Make sure the step matches
if (vote.Height != voteSet.height) ||
(int(vote.Round) != voteSet.round) ||
(vote.Type != uint32(voteSet.voteType)) {
return false, errors.Wrapf(ErrVoteUnexpectedStep, "Got %d/%d/%d, expected %d/%d/%d",
voteSet.height, voteSet.round, voteSet.voteType,
vote.Height, vote.Round, vote.Type)
}
// Ensure that signer is proposer
propAddr := valset.Proposer.Address
if !bytes.Equal(valAddr, propAddr) {
return false, errors.Wrapf(ErrVoteInvalidValidatorAddress,
"aggVote.ValidatorAddress (%X) does not match proposer address (%X)",
valAddr, propAddr)
}
// If we already know of this vote, return false
if voteSet.aggVote != nil {
if bytes.Equal(voteSet.aggVote.Signature, vote.Signature) {
return false, nil // duplicate
}
return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", voteSet.aggVote, vote)
}
// Check signature
err := vote.Verify(voteSet.chainID, voteSet.valSet)
if err != nil {
return false, err
}
// Check maj32
sum := int64(0)
arr := &BitArray{TendermintBitArray: vote.ValidatorArray}
for i, val := range valset.Validators {
if arr.GetIndex(i) {
sum += val.VotingPower
}
}
quorum := voteSet.valSet.TotalVotingPower()*2/3 + 1
if sum < quorum {
return false, errors.New("less than 2/3 total power")
}
voteSet.votesBitArray = arr.copy()
voteSet.aggVote = vote
voteSet.maj23 = vote.BlockID
voteSet.sum = sum
votesByBlock := newBlockVotes(false, voteSet.valSet.Size())
votesByBlock.bitArray = arr.copy()
votesByBlock.sum = sum
voteSet.votesByBlock[string(voteSet.maj23.Hash)] = votesByBlock
return true, nil
}
// SetAggVote generate aggregate vote when voteSet have 2/3 majority
func (voteSet *VoteSet) SetAggVote() error {
if voteSet == nil {
return errors.New("nil vote set")
}
if voteSet.maj23 == nil {
return errors.New("no 2/3 majority in voteSet")
}
voteSet.mtx.Lock()
defer voteSet.mtx.Unlock()
blockKey := string(voteSet.maj23.Hash)
votesByBlock, ok := voteSet.votesByBlock[blockKey]
if !ok {
return errors.New("no 2/3 majority blockKey")
}
bitArray := votesByBlock.bitArray.copy()
sigs := make([]crypto.Signature, 0)
for _, vote := range votesByBlock.votes {
if vote != nil {
sig, err := ConsensusCrypto.SignatureFromBytes(vote.Signature)
if err != nil {
return errors.New("invalid aggregate signature")
}
sigs = append(sigs, sig)
}
}
aggr, err := crypto.ToAggregate(ConsensusCrypto)
if err != nil {
return err
}
aggSig, err := aggr.Aggregate(sigs)
if err != nil {
return err
}
aggVote := &AggVote{&tmtypes.AggVote{
ValidatorAddress: voteSet.valSet.Proposer.Address,
ValidatorArray: bitArray.TendermintBitArray,
Height: voteSet.height,
Round: int32(voteSet.round),
Timestamp: time.Now().UnixNano(),
Type: uint32(voteSet.voteType),
BlockID: voteSet.maj23,
Signature: aggSig.Bytes(),
}}
// Verify aggVote
err = aggVote.Verify(voteSet.chainID, voteSet.valSet)
if err != nil {
return err
}
voteSet.aggVote = aggVote
return nil
}
// GetAggVote ...
func (voteSet *VoteSet) GetAggVote() *AggVote {
if voteSet == nil {
return nil
}
voteSet.mtx.Lock()
defer voteSet.mtx.Unlock()
if voteSet.aggVote == nil {
return nil
}
return voteSet.aggVote.Copy()
}
// SetPeerMaj23 If a peer claims that it has 2/3 majority for given blockKey, call this. // SetPeerMaj23 If a peer claims that it has 2/3 majority for given blockKey, call this.
// NOTE: if there are too many peers, or too much peer churn, // NOTE: if there are too many peers, or too much peer churn,
// this can cause memory issues. // this can cause memory issues.
...@@ -446,12 +590,12 @@ func (voteSet *VoteSet) StringIndented(indent string) string { ...@@ -446,12 +590,12 @@ func (voteSet *VoteSet) StringIndented(indent string) string {
} }
} }
return Fmt(`VoteSet{ return Fmt(`VoteSet{
%s H:%v R:%v T:%v %s H:%v R:%v T:%v +2/3:%X
%s %v %s %v
%s %v %s %v
%s %v %s %v
%s}`, %s}`,
indent, voteSet.height, voteSet.round, voteSet.voteType, indent, voteSet.height, voteSet.round, voteSet.voteType, voteSet.maj23,
indent, strings.Join(voteStrings, "\n"+indent+" "), indent, strings.Join(voteStrings, "\n"+indent+" "),
indent, voteSet.votesBitArray, indent, voteSet.votesBitArray,
indent, voteSet.peerMaj23s, indent, voteSet.peerMaj23s,
...@@ -491,10 +635,15 @@ func (voteSet *VoteSet) MakeCommit() *tmtypes.TendermintCommit { ...@@ -491,10 +635,15 @@ func (voteSet *VoteSet) MakeCommit() *tmtypes.TendermintCommit {
votesCopy[i] = &tmtypes.Vote{} votesCopy[i] = &tmtypes.Vote{}
} }
} }
//copy(votesCopy, voteSet.votes) var aggVote *tmtypes.AggVote
if voteSet.aggVote != nil {
copy := voteSet.aggVote.Copy()
aggVote = copy.AggVote
}
return &tmtypes.TendermintCommit{ return &tmtypes.TendermintCommit{
BlockID: voteSet.maj23, BlockID: voteSet.maj23,
Precommits: votesCopy, Precommits: votesCopy,
AggVote: aggVote,
} }
} }
...@@ -549,4 +698,5 @@ type VoteSetReader interface { ...@@ -549,4 +698,5 @@ type VoteSetReader interface {
BitArray() *BitArray BitArray() *BitArray
GetByIndex(int) *Vote GetByIndex(int) *Vote
IsCommit() bool IsCommit() bool
GetAggVote() *AggVote
} }
// 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 bls
import (
"bytes"
"crypto/rand"
"errors"
"fmt"
"github.com/33cn/chain33/common/crypto"
"github.com/phoreproject/bls/g1pubs"
)
const (
BLSPrivateKeyLength = 32
BLSPublicKeyLength = 48
BLSSignatureLength = 96
)
// Driver driver
type Driver struct{}
// GenKey create private key
func (d Driver) GenKey() (crypto.PrivKey, error) {
privKeyBytes := new([BLSPrivateKeyLength]byte)
priv, err := g1pubs.RandKey(rand.Reader)
if err != nil {
return nil, err
}
privBytes := priv.Serialize()
copy(privKeyBytes[:], privBytes[:])
return PrivKeyBLS(*privKeyBytes), nil
}
// PrivKeyFromBytes create private key from bytes
func (d Driver) PrivKeyFromBytes(b []byte) (privKey crypto.PrivKey, err error) {
if len(b) != BLSPrivateKeyLength {
return nil, errors.New("invalid bls priv key byte")
}
privKeyBytes := new([BLSPrivateKeyLength]byte)
copy(privKeyBytes[:], b[:BLSPrivateKeyLength])
priv := g1pubs.DeserializeSecretKey(*privKeyBytes)
if priv == nil {
return nil, errors.New("invalid bls privkey")
}
privBytes := priv.Serialize()
copy(privKeyBytes[:], privBytes[:])
return PrivKeyBLS(*privKeyBytes), nil
}
// PubKeyFromBytes create public key from bytes
func (d Driver) PubKeyFromBytes(b []byte) (pubKey crypto.PubKey, err error) {
if len(b) != BLSPublicKeyLength {
return nil, errors.New("invalid bls pub key byte")
}
pubKeyBytes := new([BLSPublicKeyLength]byte)
copy(pubKeyBytes[:], b[:])
return PubKeyBLS(*pubKeyBytes), nil
}
// SignatureFromBytes create signature from bytes
func (d Driver) SignatureFromBytes(b []byte) (sig crypto.Signature, err error) {
sigBytes := new([BLSSignatureLength]byte)
copy(sigBytes[:], b[:])
return SignatureBLS(*sigBytes), nil
}
//Aggregate aggregates signatures together into a new signature.
func (d Driver) Aggregate(sigs []crypto.Signature) (crypto.Signature, error) {
if len(sigs) == 0 {
return nil, errors.New("no signatures to aggregate")
}
g1sigs := make([]*g1pubs.Signature, 0, len(sigs))
for i, sig := range sigs {
g1sig, err := ConvertToSignature(sig)
if err != nil {
return nil, fmt.Errorf("%v(index: %d)", err, i)
}
g1sigs = append(g1sigs, g1sig)
}
agsig := g1pubs.AggregateSignatures(g1sigs)
return SignatureBLS(agsig.Serialize()), nil
}
//AggregatePublic aggregates public keys together into a new PublicKey.
func (d Driver) AggregatePublic(pubs []crypto.PubKey) (crypto.PubKey, error) {
if len(pubs) == 0 {
return nil, errors.New("no public keys to aggregate")
}
//blank public key
g1pubs := g1pubs.NewAggregatePubkey()
for i, pub := range pubs {
g1pub, err := ConvertToPublicKey(pub)
if err != nil {
return nil, fmt.Errorf("%v(index: %d)", err, i)
}
g1pubs.Aggregate(g1pub)
}
return PubKeyBLS(g1pubs.Serialize()), nil
}
// VerifyAggregatedOne verifies each public key against a message.
func (d Driver) VerifyAggregatedOne(pubs []crypto.PubKey, m []byte, sig crypto.Signature) error {
g1pubs := make([]*g1pubs.PublicKey, 0, len(pubs))
for i, pub := range pubs {
g1pub, err := ConvertToPublicKey(pub)
if err != nil {
return fmt.Errorf("%v(index: %d)", err, i)
}
g1pubs = append(g1pubs, g1pub)
}
g1sig, err := ConvertToSignature(sig)
if err != nil {
return err
}
if g1sig.VerifyAggregateCommon(g1pubs, m) {
return nil
}
return errors.New("bls signature mismatch")
}
// VerifyAggregatedN verifies each public key against each message.
func (d Driver) VerifyAggregatedN(pubs []crypto.PubKey, ms [][]byte, sig crypto.Signature) error {
g1pubs := make([]*g1pubs.PublicKey, 0, len(pubs))
for i, pub := range pubs {
g1pub, err := ConvertToPublicKey(pub)
if err != nil {
return fmt.Errorf("%v(index: %d)", err, i)
}
g1pubs = append(g1pubs, g1pub)
}
g1sig, err := ConvertToSignature(sig)
if err != nil {
return err
}
if len(g1pubs) != len(ms) {
return fmt.Errorf("different length of pubs and messages, %d vs %d", len(g1pubs), len(ms))
}
if g1sig.VerifyAggregate(g1pubs, ms) {
return nil
}
return errors.New("bls signature mismatch")
}
// ConvertToSignature convert to BLS Signature
func ConvertToSignature(sig crypto.Signature) (*g1pubs.Signature, error) {
// unwrap if needed
if wrap, ok := sig.(SignatureS); ok {
sig = wrap.Signature
}
sigBLS, ok := sig.(SignatureBLS)
if !ok {
return nil, errors.New("invalid bls signature")
}
g1sig, err := g1pubs.DeserializeSignature(sigBLS)
if err != nil {
return nil, err
}
return g1sig, nil
}
// ConvertToPublicKey convert to BLS PublicKey
func ConvertToPublicKey(pub crypto.PubKey) (*g1pubs.PublicKey, error) {
pubBLS, ok := pub.(PubKeyBLS)
if !ok {
return nil, errors.New("invalid bls public key")
}
g1pub, err := g1pubs.DeserializePublicKey(pubBLS)
if err != nil {
return nil, err
}
return g1pub, nil
}
// PrivKeyBLS PrivKey
type PrivKeyBLS [BLSPrivateKeyLength]byte
// Bytes convert to bytes
func (privKey PrivKeyBLS) Bytes() []byte {
s := make([]byte, BLSPrivateKeyLength)
copy(s, privKey[:])
return s
}
// Sign create signature
func (privKey PrivKeyBLS) Sign(msg []byte) crypto.Signature {
priv := g1pubs.DeserializeSecretKey(privKey)
sig := g1pubs.Sign(msg, priv)
return SignatureBLS(sig.Serialize())
}
// PubKey convert to public key
func (privKey PrivKeyBLS) PubKey() crypto.PubKey {
priv := g1pubs.DeserializeSecretKey(privKey)
return PubKeyBLS(g1pubs.PrivToPub(priv).Serialize())
}
// Equals check privkey is equal
func (privKey PrivKeyBLS) Equals(other crypto.PrivKey) bool {
if otherSecp, ok := other.(PrivKeyBLS); ok {
return bytes.Equal(privKey[:], otherSecp[:])
}
return false
}
// String convert to string
func (privKey PrivKeyBLS) String() string {
return fmt.Sprintf("PrivKeyBLS{*****}")
}
// PubKeyBLS PubKey
type PubKeyBLS [BLSPublicKeyLength]byte
// Bytes convert to bytes
func (pubKey PubKeyBLS) Bytes() []byte {
s := make([]byte, BLSPublicKeyLength)
copy(s, pubKey[:])
return s
}
// VerifyBytes verify signature
func (pubKey PubKeyBLS) VerifyBytes(msg []byte, sig crypto.Signature) bool {
pub, err := g1pubs.DeserializePublicKey(pubKey)
if err != nil {
fmt.Println("invalid bls pubkey")
return false
}
g1sig, err := ConvertToSignature(sig)
if err != nil {
fmt.Println("ConvertToSignature fail:", err)
return false
}
return g1pubs.Verify(msg, pub, g1sig)
}
// String convert to string
func (pubKey PubKeyBLS) String() string {
return fmt.Sprintf("PubKeyBLS{%X}", pubKey[:])
}
// KeyString Must return the full bytes in hex.
// Used for map keying, etc.
func (pubKey PubKeyBLS) KeyString() string {
return fmt.Sprintf("%X", pubKey[:])
}
// Equals check public key is equal
func (pubKey PubKeyBLS) Equals(other crypto.PubKey) bool {
if otherSecp, ok := other.(PubKeyBLS); ok {
return bytes.Equal(pubKey[:], otherSecp[:])
}
return false
}
// SignatureBLS Signature
type SignatureBLS [BLSSignatureLength]byte
// SignatureS signature struct
type SignatureS struct {
crypto.Signature
}
// Bytes convert signature to bytes
func (sig SignatureBLS) Bytes() []byte {
s := make([]byte, len(sig))
copy(s, sig[:])
return s
}
// IsZero check signature is zero
func (sig SignatureBLS) IsZero() bool { return len(sig) == 0 }
// String convert signature to string
func (sig SignatureBLS) String() string {
fingerprint := make([]byte, len(sig[:]))
copy(fingerprint, sig[:])
return fmt.Sprintf("/%X.../", fingerprint)
}
// Equals check signature equals
func (sig SignatureBLS) Equals(other crypto.Signature) bool {
if otherEd, ok := other.(SignatureBLS); ok {
return bytes.Equal(sig[:], otherEd[:])
}
return false
}
// Name name
const Name = "bls"
// ID id
const ID = 259
func init() {
crypto.Register(Name, &Driver{})
crypto.RegisterType(Name, ID)
}
// 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 bls
import (
"fmt"
"testing"
"github.com/33cn/chain33/common/crypto"
"github.com/stretchr/testify/assert"
)
var blsDrv = &Driver{}
func TestGenKey(t *testing.T) {
sk, err := blsDrv.GenKey()
assert.NoError(t, err)
assert.NotEmpty(t, sk)
pk := sk.PubKey()
assert.NotEmpty(t, pk)
sk2, _ := blsDrv.GenKey()
assert.NotEqual(t, sk.Bytes(), sk2.Bytes(), "should not generate two same key", sk, sk2)
}
func TestSignAndVerify(t *testing.T) {
sk, _ := blsDrv.GenKey()
pk := sk.PubKey()
m1 := []byte("message to be signed. 将要做签名的消息")
// sign and verify
sig1 := sk.Sign(m1)
ret := pk.VerifyBytes(m1, sig1)
assert.Equal(t, true, ret)
// different message should have different signature
m2 := []byte("message to be signed. 将要做签名的消息.")
sig2 := sk.Sign(m2)
assert.NotEqual(t, sig1, sig2, "different message got the same signature", sig1, sig2)
// different key should have different signature for a same message.
sk2, _ := blsDrv.GenKey()
sig12 := sk2.Sign(m1)
ret = pk.VerifyBytes(m1, sig12)
assert.Equal(t, false, ret)
}
func TestAggregate(t *testing.T) {
m := []byte("message to be signed. 将要做签名的消息")
n := 8
pubs := make([]crypto.PubKey, 0, n)
sigs := make([]crypto.Signature, 0, n) //signatures for the same message
msgs := make([][]byte, 0, n)
dsigs := make([]crypto.Signature, 0, n) //signatures for each (key,message) pair
for i := 0; i < n; i++ {
sk, _ := blsDrv.GenKey()
pk := sk.PubKey()
pubs = append(pubs, pk)
sigs = append(sigs, sk.Sign(m))
msgi := append(m, byte(i))
msgs = append(msgs, msgi)
dsigs = append(dsigs, sk.Sign(msgi))
}
asig, err := blsDrv.Aggregate(sigs)
assert.NoError(t, err)
// One
err = blsDrv.VerifyAggregatedOne(pubs, m, asig)
assert.NoError(t, err)
apub, err := blsDrv.AggregatePublic(pubs)
assert.NoError(t, err)
ret := apub.VerifyBytes(m, asig)
assert.Equal(t, true, ret)
// N
adsig, err := blsDrv.Aggregate(dsigs)
assert.NoError(t, err)
err = blsDrv.VerifyAggregatedN(pubs, msgs, adsig)
assert.NoError(t, err)
//lose some messages will cause an error
err = blsDrv.VerifyAggregatedN(pubs, msgs[1:], adsig)
assert.Error(t, err)
//with out-of-order public keys, will has no effect on VerifyAggregatedOne, but DO effects VerifyAggregatedN
pubs[0], pubs[1] = pubs[1], pubs[0]
err = blsDrv.VerifyAggregatedOne(pubs, m, asig)
assert.NoError(t, err)
err = blsDrv.VerifyAggregatedN(pubs, msgs, adsig)
assert.Error(t, err)
//invalid length
_, err = blsDrv.Aggregate(nil)
assert.Error(t, err)
_, err = blsDrv.AggregatePublic(make([]crypto.PubKey, 0))
assert.Error(t, err)
}
//benchmark
func BenchmarkBLSAggregateSignature(b *testing.B) {
msg := []byte(">16 character identical message")
n := 200
sigs := make([]crypto.Signature, 0, n) //signatures for the same message
for i := 0; i < n; i++ {
sk, _ := blsDrv.GenKey()
sigs = append(sigs, sk.Sign(msg))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
blsDrv.Aggregate(sigs) //nolint:errcheck
}
}
func BenchmarkBLSSign(b *testing.B) {
sks := make([]crypto.PrivKey, b.N)
msgs := make([][]byte, 0, b.N)
for i := range sks {
sks[i], _ = blsDrv.GenKey()
msgs = append(msgs, []byte(fmt.Sprintf("Hello world! 16 characters %d", i)))
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
sks[i].Sign(msgs[i])
}
}
func BenchmarkBLSVerify(b *testing.B) {
sk, _ := blsDrv.GenKey()
pk := sk.PubKey()
m := []byte(">16 character identical message")
sig := sk.Sign(m)
b.ResetTimer()
for i := 0; i < b.N; i++ {
pk.VerifyBytes(m, sig) //nolint:errcheck
}
}
func BenchmarkBlsManager_VerifyAggregatedOne(b *testing.B) {
m := []byte("message to be signed. 将要做签名的消息")
n := 100
pubs := make([]crypto.PubKey, 0, n)
sigs := make([]crypto.Signature, 0, n) //signatures for the same message
for i := 0; i < n; i++ {
sk, _ := blsDrv.GenKey()
pk := sk.PubKey()
pubs = append(pubs, pk)
sigs = append(sigs, sk.Sign(m))
}
asig, _ := blsDrv.Aggregate(sigs)
b.ResetTimer()
for i := 0; i < b.N; i++ {
blsDrv.VerifyAggregatedOne(pubs, m, asig) //nolint:errcheck
}
}
func BenchmarkBlsManager_VerifyAggregatedN(b *testing.B) {
m := []byte("message to be signed. 将要做签名的消息")
n := 100
pubs := make([]crypto.PubKey, 0, n)
sigs := make([]crypto.Signature, 0, n)
msgs := make([][]byte, 0, n)
for i := 0; i < n; i++ {
mi := append(m, byte(i))
sk, _ := blsDrv.GenKey()
pk := sk.PubKey()
pubs = append(pubs, pk)
sigs = append(sigs, sk.Sign(mi))
msgs = append(msgs, mi)
}
asig, _ := blsDrv.Aggregate(sigs)
b.ResetTimer()
for i := 0; i < b.N; i++ {
blsDrv.VerifyAggregatedN(pubs, msgs, asig) //nolint:errcheck
}
}
package init package init
import ( import (
_ "github.com/33cn/plugin/plugin/crypto/bls" //auto gen
_ "github.com/33cn/plugin/plugin/crypto/ecdsa" //auto gen _ "github.com/33cn/plugin/plugin/crypto/ecdsa" //auto gen
_ "github.com/33cn/plugin/plugin/crypto/sm2" //auto gen _ "github.com/33cn/plugin/plugin/crypto/sm2" //auto gen
) )
...@@ -25,6 +25,7 @@ var ( ...@@ -25,6 +25,7 @@ var (
strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters
genFile = "genesis_file.json" genFile = "genesis_file.json"
pvFile = "priv_validator_" pvFile = "priv_validator_"
AuthBLS = 259
) )
// ValCmd valnode cmd register // ValCmd valnode cmd register
...@@ -164,8 +165,9 @@ func CreateCmd() *cobra.Command { ...@@ -164,8 +165,9 @@ func CreateCmd() *cobra.Command {
} }
func addCreateCmdFlags(cmd *cobra.Command) { func addCreateCmdFlags(cmd *cobra.Command) {
cmd.Flags().StringP("num", "n", "", "Num of the keyfile to create") cmd.Flags().StringP("num", "n", "", "num of the keyfile to create")
cmd.MarkFlagRequired("num") cmd.MarkFlagRequired("num")
cmd.Flags().StringP("type", "t", "ed25519", "sign type of the keyfile (secp256k1, ed25519, sm2, bls)")
} }
// RandStr ... // RandStr ...
...@@ -192,10 +194,11 @@ MAIN_LOOP: ...@@ -192,10 +194,11 @@ MAIN_LOOP:
return string(chars) return string(chars)
} }
func initCryptoImpl() error { func initCryptoImpl(signType int) error {
cr, err := crypto.New(types.GetSignName("", types.ED25519)) ttypes.CryptoName = types.GetSignName("", signType)
cr, err := crypto.New(ttypes.CryptoName)
if err != nil { if err != nil {
fmt.Printf("New crypto impl failed err: %v", err) fmt.Printf("Init crypto fail: %v", err)
return err return err
} }
ttypes.ConsensusCrypto = cr ttypes.ConsensusCrypto = cr
...@@ -204,7 +207,13 @@ func initCryptoImpl() error { ...@@ -204,7 +207,13 @@ func initCryptoImpl() error {
func createFiles(cmd *cobra.Command, args []string) { func createFiles(cmd *cobra.Command, args []string) {
// init crypto instance // init crypto instance
err := initCryptoImpl() ty, _ := cmd.Flags().GetString("type")
signType, ok := ttypes.SignMap[ty]
if !ok {
fmt.Println("type parameter is not valid")
return
}
err := initCryptoImpl(signType)
if err != nil { if err != nil {
return return
} }
...@@ -232,7 +241,7 @@ func createFiles(cmd *cobra.Command, args []string) { ...@@ -232,7 +241,7 @@ func createFiles(cmd *cobra.Command, args []string) {
// create genesis validator by the pubkey of private validator // create genesis validator by the pubkey of private validator
gv := ttypes.GenesisValidator{ gv := ttypes.GenesisValidator{
PubKey: ttypes.KeyText{Kind: "ed25519", Data: privValidator.GetPubKey().KeyString()}, PubKey: ttypes.KeyText{Kind: ttypes.CryptoName, Data: privValidator.GetPubKey().KeyString()},
Power: 10, Power: 10,
} }
genDoc.Validators = append(genDoc.Validators, gv) genDoc.Validators = append(genDoc.Validators, gv)
......
...@@ -35,11 +35,22 @@ func (val *ValNode) Exec_BlockInfo(blockInfo *pty.TendermintBlockInfo, tx *types ...@@ -35,11 +35,22 @@ func (val *ValNode) Exec_BlockInfo(blockInfo *pty.TendermintBlockInfo, tx *types
return receipt, nil return receipt, nil
} }
func getConfigKey(key string, db dbm.KV) ([]byte, error) {
configKey := types.ConfigKey(key)
value, err := db.Get([]byte(configKey))
if err != nil {
clog.Error("getConfigKey not find", "configKey", configKey, "err", err)
return nil, err
}
return value, nil
}
func getManageKey(key string, db dbm.KV) ([]byte, error) { func getManageKey(key string, db dbm.KV) ([]byte, error) {
manageKey := types.ManageKey(key) manageKey := types.ManageKey(key)
value, err := db.Get([]byte(manageKey)) value, err := db.Get([]byte(manageKey))
if err != nil { if err != nil {
return nil, err clog.Info("getManageKey not find", "manageKey", manageKey, "err", err)
return getConfigKey(key, db)
} }
return value, nil return value, nil
} }
......
...@@ -5,86 +5,88 @@ import "blockchain.proto"; ...@@ -5,86 +5,88 @@ import "blockchain.proto";
package types; package types;
message BlockID { message BlockID {
bytes Hash = 1; bytes hash = 1;
} }
message TendermintBitArray { message TendermintBitArray {
int32 Bits = 1; int32 bits = 1;
repeated uint64 Elems = 2; repeated uint64 elems = 2;
} }
message Vote { message Vote {
bytes ValidatorAddress = 1; bytes validatorAddress = 1;
int32 ValidatorIndex = 2; int32 validatorIndex = 2;
int64 Height = 3; int64 height = 3;
int32 Round = 4; int32 round = 4;
int64 Timestamp = 5; int64 timestamp = 5;
uint32 Type = 6; uint32 type = 6;
BlockID BlockID = 7; BlockID blockID = 7;
bytes Signature = 8; bytes signature = 8;
bool useAggSig = 9;
} }
message TendermintCommit { message TendermintCommit {
BlockID BlockID = 1; BlockID blockID = 1;
repeated Vote Precommits = 2; repeated Vote precommits = 2;
AggVote aggVote = 3;
} }
message TendermintBlockInfo { message TendermintBlockInfo {
State State = 2; State state = 2;
Proposal Proposal = 3; Proposal proposal = 3;
TendermintBlock block = 4; TendermintBlock block = 4;
} }
message BlockSize { message BlockSize {
int32 MaxBytes = 1; int32 maxBytes = 1;
int32 MaxTxs = 2; int32 maxTxs = 2;
int64 MaxGas = 3; int64 maxGas = 3;
} }
message TxSize { message TxSize {
int32 MaxBytes = 1; int32 maxBytes = 1;
int64 MaxGas = 2; int64 maxGas = 2;
} }
message BlockGossip { message BlockGossip {
int32 BlockPartSizeBytes = 1; int32 blockPartSizeBytes = 1;
} }
message EvidenceParams { message EvidenceParams {
int64 MaxAge = 1; int64 maxAge = 1;
} }
message ConsensusParams { message ConsensusParams {
BlockSize BlockSize = 1; BlockSize blockSize = 1;
TxSize TxSize = 2; TxSize txSize = 2;
BlockGossip BlockGossip = 3; BlockGossip blockGossip = 3;
EvidenceParams EvidenceParams = 4; EvidenceParams evidenceParams = 4;
} }
message Validator { message Validator {
bytes Address = 1; bytes address = 1;
bytes PubKey = 2; bytes pubKey = 2;
int64 VotingPower = 3; int64 votingPower = 3;
int64 Accum = 4; int64 accum = 4;
} }
message ValidatorSet { message ValidatorSet {
repeated Validator Validators = 1; repeated Validator validators = 1;
Validator Proposer = 2; Validator proposer = 2;
} }
message State { message State {
string ChainID = 1; string chainID = 1;
int64 LastBlockHeight = 2; int64 lastBlockHeight = 2;
int64 LastBlockTotalTx = 3; int64 lastBlockTotalTx = 3;
BlockID LastBlockID = 4; BlockID lastBlockID = 4;
int64 LastBlockTime = 5; int64 lastBlockTime = 5;
ValidatorSet Validators = 6; ValidatorSet validators = 6;
ValidatorSet LastValidators = 7; ValidatorSet lastValidators = 7;
int64 LastHeightValidatorsChanged = 8; int64 lastHeightValidatorsChanged = 8;
ConsensusParams ConsensusParams = 9; ConsensusParams consensusParams = 9;
int64 LastHeightConsensusParamsChanged = 10; int64 lastHeightConsensusParamsChanged = 10;
bytes LastResultsHash = 11; bytes lastResultsHash = 11;
bytes AppHash = 12; bytes appHash = 12;
} }
message TendermintBlockHeader { message TendermintBlockHeader {
...@@ -174,3 +176,14 @@ message Heartbeat { ...@@ -174,3 +176,14 @@ message Heartbeat {
message IsHealthy { message IsHealthy {
bool isHealthy = 1; bool isHealthy = 1;
} }
message AggVote {
bytes validatorAddress = 1;
TendermintBitArray validatorArray = 2;
int64 height = 3;
int32 round = 4;
int64 timestamp = 5;
uint32 type = 6;
BlockID blockID = 7;
bytes signature = 8;
}
\ No newline at end of file
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