mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-23 08:11:57 +00:00
Compare commits
20 Commits
v0.18.0-rc
...
0.19.0-rc2
Author | SHA1 | Date | |
---|---|---|---|
|
7afe74a963 | ||
|
02531ca5a3 | ||
|
d24e4cb821 | ||
|
fb64314d1c | ||
|
32e1d195a0 | ||
|
3ca5292dc9 | ||
|
c541d58d2f | ||
|
3037b5b7ca | ||
|
e4492afbad | ||
|
799beebd36 | ||
|
45ec5fd170 | ||
|
5d1c758730 | ||
|
1b9323f105 | ||
|
196f8410ba | ||
|
89cdde7f1e | ||
|
35a1d747b0 | ||
|
34974e3932 | ||
|
901b456151 | ||
|
ced74251e9 | ||
|
6c345f9fa2 |
75
Gopkg.lock
generated
75
Gopkg.lock
generated
@@ -2,9 +2,10 @@
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
revision = "50de9da05b50eb15658bb350f6ea24368a111ab7"
|
||||
revision = "2be2f12b358dc57d70b8f501b00be450192efbc3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
@@ -19,10 +20,10 @@
|
||||
revision = "95f809107225be108efcf10a3509e4ea6ceef3c4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/fortytw2/leaktest"
|
||||
packages = ["."]
|
||||
revision = "3b724c3d7b8729a35bf4e577f71653aec6e53513"
|
||||
revision = "a5ef70473c97b71626b9abeda80ee92ba2a7de9e"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fsnotify/fsnotify"
|
||||
@@ -96,6 +97,7 @@
|
||||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
@@ -103,7 +105,7 @@
|
||||
"json/scanner",
|
||||
"json/token"
|
||||
]
|
||||
revision = "23c074d0eceb2b8a5bfdbb271ab780cde70f05a8"
|
||||
revision = "f40e974e75af4e271d97ce0fc917af5898ae7bda"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
@@ -126,12 +128,14 @@
|
||||
[[projects]]
|
||||
name = "github.com/magiconair/properties"
|
||||
packages = ["."]
|
||||
revision = "49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934"
|
||||
revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
|
||||
version = "v1.7.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
packages = ["."]
|
||||
revision = "b4575eea38cca1123ec2dc90c26529b5c5acfcff"
|
||||
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pelletier/go-toml"
|
||||
@@ -169,8 +173,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cast"
|
||||
packages = ["."]
|
||||
revision = "acbeb36b902d72a7a4c18e8f3241075e7ab763e4"
|
||||
version = "v1.1.0"
|
||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/spf13/cobra"
|
||||
@@ -193,8 +197,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/spf13/viper"
|
||||
packages = ["."]
|
||||
revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7"
|
||||
version = "v1.0.0"
|
||||
revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
|
||||
version = "v1.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/stretchr/testify"
|
||||
@@ -206,6 +210,7 @@
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
packages = [
|
||||
"leveldb",
|
||||
@@ -221,10 +226,9 @@
|
||||
"leveldb/table",
|
||||
"leveldb/util"
|
||||
]
|
||||
revision = "34011bf325bce385408353a30b101fe5e923eb6e"
|
||||
revision = "169b1b37be738edb2813dab48c97a549bcf99bb5"
|
||||
|
||||
[[projects]]
|
||||
branch = "develop"
|
||||
name = "github.com/tendermint/abci"
|
||||
packages = [
|
||||
"client",
|
||||
@@ -234,7 +238,8 @@
|
||||
"server",
|
||||
"types"
|
||||
]
|
||||
revision = "9e0e00bef42aebf6b402f66bf0f3dc607de8a6f3"
|
||||
revision = "c62aed95f2ce399ec815b0cafe478af002cdc4e6"
|
||||
version = "v0.10.3-dev"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -246,20 +251,22 @@
|
||||
]
|
||||
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
revision = "42246108ff925a457fb709475070a03dfd3e2b5c"
|
||||
version = "0.9.6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/go-crypto"
|
||||
packages = ["."]
|
||||
revision = "c3e19f3ea26f5c3357e0bcbb799b0761ef923755"
|
||||
version = "v0.5.0"
|
||||
revision = "5d5f580f49ca66c13400938c64334186068c8b7c"
|
||||
version = "v0.6.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/tendermint/go-wire"
|
||||
packages = [
|
||||
".",
|
||||
"data"
|
||||
]
|
||||
packages = ["."]
|
||||
revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c"
|
||||
source = "github.com/tendermint/go-amino"
|
||||
version = "v0.7.3"
|
||||
|
||||
[[projects]]
|
||||
@@ -278,10 +285,11 @@
|
||||
"pubsub/query",
|
||||
"test"
|
||||
]
|
||||
revision = "1b9b5652a199ab0be2e781393fb275b66377309d"
|
||||
version = "v0.7.0"
|
||||
revision = "2e24b64fc121dcdf1cabceab8dc2f7257675483c"
|
||||
version = "0.8.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"curve25519",
|
||||
@@ -293,7 +301,7 @@
|
||||
"ripemd160",
|
||||
"salsa20/salsa"
|
||||
]
|
||||
revision = "1875d0a70c90e57f11972aefd42276df65e895b9"
|
||||
revision = "88942b9c40a4c9d203b82b3731787b672d6e809b"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -307,12 +315,13 @@
|
||||
"lex/httplex",
|
||||
"trace"
|
||||
]
|
||||
revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
|
||||
revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
revision = "91ee8cde435411ca3f1cd365e8f20131aed4d0a1"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
@@ -332,12 +341,14 @@
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
]
|
||||
revision = "e19ae1496984b1c655b8044a65c0300a3c878dd3"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
revision = "4eb30f4778eed4c258ba66527a0d4f9ec8a36c45"
|
||||
revision = "ab0870e398d5dd054b868c0db1481ab029b9a9f2"
|
||||
|
||||
[[projects]]
|
||||
name = "google.golang.org/grpc"
|
||||
@@ -360,18 +371,18 @@
|
||||
"tap",
|
||||
"transport"
|
||||
]
|
||||
revision = "401e0e00e4bb830a10496d64cd95e068c5bf50de"
|
||||
version = "v1.7.3"
|
||||
revision = "5b3c4e850e90a4cf6a20ebd46c8b32a0a3afcb9e"
|
||||
version = "v1.7.5"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
||||
version = "v2.0.0"
|
||||
revision = "7f97868eec74b32b0982dd158a51a446d1da7eb5"
|
||||
version = "v2.1.1"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "ed9db0be72a900f4812675f683db20eff9d64ef4511dc00ad29a810da65909c2"
|
||||
inputs-digest = "ed1149ed5293b7b28b7505627648c6a1152aaff0ed06a3849995b29751ae00f3"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
17
Gopkg.toml
17
Gopkg.toml
@@ -26,12 +26,12 @@
|
||||
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/ebuchman/fail-test"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/fortytw2/leaktest"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/go-kit/kit"
|
||||
@@ -54,8 +54,8 @@
|
||||
version = "0.8.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/rcrowley/go-metrics"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/spf13/cobra"
|
||||
@@ -71,20 +71,19 @@
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/abci"
|
||||
branch = "develop"
|
||||
version = "0.10.3-dev"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/go-crypto"
|
||||
version = "0.5.0"
|
||||
version = "0.6.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/go-wire"
|
||||
source = "github.com/tendermint/go-amino"
|
||||
version = "0.7.3"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
version = "0.9.6"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/tendermint/tmlibs"
|
||||
version = "0.7.0"
|
||||
version = "0.8.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "google.golang.org/grpc"
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire"
|
||||
|
||||
proto "github.com/tendermint/tendermint/benchmarks/proto"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
|
||||
func BenchmarkEncodeStatusWire(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
status := &ctypes.ResultStatus{
|
||||
NodeInfo: p2p.NodeInfo{
|
||||
@@ -33,7 +35,10 @@ func BenchmarkEncodeStatusWire(b *testing.B) {
|
||||
|
||||
counter := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
jsonBytes := wire.JSONBytes(status)
|
||||
jsonBytes, err := cdc.MarshalJSON(status)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
counter += len(jsonBytes)
|
||||
}
|
||||
|
||||
@@ -41,6 +46,8 @@ func BenchmarkEncodeStatusWire(b *testing.B) {
|
||||
|
||||
func BenchmarkEncodeNodeInfoWire(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
PubKey: pubKey,
|
||||
@@ -54,13 +61,18 @@ func BenchmarkEncodeNodeInfoWire(b *testing.B) {
|
||||
|
||||
counter := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
jsonBytes := wire.JSONBytes(nodeInfo)
|
||||
jsonBytes, err := cdc.MarshalJSON(nodeInfo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
counter += len(jsonBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
|
||||
b.StopTimer()
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
nodeInfo := p2p.NodeInfo{
|
||||
PubKey: pubKey,
|
||||
@@ -74,7 +86,7 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
|
||||
|
||||
counter := 0
|
||||
for i := 0; i < b.N; i++ {
|
||||
jsonBytes := wire.BinaryBytes(nodeInfo)
|
||||
jsonBytes := cdc.MustMarshalBinaryBare(nodeInfo)
|
||||
counter += len(jsonBytes)
|
||||
}
|
||||
|
||||
@@ -82,7 +94,7 @@ func BenchmarkEncodeNodeInfoBinary(b *testing.B) {
|
||||
|
||||
func BenchmarkEncodeNodeInfoProto(b *testing.B) {
|
||||
b.StopTimer()
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey().Unwrap().(crypto.PubKeyEd25519)
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey().(crypto.PubKeyEd25519)
|
||||
pubKey2 := &proto.PubKey{Ed25519: &proto.PubKeyEd25519{Bytes: pubKey[:]}}
|
||||
nodeInfo := proto.NodeInfo{
|
||||
PubKey: pubKey2,
|
||||
|
@@ -1,21 +1,16 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -31,6 +26,13 @@ const (
|
||||
statusUpdateIntervalSeconds = 10
|
||||
// check if we should switch to consensus reactor
|
||||
switchToConsensusIntervalSeconds = 1
|
||||
|
||||
// NOTE: keep up to date with bcBlockResponseMessage
|
||||
bcBlockResponseMessagePrefixSize = 4
|
||||
bcBlockResponseMessageFieldKeySize = 1
|
||||
maxMessageSize = types.MaxBlockSizeBytes +
|
||||
bcBlockResponseMessagePrefixSize +
|
||||
bcBlockResponseMessageFieldKeySize
|
||||
)
|
||||
|
||||
type consensusReactor interface {
|
||||
@@ -52,9 +54,6 @@ func (e peerError) Error() string {
|
||||
type BlockchainReactor struct {
|
||||
p2p.BaseReactor
|
||||
|
||||
mtx sync.Mutex
|
||||
params types.ConsensusParams
|
||||
|
||||
// immutable
|
||||
initialState sm.State
|
||||
|
||||
@@ -87,7 +86,6 @@ func NewBlockchainReactor(state sm.State, blockExec *sm.BlockExecutor, store *Bl
|
||||
)
|
||||
|
||||
bcR := &BlockchainReactor{
|
||||
params: state.ConsensusParams,
|
||||
initialState: state,
|
||||
blockExec: blockExec,
|
||||
store: store,
|
||||
@@ -131,17 +129,19 @@ func (bcR *BlockchainReactor) OnStop() {
|
||||
func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
return []*p2p.ChannelDescriptor{
|
||||
{
|
||||
ID: BlockchainChannel,
|
||||
Priority: 10,
|
||||
SendQueueCapacity: 1000,
|
||||
ID: BlockchainChannel,
|
||||
Priority: 10,
|
||||
SendQueueCapacity: 1000,
|
||||
RecvBufferCapacity: 50 * 4096,
|
||||
RecvMessageCapacity: maxMessageSize,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddPeer implements Reactor by sending our state to peer.
|
||||
func (bcR *BlockchainReactor) AddPeer(peer p2p.Peer) {
|
||||
if !peer.Send(BlockchainChannel,
|
||||
struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}}) {
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusResponseMessage{bcR.store.Height()})
|
||||
if !peer.Send(BlockchainChannel, msgBytes) {
|
||||
// doing nothing, will try later in `poolRoutine`
|
||||
}
|
||||
// peer is added to the pool once we receive the first
|
||||
@@ -162,20 +162,19 @@ func (bcR *BlockchainReactor) respondToPeer(msg *bcBlockRequestMessage,
|
||||
|
||||
block := bcR.store.LoadBlock(msg.Height)
|
||||
if block != nil {
|
||||
msg := &bcBlockResponseMessage{Block: block}
|
||||
return src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockResponseMessage{Block: block})
|
||||
return src.TrySend(BlockchainChannel, msgBytes)
|
||||
}
|
||||
|
||||
bcR.Logger.Info("Peer asking for a block we don't have", "src", src, "height", msg.Height)
|
||||
|
||||
return src.TrySend(BlockchainChannel, struct{ BlockchainMessage }{
|
||||
&bcNoBlockResponseMessage{Height: msg.Height},
|
||||
})
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcNoBlockResponseMessage{Height: msg.Height})
|
||||
return src.TrySend(BlockchainChannel, msgBytes)
|
||||
}
|
||||
|
||||
// Receive implements Reactor by handling 4 types of messages (look below).
|
||||
func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
_, msg, err := DecodeMessage(msgBytes, bcR.maxMsgSize())
|
||||
msg, err := DecodeMessage(msgBytes)
|
||||
if err != nil {
|
||||
bcR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
|
||||
bcR.Switch.StopPeerForError(src, err)
|
||||
@@ -194,8 +193,8 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
bcR.pool.AddBlock(src.ID(), msg.Block, len(msgBytes))
|
||||
case *bcStatusRequestMessage:
|
||||
// Send peer our state.
|
||||
queued := src.TrySend(BlockchainChannel,
|
||||
struct{ BlockchainMessage }{&bcStatusResponseMessage{bcR.store.Height()}})
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusResponseMessage{bcR.store.Height()})
|
||||
queued := src.TrySend(BlockchainChannel, msgBytes)
|
||||
if !queued {
|
||||
// sorry
|
||||
}
|
||||
@@ -207,21 +206,6 @@ func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
}
|
||||
}
|
||||
|
||||
// maxMsgSize returns the maximum allowable size of a
|
||||
// message on the blockchain reactor.
|
||||
func (bcR *BlockchainReactor) maxMsgSize() int {
|
||||
bcR.mtx.Lock()
|
||||
defer bcR.mtx.Unlock()
|
||||
return bcR.params.BlockSize.MaxBytes + 2
|
||||
}
|
||||
|
||||
// updateConsensusParams updates the internal consensus params
|
||||
func (bcR *BlockchainReactor) updateConsensusParams(params types.ConsensusParams) {
|
||||
bcR.mtx.Lock()
|
||||
defer bcR.mtx.Unlock()
|
||||
bcR.params = params
|
||||
}
|
||||
|
||||
// Handle messages from the poolReactor telling the reactor what to do.
|
||||
// NOTE: Don't sleep in the FOR_LOOP or otherwise slow it down!
|
||||
// (Except for the SYNC_LOOP, which is the primary purpose and must be synchronous.)
|
||||
@@ -247,8 +231,8 @@ FOR_LOOP:
|
||||
if peer == nil {
|
||||
continue FOR_LOOP // Peer has since been disconnected.
|
||||
}
|
||||
msg := &bcBlockRequestMessage{request.Height}
|
||||
queued := peer.TrySend(BlockchainChannel, struct{ BlockchainMessage }{msg})
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcBlockRequestMessage{request.Height})
|
||||
queued := peer.TrySend(BlockchainChannel, msgBytes)
|
||||
if !queued {
|
||||
// We couldn't make the request, send-queue full.
|
||||
// The pool handles timeouts, just let it go.
|
||||
@@ -321,9 +305,6 @@ FOR_LOOP:
|
||||
}
|
||||
blocksSynced++
|
||||
|
||||
// update the consensus params
|
||||
bcR.updateConsensusParams(state.ConsensusParams)
|
||||
|
||||
if blocksSynced%100 == 0 {
|
||||
lastRate = 0.9*lastRate + 0.1*(100/time.Since(lastHundred).Seconds())
|
||||
bcR.Logger.Info("Fast Sync Rate", "height", bcR.pool.height,
|
||||
@@ -341,43 +322,32 @@ FOR_LOOP:
|
||||
|
||||
// BroadcastStatusRequest broadcasts `BlockStore` height.
|
||||
func (bcR *BlockchainReactor) BroadcastStatusRequest() error {
|
||||
bcR.Switch.Broadcast(BlockchainChannel,
|
||||
struct{ BlockchainMessage }{&bcStatusRequestMessage{bcR.store.Height()}})
|
||||
msgBytes := cdc.MustMarshalBinaryBare(&bcStatusRequestMessage{bcR.store.Height()})
|
||||
bcR.Switch.Broadcast(BlockchainChannel, msgBytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeBlockRequest = byte(0x10)
|
||||
msgTypeBlockResponse = byte(0x11)
|
||||
msgTypeNoBlockResponse = byte(0x12)
|
||||
msgTypeStatusResponse = byte(0x20)
|
||||
msgTypeStatusRequest = byte(0x21)
|
||||
)
|
||||
|
||||
// BlockchainMessage is a generic message for this reactor.
|
||||
type BlockchainMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ BlockchainMessage }{},
|
||||
wire.ConcreteType{&bcBlockRequestMessage{}, msgTypeBlockRequest},
|
||||
wire.ConcreteType{&bcBlockResponseMessage{}, msgTypeBlockResponse},
|
||||
wire.ConcreteType{&bcNoBlockResponseMessage{}, msgTypeNoBlockResponse},
|
||||
wire.ConcreteType{&bcStatusResponseMessage{}, msgTypeStatusResponse},
|
||||
wire.ConcreteType{&bcStatusRequestMessage{}, msgTypeStatusRequest},
|
||||
)
|
||||
func RegisterBlockchainMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*BlockchainMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&bcBlockRequestMessage{}, "tendermint/mempool/BlockRequest", nil)
|
||||
cdc.RegisterConcrete(&bcBlockResponseMessage{}, "tendermint/mempool/BlockResponse", nil)
|
||||
cdc.RegisterConcrete(&bcNoBlockResponseMessage{}, "tendermint/mempool/NoBlockResponse", nil)
|
||||
cdc.RegisterConcrete(&bcStatusResponseMessage{}, "tendermint/mempool/StatusResponse", nil)
|
||||
cdc.RegisterConcrete(&bcStatusRequestMessage{}, "tendermint/mempool/StatusRequest", nil)
|
||||
}
|
||||
|
||||
// DecodeMessage decodes BlockchainMessage.
|
||||
// TODO: ensure that bz is completely read.
|
||||
func DecodeMessage(bz []byte, maxSize int) (msgType byte, msg BlockchainMessage, err error) {
|
||||
msgType = bz[0]
|
||||
n := int(0)
|
||||
r := bytes.NewReader(bz)
|
||||
msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, maxSize, &n, &err).(struct{ BlockchainMessage }).BlockchainMessage
|
||||
if err != nil && n != len(bz) {
|
||||
err = errors.New("DecodeMessage() had bytes left over")
|
||||
func DecodeMessage(bz []byte) (msg BlockchainMessage, err error) {
|
||||
err = cdc.UnmarshalBinaryBare(bz, &msg)
|
||||
if err != nil {
|
||||
err = cmn.ErrorWrap(err, "DecodeMessage() had bytes left over")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -402,7 +372,6 @@ func (brm *bcNoBlockResponseMessage) String() string {
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
// NOTE: keep up-to-date with maxBlockchainResponseSize
|
||||
type bcBlockResponseMessage struct {
|
||||
Block *types.Block
|
||||
}
|
||||
|
@@ -3,8 +3,6 @@ package blockchain
|
||||
import (
|
||||
"testing"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -18,8 +16,15 @@ import (
|
||||
|
||||
func makeStateAndBlockStore(logger log.Logger) (sm.State, *BlockStore) {
|
||||
config := cfg.ResetTestRoot("blockchain_reactor_test")
|
||||
blockStore := NewBlockStore(dbm.NewMemDB())
|
||||
state, _ := sm.LoadStateFromDBOrGenesisFile(dbm.NewMemDB(), config.GenesisFile())
|
||||
// blockDB := dbm.NewDebugDB("blockDB", dbm.NewMemDB())
|
||||
// stateDB := dbm.NewDebugDB("stateDB", dbm.NewMemDB())
|
||||
blockDB := dbm.NewMemDB()
|
||||
stateDB := dbm.NewMemDB()
|
||||
blockStore := NewBlockStore(blockDB)
|
||||
state, err := sm.LoadStateFromDBOrGenesisFile(stateDB, config.GenesisFile())
|
||||
if err != nil {
|
||||
panic(cmn.ErrorWrap(err, "error constructing state from genesis file"))
|
||||
}
|
||||
return state, blockStore
|
||||
}
|
||||
|
||||
@@ -76,10 +81,9 @@ func TestNoBlockResponse(t *testing.T) {
|
||||
// wait for our response to be received on the peer
|
||||
for _, tt := range tests {
|
||||
reqBlockMsg := &bcBlockRequestMessage{tt.height}
|
||||
reqBlockBytes := wire.BinaryBytes(struct{ BlockchainMessage }{reqBlockMsg})
|
||||
reqBlockBytes := cdc.MustMarshalBinaryBare(reqBlockMsg)
|
||||
bcr.Receive(chID, peer, reqBlockBytes)
|
||||
value := peer.lastValue()
|
||||
msg := value.(struct{ BlockchainMessage }).BlockchainMessage
|
||||
msg := peer.lastBlockchainMessage()
|
||||
|
||||
if tt.existent {
|
||||
if blockMsg, ok := msg.(*bcBlockResponseMessage); !ok {
|
||||
@@ -173,26 +177,30 @@ func newbcrTestPeer(id p2p.ID) *bcrTestPeer {
|
||||
return bcr
|
||||
}
|
||||
|
||||
func (tp *bcrTestPeer) lastValue() interface{} { return <-tp.ch }
|
||||
func (tp *bcrTestPeer) lastBlockchainMessage() interface{} { return <-tp.ch }
|
||||
|
||||
func (tp *bcrTestPeer) TrySend(chID byte, value interface{}) bool {
|
||||
if _, ok := value.(struct{ BlockchainMessage }).
|
||||
BlockchainMessage.(*bcStatusResponseMessage); ok {
|
||||
func (tp *bcrTestPeer) TrySend(chID byte, msgBytes []byte) bool {
|
||||
var msg BlockchainMessage
|
||||
err := cdc.UnmarshalBinaryBare(msgBytes, &msg)
|
||||
if err != nil {
|
||||
panic(cmn.ErrorWrap(err, "Error while trying to parse a BlockchainMessage"))
|
||||
}
|
||||
if _, ok := msg.(*bcStatusResponseMessage); ok {
|
||||
// Discard status response messages since they skew our results
|
||||
// We only want to deal with:
|
||||
// + bcBlockResponseMessage
|
||||
// + bcNoBlockResponseMessage
|
||||
} else {
|
||||
tp.ch <- value
|
||||
tp.ch <- msg
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (tp *bcrTestPeer) Send(chID byte, data interface{}) bool { return tp.TrySend(chID, data) }
|
||||
func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.NodeInfo{} }
|
||||
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
|
||||
func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
|
||||
func (tp *bcrTestPeer) IsOutbound() bool { return false }
|
||||
func (tp *bcrTestPeer) IsPersistent() bool { return true }
|
||||
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
|
||||
func (tp *bcrTestPeer) Set(string, interface{}) {}
|
||||
func (tp *bcrTestPeer) Send(chID byte, msgBytes []byte) bool { return tp.TrySend(chID, msgBytes) }
|
||||
func (tp *bcrTestPeer) NodeInfo() p2p.NodeInfo { return p2p.NodeInfo{} }
|
||||
func (tp *bcrTestPeer) Status() p2p.ConnectionStatus { return p2p.ConnectionStatus{} }
|
||||
func (tp *bcrTestPeer) ID() p2p.ID { return tp.id }
|
||||
func (tp *bcrTestPeer) IsOutbound() bool { return false }
|
||||
func (tp *bcrTestPeer) IsPersistent() bool { return true }
|
||||
func (tp *bcrTestPeer) Get(s string) interface{} { return s }
|
||||
func (tp *bcrTestPeer) Set(string, interface{}) {}
|
||||
|
@@ -1,14 +1,10 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
@@ -54,38 +50,25 @@ func (bs *BlockStore) Height() int64 {
|
||||
return bs.height
|
||||
}
|
||||
|
||||
// GetReader returns the value associated with the given key wrapped in an io.Reader.
|
||||
// If no value is found, it returns nil.
|
||||
// It's mainly for use with wire.ReadBinary.
|
||||
func (bs *BlockStore) GetReader(key []byte) io.Reader {
|
||||
bytez := bs.db.Get(key)
|
||||
if bytez == nil {
|
||||
return nil
|
||||
}
|
||||
return bytes.NewReader(bytez)
|
||||
}
|
||||
|
||||
// LoadBlock returns the block with the given height.
|
||||
// If no block is found for that height, it returns nil.
|
||||
func (bs *BlockStore) LoadBlock(height int64) *types.Block {
|
||||
var n int
|
||||
var err error
|
||||
r := bs.GetReader(calcBlockMetaKey(height))
|
||||
if r == nil {
|
||||
var blockMeta = bs.LoadBlockMeta(height)
|
||||
if blockMeta == nil {
|
||||
return nil
|
||||
}
|
||||
blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading block meta: %v", err))
|
||||
}
|
||||
bytez := []byte{}
|
||||
|
||||
var block = new(types.Block)
|
||||
buf := []byte{}
|
||||
for i := 0; i < blockMeta.BlockID.PartsHeader.Total; i++ {
|
||||
part := bs.LoadBlockPart(height, i)
|
||||
bytez = append(bytez, part.Bytes...)
|
||||
buf = append(buf, part.Bytes...)
|
||||
}
|
||||
block := wire.ReadBinary(&types.Block{}, bytes.NewReader(bytez), 0, &n, &err).(*types.Block)
|
||||
err := cdc.UnmarshalBinary(buf, block)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading block: %v", err))
|
||||
// NOTE: The existence of meta should imply the existence of the
|
||||
// block. So, make sure meta is only saved after blocks are saved.
|
||||
panic(cmn.ErrorWrap(err, "Error reading block"))
|
||||
}
|
||||
return block
|
||||
}
|
||||
@@ -94,15 +77,14 @@ func (bs *BlockStore) LoadBlock(height int64) *types.Block {
|
||||
// from the block at the given height.
|
||||
// If no part is found for the given height and index, it returns nil.
|
||||
func (bs *BlockStore) LoadBlockPart(height int64, index int) *types.Part {
|
||||
var n int
|
||||
var err error
|
||||
r := bs.GetReader(calcBlockPartKey(height, index))
|
||||
if r == nil {
|
||||
var part = new(types.Part)
|
||||
bz := bs.db.Get(calcBlockPartKey(height, index))
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
part := wire.ReadBinary(&types.Part{}, r, 0, &n, &err).(*types.Part)
|
||||
err := cdc.UnmarshalBinaryBare(bz, part)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading block part: %v", err))
|
||||
panic(cmn.ErrorWrap(err, "Error reading block part"))
|
||||
}
|
||||
return part
|
||||
}
|
||||
@@ -110,15 +92,14 @@ func (bs *BlockStore) LoadBlockPart(height int64, index int) *types.Part {
|
||||
// LoadBlockMeta returns the BlockMeta for the given height.
|
||||
// If no block is found for the given height, it returns nil.
|
||||
func (bs *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
var n int
|
||||
var err error
|
||||
r := bs.GetReader(calcBlockMetaKey(height))
|
||||
if r == nil {
|
||||
var blockMeta = new(types.BlockMeta)
|
||||
bz := bs.db.Get(calcBlockMetaKey(height))
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
blockMeta := wire.ReadBinary(&types.BlockMeta{}, r, 0, &n, &err).(*types.BlockMeta)
|
||||
err := cdc.UnmarshalBinaryBare(bz, blockMeta)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading block meta: %v", err))
|
||||
panic(cmn.ErrorWrap(err, "Error reading block meta"))
|
||||
}
|
||||
return blockMeta
|
||||
}
|
||||
@@ -128,15 +109,14 @@ func (bs *BlockStore) LoadBlockMeta(height int64) *types.BlockMeta {
|
||||
// and it comes from the block.LastCommit for `height+1`.
|
||||
// If no commit is found for the given height, it returns nil.
|
||||
func (bs *BlockStore) LoadBlockCommit(height int64) *types.Commit {
|
||||
var n int
|
||||
var err error
|
||||
r := bs.GetReader(calcBlockCommitKey(height))
|
||||
if r == nil {
|
||||
var commit = new(types.Commit)
|
||||
bz := bs.db.Get(calcBlockCommitKey(height))
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
commit := wire.ReadBinary(&types.Commit{}, r, 0, &n, &err).(*types.Commit)
|
||||
err := cdc.UnmarshalBinaryBare(bz, commit)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading commit: %v", err))
|
||||
panic(cmn.ErrorWrap(err, "Error reading block commit"))
|
||||
}
|
||||
return commit
|
||||
}
|
||||
@@ -145,15 +125,14 @@ func (bs *BlockStore) LoadBlockCommit(height int64) *types.Commit {
|
||||
// This is useful when we've seen a commit, but there has not yet been
|
||||
// a new block at `height + 1` that includes this commit in its block.LastCommit.
|
||||
func (bs *BlockStore) LoadSeenCommit(height int64) *types.Commit {
|
||||
var n int
|
||||
var err error
|
||||
r := bs.GetReader(calcSeenCommitKey(height))
|
||||
if r == nil {
|
||||
var commit = new(types.Commit)
|
||||
bz := bs.db.Get(calcSeenCommitKey(height))
|
||||
if len(bz) == 0 {
|
||||
return nil
|
||||
}
|
||||
commit := wire.ReadBinary(&types.Commit{}, r, 0, &n, &err).(*types.Commit)
|
||||
err := cdc.UnmarshalBinaryBare(bz, commit)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error reading commit: %v", err))
|
||||
panic(cmn.ErrorWrap(err, "Error reading block seen commit"))
|
||||
}
|
||||
return commit
|
||||
}
|
||||
@@ -178,21 +157,22 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||
|
||||
// Save block meta
|
||||
blockMeta := types.NewBlockMeta(block, blockParts)
|
||||
metaBytes := wire.BinaryBytes(blockMeta)
|
||||
metaBytes := cdc.MustMarshalBinaryBare(blockMeta)
|
||||
bs.db.Set(calcBlockMetaKey(height), metaBytes)
|
||||
|
||||
// Save block parts
|
||||
for i := 0; i < blockParts.Total(); i++ {
|
||||
bs.saveBlockPart(height, i, blockParts.GetPart(i))
|
||||
part := blockParts.GetPart(i)
|
||||
bs.saveBlockPart(height, i, part)
|
||||
}
|
||||
|
||||
// Save block commit (duplicate and separate from the Block)
|
||||
blockCommitBytes := wire.BinaryBytes(block.LastCommit)
|
||||
blockCommitBytes := cdc.MustMarshalBinaryBare(block.LastCommit)
|
||||
bs.db.Set(calcBlockCommitKey(height-1), blockCommitBytes)
|
||||
|
||||
// Save seen commit (seen +2/3 precommits for block)
|
||||
// NOTE: we can delete this at a later height
|
||||
seenCommitBytes := wire.BinaryBytes(seenCommit)
|
||||
seenCommitBytes := cdc.MustMarshalBinaryBare(seenCommit)
|
||||
bs.db.Set(calcSeenCommitKey(height), seenCommitBytes)
|
||||
|
||||
// Save new BlockStoreStateJSON descriptor
|
||||
@@ -211,7 +191,7 @@ func (bs *BlockStore) saveBlockPart(height int64, index int, part *types.Part) {
|
||||
if height != bs.Height()+1 {
|
||||
cmn.PanicSanity(cmn.Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.Height()+1, height))
|
||||
}
|
||||
partBytes := wire.BinaryBytes(part)
|
||||
partBytes := cdc.MustMarshalBinaryBare(part)
|
||||
bs.db.Set(calcBlockPartKey(height, index), partBytes)
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package blockchain
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -11,9 +10,6 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -61,38 +57,6 @@ func TestNewBlockStore(t *testing.T) {
|
||||
assert.Equal(t, bs.Height(), int64(0), "expecting nil bytes to be unmarshaled alright")
|
||||
}
|
||||
|
||||
func TestBlockStoreGetReader(t *testing.T) {
|
||||
db := db.NewMemDB()
|
||||
// Initial setup
|
||||
db.Set([]byte("Foo"), []byte("Bar"))
|
||||
db.Set([]byte("Foo1"), nil)
|
||||
|
||||
bs := NewBlockStore(db)
|
||||
|
||||
tests := [...]struct {
|
||||
key []byte
|
||||
want []byte
|
||||
}{
|
||||
0: {key: []byte("Foo"), want: []byte("Bar")},
|
||||
1: {key: []byte("KnoxNonExistent"), want: nil},
|
||||
2: {key: []byte("Foo1"), want: []byte{}},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
r := bs.GetReader(tt.key)
|
||||
if r == nil {
|
||||
assert.Nil(t, tt.want, "#%d: expected a non-nil reader", i)
|
||||
continue
|
||||
}
|
||||
slurp, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: unexpected Read err: %v", i, err)
|
||||
} else {
|
||||
assert.Equal(t, slurp, tt.want, "#%d: mismatch", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func freshBlockStore() (*BlockStore, db.DB) {
|
||||
db := db.NewMemDB()
|
||||
return NewBlockStore(db), db
|
||||
@@ -189,14 +153,14 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
corruptCommitInDB: true, // Corrupt the DB's commit entry
|
||||
wantPanic: "rror reading commit",
|
||||
wantPanic: "Error reading block commit",
|
||||
},
|
||||
|
||||
{
|
||||
block: newBlock(&header1, commitAtH10),
|
||||
parts: validPartSet,
|
||||
seenCommit: seenCommit1,
|
||||
wantPanic: "rror reading block",
|
||||
wantPanic: "Error reading block",
|
||||
corruptBlockInDB: true, // Corrupt the DB's block entry
|
||||
},
|
||||
|
||||
@@ -215,7 +179,7 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
seenCommit: seenCommit1,
|
||||
|
||||
corruptSeenCommitInDB: true,
|
||||
wantPanic: "rror reading commit",
|
||||
wantPanic: "Error reading block seen commit",
|
||||
},
|
||||
|
||||
{
|
||||
@@ -305,14 +269,6 @@ func TestBlockStoreSaveLoadBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func binarySerializeIt(v interface{}) []byte {
|
||||
var n int
|
||||
var err error
|
||||
buf := new(bytes.Buffer)
|
||||
wire.WriteBinary(v, buf, &n, &err)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func TestLoadBlockPart(t *testing.T) {
|
||||
bs, db := freshBlockStore()
|
||||
height, index := int64(10), 1
|
||||
@@ -334,7 +290,7 @@ func TestLoadBlockPart(t *testing.T) {
|
||||
require.Contains(t, panicErr.Error(), "Error reading block part")
|
||||
|
||||
// 3. A good block serialized and saved to the DB should be retrievable
|
||||
db.Set(calcBlockPartKey(height, index), binarySerializeIt(part1))
|
||||
db.Set(calcBlockPartKey(height, index), cdc.MustMarshalBinaryBare(part1))
|
||||
gotPart, _, panicErr := doFn(loadPart)
|
||||
require.Nil(t, panicErr, "an existent and proper block should not panic")
|
||||
require.Nil(t, res, "a properly saved block should return a proper block")
|
||||
@@ -364,11 +320,11 @@ func TestLoadBlockMeta(t *testing.T) {
|
||||
|
||||
// 3. A good blockMeta serialized and saved to the DB should be retrievable
|
||||
meta := &types.BlockMeta{}
|
||||
db.Set(calcBlockMetaKey(height), binarySerializeIt(meta))
|
||||
db.Set(calcBlockMetaKey(height), cdc.MustMarshalBinaryBare(meta))
|
||||
gotMeta, _, panicErr := doFn(loadMeta)
|
||||
require.Nil(t, panicErr, "an existent and proper block should not panic")
|
||||
require.Nil(t, res, "a properly saved blockMeta should return a proper blocMeta ")
|
||||
require.Equal(t, binarySerializeIt(meta), binarySerializeIt(gotMeta),
|
||||
require.Equal(t, cdc.MustMarshalBinaryBare(meta), cdc.MustMarshalBinaryBare(gotMeta),
|
||||
"expecting successful retrieval of previously saved blockMeta")
|
||||
}
|
||||
|
||||
@@ -385,6 +341,9 @@ func TestBlockFetchAtHeight(t *testing.T) {
|
||||
require.Equal(t, bs.Height(), block.Header.Height, "expecting the new height to be changed")
|
||||
|
||||
blockAtHeight := bs.LoadBlock(bs.Height())
|
||||
bz1 := cdc.MustMarshalBinaryBare(block)
|
||||
bz2 := cdc.MustMarshalBinaryBare(blockAtHeight)
|
||||
require.Equal(t, bz1, bz2)
|
||||
require.Equal(t, block.Hash(), blockAtHeight.Hash(),
|
||||
"expecting a successful load of the last saved block")
|
||||
|
||||
|
13
blockchain/wire.go
Normal file
13
blockchain/wire.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
RegisterBlockchainMessages(cdc)
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -30,7 +30,7 @@ func main() {
|
||||
"privPath", *privValPath,
|
||||
)
|
||||
|
||||
privVal := priv_val.LoadPrivValidatorJSON(*privValPath)
|
||||
privVal := priv_val.LoadFilePV(*privValPath)
|
||||
|
||||
rs := priv_val.NewRemoteSigner(
|
||||
logger,
|
||||
|
@@ -1,12 +1,11 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
)
|
||||
|
||||
// GenValidatorCmd allows the generation of a keypair for a
|
||||
@@ -18,11 +17,11 @@ var GenValidatorCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func genValidator(cmd *cobra.Command, args []string) {
|
||||
privValidator := types.GenPrivValidatorFS("")
|
||||
privValidatorJSONBytes, err := json.MarshalIndent(privValidator, "", "\t")
|
||||
pv := pvm.GenFilePV("")
|
||||
jsbz, err := cdc.MarshalJSON(pv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf(`%v
|
||||
`, string(privValidatorJSONBytes))
|
||||
`, string(jsbz))
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -17,13 +18,13 @@ var InitFilesCmd = &cobra.Command{
|
||||
func initFiles(cmd *cobra.Command, args []string) {
|
||||
// private validator
|
||||
privValFile := config.PrivValidatorFile()
|
||||
var privValidator *types.PrivValidatorFS
|
||||
var pv *pvm.FilePV
|
||||
if cmn.FileExists(privValFile) {
|
||||
privValidator = types.LoadPrivValidatorFS(privValFile)
|
||||
pv = pvm.LoadFilePV(privValFile)
|
||||
logger.Info("Found private validator", "path", privValFile)
|
||||
} else {
|
||||
privValidator = types.GenPrivValidatorFS(privValFile)
|
||||
privValidator.Save()
|
||||
pv = pvm.GenFilePV(privValFile)
|
||||
pv.Save()
|
||||
logger.Info("Generated private validator", "path", privValFile)
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ func initFiles(cmd *cobra.Command, args []string) {
|
||||
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
|
||||
}
|
||||
genDoc.Validators = []types.GenesisValidator{{
|
||||
PubKey: privValidator.GetPubKey(),
|
||||
PubKey: pv.GetPubKey(),
|
||||
Power: 10,
|
||||
}}
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
@@ -27,7 +27,7 @@ var ResetPrivValidatorCmd = &cobra.Command{
|
||||
// ResetAll removes the privValidator files.
|
||||
// Exported so other CLI tools can use it.
|
||||
func ResetAll(dbDir, privValFile string, logger log.Logger) {
|
||||
resetPrivValidatorFS(privValFile, logger)
|
||||
resetFilePV(privValFile, logger)
|
||||
if err := os.RemoveAll(dbDir); err != nil {
|
||||
logger.Error("Error removing directory", "err", err)
|
||||
return
|
||||
@@ -44,18 +44,18 @@ func resetAll(cmd *cobra.Command, args []string) {
|
||||
// XXX: this is totally unsafe.
|
||||
// it's only suitable for testnets.
|
||||
func resetPrivValidator(cmd *cobra.Command, args []string) {
|
||||
resetPrivValidatorFS(config.PrivValidatorFile(), logger)
|
||||
resetFilePV(config.PrivValidatorFile(), logger)
|
||||
}
|
||||
|
||||
func resetPrivValidatorFS(privValFile string, logger log.Logger) {
|
||||
func resetFilePV(privValFile string, logger log.Logger) {
|
||||
// Get PrivValidator
|
||||
if _, err := os.Stat(privValFile); err == nil {
|
||||
privValidator := types.LoadPrivValidatorFS(privValFile)
|
||||
privValidator.Reset()
|
||||
pv := pvm.LoadFilePV(privValFile)
|
||||
pv.Reset()
|
||||
logger.Info("Reset PrivValidator", "file", privValFile)
|
||||
} else {
|
||||
privValidator := types.GenPrivValidatorFS(privValFile)
|
||||
privValidator.Save()
|
||||
pv := pvm.GenFilePV(privValFile)
|
||||
pv.Save()
|
||||
logger.Info("Generated PrivValidator", "file", privValFile)
|
||||
}
|
||||
}
|
||||
|
@@ -2,11 +2,9 @@ package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
privval "github.com/tendermint/tendermint/types/priv_validator"
|
||||
)
|
||||
|
||||
// ShowValidatorCmd adds capabilities for showing the validator info.
|
||||
@@ -17,7 +15,7 @@ var ShowValidatorCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func showValidator(cmd *cobra.Command, args []string) {
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile())
|
||||
pubKeyJSONBytes, _ := data.ToJSON(privValidator.PubKey)
|
||||
privValidator := privval.LoadOrGenFilePV(config.PrivValidatorFile())
|
||||
pubKeyJSONBytes, _ := cdc.MarshalJSON(privValidator.GetPubKey())
|
||||
fmt.Println(string(pubKeyJSONBytes))
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -46,10 +47,10 @@ func testnetFiles(cmd *cobra.Command, args []string) {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
// Read priv_validator.json to populate vals
|
||||
privValFile := filepath.Join(dataDir, mach, defaultConfig.PrivValidator)
|
||||
privVal := types.LoadPrivValidatorFS(privValFile)
|
||||
pvFile := filepath.Join(dataDir, mach, defaultConfig.PrivValidator)
|
||||
pv := pvm.LoadFilePV(pvFile)
|
||||
genVals[i] = types.GenesisValidator{
|
||||
PubKey: privVal.GetPubKey(),
|
||||
PubKey: pv.GetPubKey(),
|
||||
Power: 1,
|
||||
Name: mach,
|
||||
}
|
||||
@@ -78,13 +79,13 @@ func initMachCoreDirectory(base, mach string) error {
|
||||
// Create priv_validator.json file if not present
|
||||
defaultConfig := cfg.DefaultBaseConfig()
|
||||
dir := filepath.Join(base, mach)
|
||||
privValPath := filepath.Join(dir, defaultConfig.PrivValidator)
|
||||
dir = filepath.Dir(privValPath)
|
||||
pvPath := filepath.Join(dir, defaultConfig.PrivValidator)
|
||||
dir = filepath.Dir(pvPath)
|
||||
err := cmn.EnsureDir(dir, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ensurePrivValidator(privValPath)
|
||||
ensurePrivValidator(pvPath)
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -93,6 +94,6 @@ func ensurePrivValidator(file string) {
|
||||
if cmn.FileExists(file) {
|
||||
return
|
||||
}
|
||||
privValidator := types.GenPrivValidatorFS(file)
|
||||
privValidator.Save()
|
||||
pv := pvm.GenFilePV(file)
|
||||
pv.Save()
|
||||
}
|
||||
|
12
cmd/tendermint/commands/wire.go
Normal file
12
cmd/tendermint/commands/wire.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -270,7 +270,7 @@ type P2PConfig struct {
|
||||
FlushThrottleTimeout int `mapstructure:"flush_throttle_timeout"`
|
||||
|
||||
// Maximum size of a message packet payload, in bytes
|
||||
MaxMsgPacketPayloadSize int `mapstructure:"max_msg_packet_payload_size"`
|
||||
MaxPacketMsgPayloadSize int `mapstructure:"max_packet_msg_payload_size"`
|
||||
|
||||
// Rate at which packets can be sent, in bytes/second
|
||||
SendRate int64 `mapstructure:"send_rate"`
|
||||
@@ -299,7 +299,7 @@ func DefaultP2PConfig() *P2PConfig {
|
||||
AddrBookStrict: true,
|
||||
MaxNumPeers: 50,
|
||||
FlushThrottleTimeout: 100,
|
||||
MaxMsgPacketPayloadSize: 1024, // 1 kB
|
||||
MaxPacketMsgPayloadSize: 1024, // 1 kB
|
||||
SendRate: 512000, // 500 kB/s
|
||||
RecvRate: 512000, // 500 kB/s
|
||||
PexReactor: true,
|
||||
|
@@ -142,7 +142,7 @@ flush_throttle_timeout = {{ .P2P.FlushThrottleTimeout }}
|
||||
max_num_peers = {{ .P2P.MaxNumPeers }}
|
||||
|
||||
# Maximum size of a message packet payload, in bytes
|
||||
max_msg_packet_payload_size = {{ .P2P.MaxMsgPacketPayloadSize }}
|
||||
max_packet_msg_payload_size = {{ .P2P.MaxPacketMsgPayloadSize }}
|
||||
|
||||
# Rate at which packets can be sent, in bytes/second
|
||||
send_rate = {{ .P2P.SendRate }}
|
||||
@@ -276,8 +276,8 @@ var testGenesis = `{
|
||||
"validators": [
|
||||
{
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data":"3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
|
||||
"type": "AC26791624DE60",
|
||||
"value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
|
||||
},
|
||||
"power": 10,
|
||||
"name": ""
|
||||
@@ -287,14 +287,14 @@ var testGenesis = `{
|
||||
}`
|
||||
|
||||
var testPrivValidator = `{
|
||||
"address": "D028C9981F7A87F3093672BF0D5B0E2A1B3ED456",
|
||||
"address": "849CB2C877F87A20925F35D00AE6688342D25B47",
|
||||
"pub_key": {
|
||||
"type": "ed25519",
|
||||
"data": "3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
|
||||
"type": "AC26791624DE60",
|
||||
"value": "AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="
|
||||
},
|
||||
"priv_key": {
|
||||
"type": "ed25519",
|
||||
"data": "27F82582AEFAE7AB151CFB01C48BB6C1A0DA78F9BDDA979A9F70A84D074EB07D3B3069C422E19688B45CBFAE7BB009FC0FA1B1EA86593519318B7214853803C8"
|
||||
"type": "954568A3288910",
|
||||
"value": "EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="
|
||||
},
|
||||
"last_height": 0,
|
||||
"last_round": 0,
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
@@ -48,7 +47,9 @@ func TestByzantine(t *testing.T) {
|
||||
for i := 0; i < N; i++ {
|
||||
// make first val byzantine
|
||||
if i == 0 {
|
||||
css[i].privValidator = NewByzantinePrivValidator(css[i].privValidator)
|
||||
// NOTE: Now, test validators are MockPV, which by default doesn't
|
||||
// do any safety checks.
|
||||
css[i].privValidator.(*types.MockPV).DisableChecks()
|
||||
css[i].decideProposal = func(j int) func(int64, int) {
|
||||
return func(height int64, round int) {
|
||||
byzantineDecideProposalFunc(t, height, round, css[j], switches[j])
|
||||
@@ -203,7 +204,7 @@ func byzantineDecideProposalFunc(t *testing.T, height int64, round int, cs *Cons
|
||||
func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.Peer, proposal *types.Proposal, blockHash []byte, parts *types.PartSet) {
|
||||
// proposal
|
||||
msg := &ProposalMessage{Proposal: proposal}
|
||||
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
|
||||
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
|
||||
// parts
|
||||
for i := 0; i < parts.Total(); i++ {
|
||||
@@ -213,7 +214,7 @@ func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.
|
||||
Round: round, // This tells peer that this part applies to us.
|
||||
Part: part,
|
||||
}
|
||||
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
|
||||
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
}
|
||||
|
||||
// votes
|
||||
@@ -222,8 +223,8 @@ func sendProposalAndParts(height int64, round int, cs *ConsensusState, peer p2p.
|
||||
precommit, _ := cs.signVote(types.VoteTypePrecommit, blockHash, parts.Header())
|
||||
cs.mtx.Unlock()
|
||||
|
||||
peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{prevote}})
|
||||
peer.Send(VoteChannel, struct{ ConsensusMessage }{&VoteMessage{precommit}})
|
||||
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{prevote}))
|
||||
peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(&VoteMessage{precommit}))
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
@@ -264,47 +265,3 @@ func (br *ByzantineReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
func (br *ByzantineReactor) Receive(chID byte, peer p2p.Peer, msgBytes []byte) {
|
||||
br.reactor.Receive(chID, peer, msgBytes)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// byzantine privValidator
|
||||
|
||||
type ByzantinePrivValidator struct {
|
||||
types.Signer
|
||||
|
||||
pv types.PrivValidator
|
||||
}
|
||||
|
||||
// Return a priv validator that will sign anything
|
||||
func NewByzantinePrivValidator(pv types.PrivValidator) *ByzantinePrivValidator {
|
||||
return &ByzantinePrivValidator{
|
||||
Signer: pv.(*types.PrivValidatorFS).Signer,
|
||||
pv: pv,
|
||||
}
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) GetAddress() types.Address {
|
||||
return privVal.pv.GetAddress()
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) GetPubKey() crypto.PubKey {
|
||||
return privVal.pv.GetPubKey()
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) (err error) {
|
||||
vote.Signature, err = privVal.Sign(vote.SignBytes(chainID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignProposal(chainID string, proposal *types.Proposal) (err error) {
|
||||
proposal.Signature, _ = privVal.Sign(proposal.SignBytes(chainID))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat *types.Heartbeat) (err error) {
|
||||
heartbeat.Signature, _ = privVal.Sign(heartbeat.SignBytes(chainID))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (privVal *ByzantinePrivValidator) String() string {
|
||||
return cmn.Fmt("PrivValidator{%X}", privVal.GetAddress())
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -222,7 +223,7 @@ func subscribeToVoter(cs *ConsensusState, addr []byte) chan interface{} {
|
||||
voteCh := make(chan interface{})
|
||||
go func() {
|
||||
for v := range voteCh0 {
|
||||
vote := v.(types.TMEventData).Unwrap().(types.EventDataVote)
|
||||
vote := v.(types.EventDataVote)
|
||||
// we only fire for our own votes
|
||||
if bytes.Equal(addr, vote.Vote.ValidatorAddress) {
|
||||
voteCh <- v
|
||||
@@ -277,10 +278,10 @@ func newConsensusStateWithConfigAndBlockStore(thisConfig *cfg.Config, state sm.S
|
||||
return cs
|
||||
}
|
||||
|
||||
func loadPrivValidator(config *cfg.Config) *types.PrivValidatorFS {
|
||||
func loadPrivValidator(config *cfg.Config) *pvm.FilePV {
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
ensureDir(path.Dir(privValidatorFile), 0700)
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
privValidator := pvm.LoadOrGenFilePV(privValidatorFile)
|
||||
privValidator.Reset()
|
||||
return privValidator
|
||||
}
|
||||
@@ -378,7 +379,7 @@ func randConsensusNetWithPeers(nValidators, nPeers int, testName string, tickerF
|
||||
privVal = privVals[i]
|
||||
} else {
|
||||
_, tempFilePath := cmn.Tempfile("priv_validator_")
|
||||
privVal = types.GenPrivValidatorFS(tempFilePath)
|
||||
privVal = pvm.GenFilePV(tempFilePath)
|
||||
}
|
||||
|
||||
app := appFunc()
|
||||
@@ -405,9 +406,9 @@ func getSwitchIndex(switches []*p2p.Switch, peer p2p.Peer) int {
|
||||
//-------------------------------------------------------------------------------
|
||||
// genesis
|
||||
|
||||
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []*types.PrivValidatorFS) {
|
||||
func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.GenesisDoc, []types.PrivValidator) {
|
||||
validators := make([]types.GenesisValidator, numValidators)
|
||||
privValidators := make([]*types.PrivValidatorFS, numValidators)
|
||||
privValidators := make([]types.PrivValidator, numValidators)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
val, privVal := types.RandValidator(randPower, minPower)
|
||||
validators[i] = types.GenesisValidator{
|
||||
@@ -425,7 +426,7 @@ func randGenesisDoc(numValidators int, randPower bool, minPower int64) (*types.G
|
||||
}, privValidators
|
||||
}
|
||||
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []*types.PrivValidatorFS) {
|
||||
func randGenesisState(numValidators int, randPower bool, minPower int64) (sm.State, []types.PrivValidator) {
|
||||
genDoc, privValidators := randGenesisDoc(numValidators, randPower, minPower)
|
||||
s0, _ := sm.MakeGenesisState(genDoc)
|
||||
db := dbm.NewMemDB()
|
||||
|
@@ -108,7 +108,7 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) {
|
||||
ticker := time.NewTicker(time.Second * 30)
|
||||
select {
|
||||
case b := <-newBlockCh:
|
||||
evt := b.(types.TMEventData).Unwrap().(types.EventDataNewBlock)
|
||||
evt := b.(types.EventDataNewBlock)
|
||||
nTxs += int(evt.Block.Header.NumTxs)
|
||||
case <-ticker.C:
|
||||
panic("Timed out waiting to commit blocks with transactions")
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -108,27 +107,31 @@ func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor {
|
||||
// TODO optimize
|
||||
return []*p2p.ChannelDescriptor{
|
||||
{
|
||||
ID: StateChannel,
|
||||
Priority: 5,
|
||||
SendQueueCapacity: 100,
|
||||
ID: StateChannel,
|
||||
Priority: 5,
|
||||
SendQueueCapacity: 100,
|
||||
RecvMessageCapacity: maxConsensusMessageSize,
|
||||
},
|
||||
{
|
||||
ID: DataChannel, // maybe split between gossiping current block and catchup stuff
|
||||
Priority: 10, // once we gossip the whole block there's nothing left to send until next height or round
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 50 * 4096,
|
||||
ID: DataChannel, // maybe split between gossiping current block and catchup stuff
|
||||
Priority: 10, // once we gossip the whole block there's nothing left to send until next height or round
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 50 * 4096,
|
||||
RecvMessageCapacity: maxConsensusMessageSize,
|
||||
},
|
||||
{
|
||||
ID: VoteChannel,
|
||||
Priority: 5,
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 100 * 100,
|
||||
ID: VoteChannel,
|
||||
Priority: 5,
|
||||
SendQueueCapacity: 100,
|
||||
RecvBufferCapacity: 100 * 100,
|
||||
RecvMessageCapacity: maxConsensusMessageSize,
|
||||
},
|
||||
{
|
||||
ID: VoteSetBitsChannel,
|
||||
Priority: 1,
|
||||
SendQueueCapacity: 2,
|
||||
RecvBufferCapacity: 1024,
|
||||
ID: VoteSetBitsChannel,
|
||||
Priority: 1,
|
||||
SendQueueCapacity: 2,
|
||||
RecvBufferCapacity: 1024,
|
||||
RecvMessageCapacity: maxConsensusMessageSize,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -176,7 +179,7 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
return
|
||||
}
|
||||
|
||||
_, msg, err := DecodeMessage(msgBytes)
|
||||
msg, err := DecodeMessage(msgBytes)
|
||||
if err != nil {
|
||||
conR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
|
||||
conR.Switch.StopPeerForError(src, err)
|
||||
@@ -222,13 +225,13 @@ func (conR *ConsensusReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte)
|
||||
conR.Logger.Error("Bad VoteSetBitsMessage field Type")
|
||||
return
|
||||
}
|
||||
src.TrySend(VoteSetBitsChannel, struct{ ConsensusMessage }{&VoteSetBitsMessage{
|
||||
src.TrySend(VoteSetBitsChannel, cdc.MustMarshalBinaryBare(&VoteSetBitsMessage{
|
||||
Height: msg.Height,
|
||||
Round: msg.Round,
|
||||
Type: msg.Type,
|
||||
BlockID: msg.BlockID,
|
||||
Votes: ourVotes,
|
||||
}})
|
||||
}))
|
||||
case *ProposalHeartbeatMessage:
|
||||
hb := msg.Heartbeat
|
||||
conR.Logger.Debug("Received proposal heartbeat message",
|
||||
@@ -373,17 +376,17 @@ func (conR *ConsensusReactor) startBroadcastRoutine() error {
|
||||
select {
|
||||
case data, ok := <-stepsCh:
|
||||
if ok { // a receive from a closed channel returns the zero value immediately
|
||||
edrs := data.(types.TMEventData).Unwrap().(types.EventDataRoundState)
|
||||
edrs := data.(types.EventDataRoundState)
|
||||
conR.broadcastNewRoundStep(edrs.RoundState.(*cstypes.RoundState))
|
||||
}
|
||||
case data, ok := <-votesCh:
|
||||
if ok {
|
||||
edv := data.(types.TMEventData).Unwrap().(types.EventDataVote)
|
||||
edv := data.(types.EventDataVote)
|
||||
conR.broadcastHasVoteMessage(edv.Vote)
|
||||
}
|
||||
case data, ok := <-heartbeatsCh:
|
||||
if ok {
|
||||
edph := data.(types.TMEventData).Unwrap().(types.EventDataProposalHeartbeat)
|
||||
edph := data.(types.EventDataProposalHeartbeat)
|
||||
conR.broadcastProposalHeartbeatMessage(edph)
|
||||
}
|
||||
case <-conR.Quit():
|
||||
@@ -401,16 +404,16 @@ func (conR *ConsensusReactor) broadcastProposalHeartbeatMessage(heartbeat types.
|
||||
conR.Logger.Debug("Broadcasting proposal heartbeat message",
|
||||
"height", hb.Height, "round", hb.Round, "sequence", hb.Sequence)
|
||||
msg := &ProposalHeartbeatMessage{hb}
|
||||
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
}
|
||||
|
||||
func (conR *ConsensusReactor) broadcastNewRoundStep(rs *cstypes.RoundState) {
|
||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||
if nrsMsg != nil {
|
||||
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{nrsMsg})
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
if csMsg != nil {
|
||||
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{csMsg})
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,7 +425,7 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote) {
|
||||
Type: vote.Type,
|
||||
Index: vote.ValidatorIndex,
|
||||
}
|
||||
conR.Switch.Broadcast(StateChannel, struct{ ConsensusMessage }{msg})
|
||||
conR.Switch.Broadcast(StateChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
/*
|
||||
// TODO: Make this broadcast more selective.
|
||||
for _, peer := range conR.Switch.Peers().List() {
|
||||
@@ -462,10 +465,10 @@ func (conR *ConsensusReactor) sendNewRoundStepMessages(peer p2p.Peer) {
|
||||
rs := conR.conS.GetRoundState()
|
||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||
if nrsMsg != nil {
|
||||
peer.Send(StateChannel, struct{ ConsensusMessage }{nrsMsg})
|
||||
peer.Send(StateChannel, cdc.MustMarshalBinaryBare(nrsMsg))
|
||||
}
|
||||
if csMsg != nil {
|
||||
peer.Send(StateChannel, struct{ ConsensusMessage }{csMsg})
|
||||
peer.Send(StateChannel, cdc.MustMarshalBinaryBare(csMsg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +495,7 @@ OUTER_LOOP:
|
||||
Part: part,
|
||||
}
|
||||
logger.Debug("Sending block part", "height", prs.Height, "round", prs.Round)
|
||||
if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
|
||||
if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
|
||||
ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
@@ -536,7 +539,7 @@ OUTER_LOOP:
|
||||
{
|
||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||
logger.Debug("Sending proposal", "height", prs.Height, "round", prs.Round)
|
||||
if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
|
||||
if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
|
||||
ps.SetHasProposal(rs.Proposal)
|
||||
}
|
||||
}
|
||||
@@ -551,7 +554,7 @@ OUTER_LOOP:
|
||||
ProposalPOL: rs.Votes.Prevotes(rs.Proposal.POLRound).BitArray(),
|
||||
}
|
||||
logger.Debug("Sending POL", "height", prs.Height, "round", prs.Round)
|
||||
peer.Send(DataChannel, struct{ ConsensusMessage }{msg})
|
||||
peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
}
|
||||
continue OUTER_LOOP
|
||||
}
|
||||
@@ -594,7 +597,7 @@ func (conR *ConsensusReactor) gossipDataForCatchup(logger log.Logger, rs *cstype
|
||||
Part: part,
|
||||
}
|
||||
logger.Debug("Sending block part for catchup", "round", prs.Round, "index", index)
|
||||
if peer.Send(DataChannel, struct{ ConsensusMessage }{msg}) {
|
||||
if peer.Send(DataChannel, cdc.MustMarshalBinaryBare(msg)) {
|
||||
ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
|
||||
} else {
|
||||
logger.Debug("Sending block part for catchup failed")
|
||||
@@ -733,12 +736,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height {
|
||||
if maj23, ok := rs.Votes.Prevotes(prs.Round).TwoThirdsMajority(); ok {
|
||||
peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: types.VoteTypePrevote,
|
||||
BlockID: maj23,
|
||||
}})
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
|
||||
}
|
||||
}
|
||||
@@ -750,12 +753,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height {
|
||||
if maj23, ok := rs.Votes.Precommits(prs.Round).TwoThirdsMajority(); ok {
|
||||
peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.Round,
|
||||
Type: types.VoteTypePrecommit,
|
||||
BlockID: maj23,
|
||||
}})
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
|
||||
}
|
||||
}
|
||||
@@ -767,12 +770,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if rs.Height == prs.Height && prs.ProposalPOLRound >= 0 {
|
||||
if maj23, ok := rs.Votes.Prevotes(prs.ProposalPOLRound).TwoThirdsMajority(); ok {
|
||||
peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: prs.ProposalPOLRound,
|
||||
Type: types.VoteTypePrevote,
|
||||
BlockID: maj23,
|
||||
}})
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
|
||||
}
|
||||
}
|
||||
@@ -786,12 +789,12 @@ OUTER_LOOP:
|
||||
prs := ps.GetRoundState()
|
||||
if prs.CatchupCommitRound != -1 && 0 < prs.Height && prs.Height <= conR.conS.blockStore.Height() {
|
||||
commit := conR.conS.LoadCommit(prs.Height)
|
||||
peer.TrySend(StateChannel, struct{ ConsensusMessage }{&VoteSetMaj23Message{
|
||||
peer.TrySend(StateChannel, cdc.MustMarshalBinaryBare(&VoteSetMaj23Message{
|
||||
Height: prs.Height,
|
||||
Round: commit.Round(),
|
||||
Type: types.VoteTypePrecommit,
|
||||
BlockID: commit.BlockID,
|
||||
}})
|
||||
}))
|
||||
time.Sleep(conR.conS.config.PeerQueryMaj23Sleep())
|
||||
}
|
||||
}
|
||||
@@ -938,7 +941,7 @@ func (ps *PeerState) PickSendVote(votes types.VoteSetReader) bool {
|
||||
if vote, ok := ps.PickVoteToSend(votes); ok {
|
||||
msg := &VoteMessage{vote}
|
||||
ps.logger.Debug("Sending vote message", "ps", ps, "vote", vote)
|
||||
return ps.Peer.Send(VoteChannel, struct{ ConsensusMessage }{msg})
|
||||
return ps.Peer.Send(VoteChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1261,45 +1264,26 @@ func (ps *PeerState) StringIndented(indent string) string {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeNewRoundStep = byte(0x01)
|
||||
msgTypeCommitStep = byte(0x02)
|
||||
msgTypeProposal = byte(0x11)
|
||||
msgTypeProposalPOL = byte(0x12)
|
||||
msgTypeBlockPart = byte(0x13) // both block & POL
|
||||
msgTypeVote = byte(0x14)
|
||||
msgTypeHasVote = byte(0x15)
|
||||
msgTypeVoteSetMaj23 = byte(0x16)
|
||||
msgTypeVoteSetBits = byte(0x17)
|
||||
|
||||
msgTypeProposalHeartbeat = byte(0x20)
|
||||
)
|
||||
|
||||
// ConsensusMessage is a message that can be sent and received on the ConsensusReactor
|
||||
type ConsensusMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ ConsensusMessage }{},
|
||||
wire.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
|
||||
wire.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
|
||||
wire.ConcreteType{&ProposalMessage{}, msgTypeProposal},
|
||||
wire.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL},
|
||||
wire.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart},
|
||||
wire.ConcreteType{&VoteMessage{}, msgTypeVote},
|
||||
wire.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
|
||||
wire.ConcreteType{&VoteSetMaj23Message{}, msgTypeVoteSetMaj23},
|
||||
wire.ConcreteType{&VoteSetBitsMessage{}, msgTypeVoteSetBits},
|
||||
wire.ConcreteType{&ProposalHeartbeatMessage{}, msgTypeProposalHeartbeat},
|
||||
)
|
||||
func RegisterConsensusMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*ConsensusMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&NewRoundStepMessage{}, "tendermint/NewRoundStepMessage", nil)
|
||||
cdc.RegisterConcrete(&CommitStepMessage{}, "tendermint/CommitStep", nil)
|
||||
cdc.RegisterConcrete(&ProposalMessage{}, "tendermint/Proposal", nil)
|
||||
cdc.RegisterConcrete(&ProposalPOLMessage{}, "tendermint/ProposalPOL", nil)
|
||||
cdc.RegisterConcrete(&BlockPartMessage{}, "tendermint/BlockPart", nil)
|
||||
cdc.RegisterConcrete(&VoteMessage{}, "tendermint/Vote", nil)
|
||||
cdc.RegisterConcrete(&HasVoteMessage{}, "tendermint/HasVote", nil)
|
||||
cdc.RegisterConcrete(&VoteSetMaj23Message{}, "tendermint/VoteSetMaj23", nil)
|
||||
cdc.RegisterConcrete(&VoteSetBitsMessage{}, "tendermint/VoteSetBits", nil)
|
||||
cdc.RegisterConcrete(&ProposalHeartbeatMessage{}, "tendermint/ProposalHeartbeat", nil)
|
||||
}
|
||||
|
||||
// DecodeMessage decodes the given bytes into a ConsensusMessage.
|
||||
// TODO: check for unnecessary extra bytes at the end.
|
||||
func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error) {
|
||||
msgType = bz[0]
|
||||
n := new(int)
|
||||
r := bytes.NewReader(bz)
|
||||
msgI := wire.ReadBinary(struct{ ConsensusMessage }{}, r, maxConsensusMessageSize, n, &err)
|
||||
msg = msgI.(struct{ ConsensusMessage }).ConsensusMessage
|
||||
func DecodeMessage(bz []byte) (msg ConsensusMessage, err error) {
|
||||
err = cdc.UnmarshalBinaryBare(bz, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -301,7 +301,7 @@ func waitForAndValidateBlock(t *testing.T, n int, activeVals map[string]struct{}
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
newBlock := newBlockI.(types.TMEventData).Unwrap().(types.EventDataNewBlock).Block
|
||||
newBlock := newBlockI.(types.EventDataNewBlock).Block
|
||||
css[j].Logger.Debug("waitForAndValidateBlock: Got block", "height", newBlock.Height)
|
||||
err := validateBlock(newBlock, activeVals)
|
||||
assert.Nil(t, err)
|
||||
@@ -322,7 +322,7 @@ func waitForAndValidateBlockWithTx(t *testing.T, n int, activeVals map[string]st
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
newBlock := newBlockI.(types.TMEventData).Unwrap().(types.EventDataNewBlock).Block
|
||||
newBlock := newBlockI.(types.EventDataNewBlock).Block
|
||||
css[j].Logger.Debug("waitForAndValidateBlockWithTx: Got block", "height", newBlock.Height)
|
||||
err := validateBlock(newBlock, activeVals)
|
||||
assert.Nil(t, err)
|
||||
@@ -354,7 +354,7 @@ func waitForBlockWithUpdatedValsAndValidateIt(t *testing.T, n int, updatedVals m
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
newBlock = newBlockI.(types.TMEventData).Unwrap().(types.EventDataNewBlock).Block
|
||||
newBlock = newBlockI.(types.EventDataNewBlock).Block
|
||||
if newBlock.LastCommit.Size() == len(updatedVals) {
|
||||
css[j].Logger.Debug("waitForBlockWithUpdatedValsAndValidateIt: Got block", "height", newBlock.Height)
|
||||
break LOOP
|
||||
|
@@ -17,8 +17,7 @@ import (
|
||||
|
||||
"github.com/tendermint/abci/example/kvstore"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-crypto"
|
||||
auto "github.com/tendermint/tmlibs/autofile"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
@@ -27,6 +26,7 @@ import (
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ func startNewConsensusStateAndWaitForBlock(t *testing.T, lastBlockHeight int64,
|
||||
|
||||
bytes, _ := ioutil.ReadFile(cs.config.WalFile())
|
||||
// fmt.Printf("====== WAL: \n\r%s\n", bytes)
|
||||
t.Logf("====== WAL: \n\r%s\n", bytes)
|
||||
t.Logf("====== WAL: \n\r%X\n", bytes)
|
||||
|
||||
err := cs.Start()
|
||||
require.NoError(t, err)
|
||||
@@ -325,7 +325,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
|
||||
walFile := tempWALWithData(walBody)
|
||||
config.Consensus.SetWalFile(walFile)
|
||||
|
||||
privVal := types.LoadPrivValidatorFS(config.PrivValidatorFile())
|
||||
privVal := pvm.LoadFilePV(config.PrivValidatorFile())
|
||||
|
||||
wal, err := NewWAL(walFile, false)
|
||||
if err != nil {
|
||||
@@ -519,8 +519,8 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
||||
case EndHeightMessage:
|
||||
// if its not the first one, we have a full block
|
||||
if thisBlockParts != nil {
|
||||
var n int
|
||||
block := wire.ReadBinary(&types.Block{}, thisBlockParts.GetReader(), 0, &n, &err).(*types.Block)
|
||||
var block = new(types.Block)
|
||||
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -552,8 +552,8 @@ func makeBlockchainFromWAL(wal WAL) ([]*types.Block, []*types.Commit, error) {
|
||||
}
|
||||
}
|
||||
// grab the last block too
|
||||
var n int
|
||||
block := wire.ReadBinary(&types.Block{}, thisBlockParts.GetReader(), 0, &n, &err).(*types.Block)
|
||||
var block = new(types.Block)
|
||||
_, err = cdc.UnmarshalBinaryReader(thisBlockParts.GetReader(), block, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -10,8 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
fail "github.com/ebuchman/fail-test"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -780,7 +778,7 @@ func (cs *ConsensusState) enterPropose(height int64, round int) {
|
||||
|
||||
// if not a validator, we're done
|
||||
if !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
|
||||
cs.Logger.Debug("This node is not a validator")
|
||||
cs.Logger.Debug("This node is not a validator", "addr", cs.privValidator.GetAddress(), "vals", cs.Validators)
|
||||
return
|
||||
}
|
||||
cs.Logger.Debug("This node is a validator")
|
||||
@@ -1301,10 +1299,10 @@ func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, v
|
||||
}
|
||||
if added && cs.ProposalBlockParts.IsComplete() {
|
||||
// Added and completed!
|
||||
var n int
|
||||
var err error
|
||||
cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(),
|
||||
cs.state.ConsensusParams.BlockSize.MaxBytes, &n, &err).(*types.Block)
|
||||
_, err = cdc.UnmarshalBinaryReader(cs.ProposalBlockParts.GetReader(), &cs.ProposalBlock, int64(cs.state.ConsensusParams.BlockSize.MaxBytes))
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
// NOTE: it's possible to receive complete proposal blocks for future rounds without having the proposal
|
||||
cs.Logger.Info("Received complete proposal block", "height", cs.ProposalBlock.Height, "hash", cs.ProposalBlock.Hash())
|
||||
if cs.Step == cstypes.RoundStepPropose && cs.isProposalComplete() {
|
||||
@@ -1314,7 +1312,7 @@ func (cs *ConsensusState) addProposalBlockPart(height int64, part *types.Part, v
|
||||
// If we're waiting on the proposal block...
|
||||
cs.tryFinalizeCommit(height)
|
||||
}
|
||||
return true, err
|
||||
return true, nil
|
||||
}
|
||||
return added, nil
|
||||
}
|
||||
|
@@ -261,7 +261,7 @@ func TestStateFullRound1(t *testing.T) {
|
||||
|
||||
// grab proposal
|
||||
re := <-propCh
|
||||
propBlockHash := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState).ProposalBlock.Hash()
|
||||
propBlockHash := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState).ProposalBlock.Hash()
|
||||
|
||||
<-voteCh // wait for prevote
|
||||
validatePrevote(t, cs, round, vss[0], propBlockHash)
|
||||
@@ -356,7 +356,7 @@ func TestStateLockNoPOL(t *testing.T) {
|
||||
cs1.startRoutines(0)
|
||||
|
||||
re := <-proposalCh
|
||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
theBlockHash := rs.ProposalBlock.Hash()
|
||||
|
||||
<-voteCh // prevote
|
||||
@@ -396,7 +396,7 @@ func TestStateLockNoPOL(t *testing.T) {
|
||||
|
||||
// now we're on a new round and not the proposer, so wait for timeout
|
||||
re = <-timeoutProposeCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
|
||||
if rs.ProposalBlock != nil {
|
||||
panic("Expected proposal block to be nil")
|
||||
@@ -409,7 +409,7 @@ func TestStateLockNoPOL(t *testing.T) {
|
||||
validatePrevote(t, cs1, 1, vss[0], rs.LockedBlock.Hash())
|
||||
|
||||
// add a conflicting prevote from the other validator
|
||||
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
|
||||
signAddVotes(cs1, types.VoteTypePrevote, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
|
||||
<-voteCh
|
||||
|
||||
// now we're going to enter prevote again, but with invalid args
|
||||
@@ -424,7 +424,7 @@ func TestStateLockNoPOL(t *testing.T) {
|
||||
|
||||
// add conflicting precommit from vs2
|
||||
// NOTE: in practice we should never get to a point where there are precommits for different blocks at the same round
|
||||
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.ProposalBlock.MakePartSet(partSize).Header(), vs2)
|
||||
signAddVotes(cs1, types.VoteTypePrecommit, hash, rs.LockedBlock.MakePartSet(partSize).Header(), vs2)
|
||||
<-voteCh
|
||||
|
||||
// (note we're entering precommit for a second time this round, but with invalid args
|
||||
@@ -440,7 +440,7 @@ func TestStateLockNoPOL(t *testing.T) {
|
||||
incrementRound(vs2)
|
||||
|
||||
re = <-proposalCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
|
||||
// now we're on a new round and are the proposer
|
||||
if !bytes.Equal(rs.ProposalBlock.Hash(), rs.LockedBlock.Hash()) {
|
||||
@@ -529,7 +529,7 @@ func TestStateLockPOLRelock(t *testing.T) {
|
||||
|
||||
<-newRoundCh
|
||||
re := <-proposalCh
|
||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
theBlockHash := rs.ProposalBlock.Hash()
|
||||
|
||||
<-voteCh // prevote
|
||||
@@ -605,9 +605,9 @@ func TestStateLockPOLRelock(t *testing.T) {
|
||||
discardFromChan(voteCh, 2)
|
||||
|
||||
be := <-newBlockCh
|
||||
b := be.(types.TMEventData).Unwrap().(types.EventDataNewBlockHeader)
|
||||
b := be.(types.EventDataNewBlockHeader)
|
||||
re = <-newRoundCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
if rs.Height != 2 {
|
||||
panic("Expected height to increment")
|
||||
}
|
||||
@@ -643,7 +643,7 @@ func TestStateLockPOLUnlock(t *testing.T) {
|
||||
startTestRound(cs1, cs1.Height, 0)
|
||||
<-newRoundCh
|
||||
re := <-proposalCh
|
||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
theBlockHash := rs.ProposalBlock.Hash()
|
||||
|
||||
<-voteCh // prevote
|
||||
@@ -669,7 +669,7 @@ func TestStateLockPOLUnlock(t *testing.T) {
|
||||
|
||||
// timeout to new round
|
||||
re = <-timeoutWaitCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
lockedBlockHash := rs.LockedBlock.Hash()
|
||||
|
||||
//XXX: this isnt guaranteed to get there before the timeoutPropose ...
|
||||
@@ -731,7 +731,7 @@ func TestStateLockPOLSafety1(t *testing.T) {
|
||||
startTestRound(cs1, cs1.Height, 0)
|
||||
<-newRoundCh
|
||||
re := <-proposalCh
|
||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
propBlock := rs.ProposalBlock
|
||||
|
||||
<-voteCh // prevote
|
||||
@@ -781,7 +781,7 @@ func TestStateLockPOLSafety1(t *testing.T) {
|
||||
re = <-proposalCh
|
||||
}
|
||||
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
|
||||
if rs.LockedBlock != nil {
|
||||
panic("we should not be locked!")
|
||||
@@ -1033,7 +1033,7 @@ func TestStateHalt1(t *testing.T) {
|
||||
startTestRound(cs1, cs1.Height, 0)
|
||||
<-newRoundCh
|
||||
re := <-proposalCh
|
||||
rs := re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs := re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
propBlock := rs.ProposalBlock
|
||||
propBlockParts := propBlock.MakePartSet(partSize)
|
||||
|
||||
@@ -1056,7 +1056,7 @@ func TestStateHalt1(t *testing.T) {
|
||||
// timeout to new round
|
||||
<-timeoutWaitCh
|
||||
re = <-newRoundCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
|
||||
t.Log("### ONTO ROUND 1")
|
||||
/*Round2
|
||||
@@ -1074,7 +1074,7 @@ func TestStateHalt1(t *testing.T) {
|
||||
// receiving that precommit should take us straight to commit
|
||||
<-newBlockCh
|
||||
re = <-newRoundCh
|
||||
rs = re.(types.TMEventData).Unwrap().(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
rs = re.(types.EventDataRoundState).RoundState.(*cstypes.RoundState)
|
||||
|
||||
if rs.Height != 2 {
|
||||
panic("expected height to increment")
|
||||
|
@@ -48,7 +48,7 @@ func TestPeerCatchupRounds(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func makeVoteHR(t *testing.T, height int64, round int, privVals []*types.PrivValidatorFS, valIndex int) *types.Vote {
|
||||
func makeVoteHR(t *testing.T, height int64, round int, privVals []types.PrivValidator, valIndex int) *types.Vote {
|
||||
privVal := privVals[valIndex]
|
||||
vote := &types.Vote{
|
||||
ValidatorAddress: privVal.GetAddress(),
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
@@ -11,7 +10,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
auto "github.com/tendermint/tmlibs/autofile"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
@@ -38,13 +37,13 @@ type EndHeightMessage struct {
|
||||
|
||||
type WALMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ WALMessage }{},
|
||||
wire.ConcreteType{types.EventDataRoundState{}, 0x01},
|
||||
wire.ConcreteType{msgInfo{}, 0x02},
|
||||
wire.ConcreteType{timeoutInfo{}, 0x03},
|
||||
wire.ConcreteType{EndHeightMessage{}, 0x04},
|
||||
)
|
||||
func RegisterWALMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*WALMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(types.EventDataRoundState{}, "tendermint/wal/EventDataRoundState", nil)
|
||||
cdc.RegisterConcrete(msgInfo{}, "tendermint/wal/MsgInfo", nil)
|
||||
cdc.RegisterConcrete(timeoutInfo{}, "tendermint/wal/TimeoutInfo", nil)
|
||||
cdc.RegisterConcrete(EndHeightMessage{}, "tendermint/wal/EndHeightMessage", nil)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Simple write-ahead logger
|
||||
@@ -193,7 +192,7 @@ func (wal *baseWAL) SearchForEndHeight(height int64, options *WALSearchOptions)
|
||||
|
||||
// A WALEncoder writes custom-encoded WAL messages to an output stream.
|
||||
//
|
||||
// Format: 4 bytes CRC sum + 4 bytes length + arbitrary-length value (go-wire encoded)
|
||||
// Format: 4 bytes CRC sum + 4 bytes length + arbitrary-length value (go-amino encoded)
|
||||
type WALEncoder struct {
|
||||
wr io.Writer
|
||||
}
|
||||
@@ -205,7 +204,7 @@ func NewWALEncoder(wr io.Writer) *WALEncoder {
|
||||
|
||||
// Encode writes the custom encoding of v to the stream.
|
||||
func (enc *WALEncoder) Encode(v *TimedWALMessage) error {
|
||||
data := wire.BinaryBytes(v)
|
||||
data := cdc.MustMarshalBinaryBare(v)
|
||||
|
||||
crc := crc32.Checksum(data, crc32c)
|
||||
length := uint32(len(data))
|
||||
@@ -298,9 +297,8 @@ func (dec *WALDecoder) Decode() (*TimedWALMessage, error) {
|
||||
return nil, DataCorruptionError{fmt.Errorf("checksums do not match: (read: %v, actual: %v)", crc, actualCRC)}
|
||||
}
|
||||
|
||||
var nn int
|
||||
var res *TimedWALMessage // nolint: gosimple
|
||||
res = wire.ReadBinary(&TimedWALMessage{}, bytes.NewBuffer(data), int(length), &nn, &err).(*TimedWALMessage)
|
||||
var res = new(TimedWALMessage) // nolint: gosimple
|
||||
err = cdc.UnmarshalBinaryBare(data, res)
|
||||
if err != nil {
|
||||
return nil, DataCorruptionError{fmt.Errorf("failed to decode data: %v", err)}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
sm "github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
auto "github.com/tendermint/tmlibs/autofile"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/db"
|
||||
@@ -40,7 +41,7 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) {
|
||||
// COPY PASTE FROM node.go WITH A FEW MODIFICATIONS
|
||||
// NOTE: we can't import node package because of circular dependency
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
privValidator := pvm.LoadOrGenFilePV(privValidatorFile)
|
||||
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to read genesis file")
|
||||
|
@@ -3,11 +3,10 @@ package consensus
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"sync"
|
||||
// "sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tendermint/consensus/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
@@ -36,7 +35,7 @@ func TestWALEncoderDecoder(t *testing.T) {
|
||||
decoded, err := dec.Decode()
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, msg.Time.Truncate(time.Millisecond), decoded.Time)
|
||||
assert.Equal(t, msg.Time.UTC(), decoded.Time)
|
||||
assert.Equal(t, msg.Msg, decoded.Msg)
|
||||
}
|
||||
}
|
||||
@@ -68,6 +67,7 @@ func TestWALSearchForEndHeight(t *testing.T) {
|
||||
assert.Equal(t, rs.Height, h+1, cmn.Fmt("wrong height"))
|
||||
}
|
||||
|
||||
/*
|
||||
var initOnce sync.Once
|
||||
|
||||
func registerInterfacesOnce() {
|
||||
@@ -78,6 +78,7 @@ func registerInterfacesOnce() {
|
||||
)
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
func nBytes(n int) []byte {
|
||||
buf := make([]byte, n)
|
||||
@@ -86,7 +87,7 @@ func nBytes(n int) []byte {
|
||||
}
|
||||
|
||||
func benchmarkWalDecode(b *testing.B, n int) {
|
||||
registerInterfacesOnce()
|
||||
// registerInterfacesOnce()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
enc := NewWALEncoder(buf)
|
||||
|
14
consensus/wire.go
Normal file
14
consensus/wire.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package consensus
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
RegisterConsensusMessages(cdc)
|
||||
RegisterWALMessages(cdc)
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -1,128 +1,29 @@
|
||||
# ADR 008: PrivValidator
|
||||
# ADR 008: SocketPV
|
||||
|
||||
## Context
|
||||
Tendermint node's should support only two in-process PrivValidator
|
||||
implementations:
|
||||
|
||||
The current PrivValidator is monolithic and isn't easily reuseable by alternative signers.
|
||||
- FilePV uses an unencrypted private key in a "priv_validator.json" file - no
|
||||
configuration required (just `tendermint init`).
|
||||
- SocketPV uses a socket to send signing requests to another process - user is
|
||||
responsible for starting that process themselves.
|
||||
|
||||
For instance, see https://github.com/tendermint/tendermint/issues/673
|
||||
The SocketPV address can be provided via flags at the command line - doing so
|
||||
will cause Tendermint to ignore any "priv_validator.json" file and to listen on
|
||||
the given address for incoming connections from an external priv_validator
|
||||
process. It will halt any operation until at least one external process
|
||||
succesfully connected.
|
||||
|
||||
The goal is to have a clean PrivValidator interface like:
|
||||
The external priv_validator process will dial the address to connect to
|
||||
Tendermint, and then Tendermint will send requests on the ensuing connection to
|
||||
sign votes and proposals. Thus the external process initiates the connection,
|
||||
but the Tendermint process makes all requests. In a later stage we're going to
|
||||
support multiple validators for fault tolerance. To prevent double signing they
|
||||
need to be synced, which is deferred to an external solution (see #1185).
|
||||
|
||||
```
|
||||
type PrivValidator interface {
|
||||
Address() data.Bytes
|
||||
PubKey() crypto.PubKey
|
||||
|
||||
SignVote(chainID string, vote *types.Vote) error
|
||||
SignProposal(chainID string, proposal *types.Proposal) error
|
||||
SignHeartbeat(chainID string, heartbeat *types.Heartbeat) error
|
||||
}
|
||||
```
|
||||
|
||||
It should also be easy to re-use the LastSignedInfo logic to avoid double signing.
|
||||
|
||||
## Decision
|
||||
|
||||
Tendermint node's should support only two in-process PrivValidator implementations:
|
||||
|
||||
- PrivValidatorUnencrypted uses an unencrypted private key in a "priv_validator.json" file - no configuration required (just `tendermint init`).
|
||||
- PrivValidatorSocket uses a socket to send signing requests to another process - user is responsible for starting that process themselves.
|
||||
|
||||
The PrivValidatorSocket address can be provided via flags at the command line -
|
||||
doing so will cause Tendermint to ignore any "priv_validator.json" file and to listen
|
||||
on the given address for incoming connections from an external priv_validator process.
|
||||
It will halt any operation until at least one external process succesfully
|
||||
connected.
|
||||
|
||||
The external priv_validator process will dial the address to connect to Tendermint,
|
||||
and then Tendermint will send requests on the ensuing connection to sign votes and proposals.
|
||||
Thus the external process initiates the connection, but the Tendermint process makes all requests.
|
||||
In a later stage we're going to support multiple validators for fault
|
||||
tolerance. To prevent double signing they need to be synced, which is deferred
|
||||
to an external solution (see #1185).
|
||||
|
||||
In addition, Tendermint will provide implementations that can be run in that external process.
|
||||
These include:
|
||||
|
||||
- PrivValidatorEncrypted uses an encrypted private key persisted to disk - user must enter password to decrypt key when process is started.
|
||||
- PrivValidatorLedger uses a Ledger Nano S to handle all signing.
|
||||
|
||||
What follows are descriptions of useful types
|
||||
|
||||
### Signer
|
||||
|
||||
```
|
||||
type Signer interface {
|
||||
Sign(msg []byte) (crypto.Signature, error)
|
||||
}
|
||||
```
|
||||
|
||||
Signer signs a message. It can also return an error.
|
||||
|
||||
### ValidatorID
|
||||
|
||||
|
||||
ValidatorID is just the Address and PubKey
|
||||
|
||||
```
|
||||
type ValidatorID struct {
|
||||
Address data.Bytes `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
}
|
||||
```
|
||||
|
||||
### LastSignedInfo
|
||||
|
||||
LastSignedInfo tracks the last thing we signed:
|
||||
|
||||
```
|
||||
type LastSignedInfo struct {
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Step int8 `json:"step"`
|
||||
Signature crypto.Signature `json:"signature,omitempty"` // so we dont lose signatures
|
||||
SignBytes data.Bytes `json:"signbytes,omitempty"` // so we dont lose signatures
|
||||
}
|
||||
```
|
||||
|
||||
It exposes methods for signing votes and proposals using a `Signer`.
|
||||
|
||||
This allows it to easily be reused by developers implemented their own PrivValidator.
|
||||
|
||||
### PrivValidatorUnencrypted
|
||||
|
||||
```
|
||||
type PrivValidatorUnencrypted struct {
|
||||
ID types.ValidatorID `json:"id"`
|
||||
PrivKey PrivKey `json:"priv_key"`
|
||||
LastSignedInfo *LastSignedInfo `json:"last_signed_info"`
|
||||
}
|
||||
```
|
||||
|
||||
Has the same structure as currently, but broken up into sub structs.
|
||||
|
||||
Note the LastSignedInfo is mutated in place every time we sign.
|
||||
|
||||
### PrivValidatorJSON
|
||||
|
||||
The "priv_validator.json" file supports only the PrivValidatorUnencrypted type.
|
||||
|
||||
It unmarshals into PrivValidatorJSON, which is used as the default PrivValidator type.
|
||||
It wraps the PrivValidatorUnencrypted and persists it to disk after every signature.
|
||||
|
||||
## Status
|
||||
|
||||
Accepted.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- Cleaner separation of components enabling re-use.
|
||||
|
||||
### Negative
|
||||
|
||||
- More files - led to creation of new directory.
|
||||
|
||||
### Neutral
|
||||
In addition, Tendermint will provide implementations that can be run in that
|
||||
external process. These include:
|
||||
|
||||
- FilePV will encrypt the private key, and the user must enter password to
|
||||
decrypt key when process is started.
|
||||
- LedgerPV uses a Ledger Nano S to handle all signing.
|
||||
|
@@ -1,14 +1,12 @@
|
||||
package evidence
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
@@ -68,7 +66,7 @@ func (evR *EvidenceReactor) AddPeer(peer p2p.Peer) {
|
||||
// the rest will be sent by the broadcastRoutine
|
||||
evidences := evR.evpool.PriorityEvidence()
|
||||
msg := &EvidenceListMessage{evidences}
|
||||
success := peer.Send(EvidenceChannel, struct{ EvidenceMessage }{msg})
|
||||
success := peer.Send(EvidenceChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
if !success {
|
||||
// TODO: remove peer ?
|
||||
}
|
||||
@@ -82,7 +80,7 @@ func (evR *EvidenceReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
// Receive implements Reactor.
|
||||
// It adds any received evidence to the evpool.
|
||||
func (evR *EvidenceReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
_, msg, err := DecodeMessage(msgBytes)
|
||||
msg, err := DecodeMessage(msgBytes)
|
||||
if err != nil {
|
||||
evR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
|
||||
evR.Switch.StopPeerForError(src, err)
|
||||
@@ -119,7 +117,7 @@ func (evR *EvidenceReactor) broadcastRoutine() {
|
||||
case evidence := <-evR.evpool.EvidenceChan():
|
||||
// broadcast some new evidence
|
||||
msg := &EvidenceListMessage{[]types.Evidence{evidence}}
|
||||
evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})
|
||||
evR.Switch.Broadcast(EvidenceChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
|
||||
// TODO: Broadcast runs asynchronously, so this should wait on the successChan
|
||||
// in another routine before marking to be proper.
|
||||
@@ -127,7 +125,7 @@ func (evR *EvidenceReactor) broadcastRoutine() {
|
||||
case <-ticker.C:
|
||||
// broadcast all pending evidence
|
||||
msg := &EvidenceListMessage{evR.evpool.PendingEvidence()}
|
||||
evR.Switch.Broadcast(EvidenceChannel, struct{ EvidenceMessage }{msg})
|
||||
evR.Switch.Broadcast(EvidenceChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
case <-evR.Quit():
|
||||
return
|
||||
}
|
||||
@@ -137,24 +135,18 @@ func (evR *EvidenceReactor) broadcastRoutine() {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeEvidence = byte(0x01)
|
||||
)
|
||||
|
||||
// EvidenceMessage is a message sent or received by the EvidenceReactor.
|
||||
type EvidenceMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ EvidenceMessage }{},
|
||||
wire.ConcreteType{&EvidenceListMessage{}, msgTypeEvidence},
|
||||
)
|
||||
func RegisterEvidenceMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*EvidenceMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&EvidenceListMessage{},
|
||||
"tendermint/evidence/EvidenceListMessage", nil)
|
||||
}
|
||||
|
||||
// DecodeMessage decodes a byte-array into a EvidenceMessage.
|
||||
func DecodeMessage(bz []byte) (msgType byte, msg EvidenceMessage, err error) {
|
||||
msgType = bz[0]
|
||||
n := new(int)
|
||||
r := bytes.NewReader(bz)
|
||||
msg = wire.ReadBinary(struct{ EvidenceMessage }{}, r, maxEvidenceMessageSize, n, &err).(struct{ EvidenceMessage }).EvidenceMessage
|
||||
func DecodeMessage(bz []byte) (msg EvidenceMessage, err error) {
|
||||
err = cdc.UnmarshalBinaryBare(bz, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ package evidence
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
)
|
||||
@@ -104,7 +103,10 @@ func (store *EvidenceStore) ListEvidence(prefixKey string) (evidence []types.Evi
|
||||
val := iter.Value()
|
||||
|
||||
var ei EvidenceInfo
|
||||
wire.ReadBinaryBytes(val, &ei)
|
||||
err := cdc.UnmarshalBinaryBare(val, &ei)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
evidence = append(evidence, ei.Evidence)
|
||||
}
|
||||
return evidence
|
||||
@@ -119,7 +121,10 @@ func (store *EvidenceStore) GetEvidence(height int64, hash []byte) *EvidenceInfo
|
||||
return nil
|
||||
}
|
||||
var ei EvidenceInfo
|
||||
wire.ReadBinaryBytes(val, &ei)
|
||||
err := cdc.UnmarshalBinaryBare(val, &ei)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &ei
|
||||
}
|
||||
|
||||
@@ -137,7 +142,7 @@ func (store *EvidenceStore) AddNewEvidence(evidence types.Evidence, priority int
|
||||
Priority: priority,
|
||||
Evidence: evidence,
|
||||
}
|
||||
eiBytes := wire.BinaryBytes(ei)
|
||||
eiBytes := cdc.MustMarshalBinaryBare(ei)
|
||||
|
||||
// add it to the store
|
||||
key := keyOutqueue(evidence, priority)
|
||||
@@ -171,7 +176,7 @@ func (store *EvidenceStore) MarkEvidenceAsCommitted(evidence types.Evidence) {
|
||||
ei.Committed = true
|
||||
|
||||
lookupKey := keyLookup(evidence)
|
||||
store.db.SetSync(lookupKey, wire.BinaryBytes(ei))
|
||||
store.db.SetSync(lookupKey, cdc.MustMarshalBinaryBare(ei))
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
@@ -181,6 +186,9 @@ func (store *EvidenceStore) getEvidenceInfo(evidence types.Evidence) EvidenceInf
|
||||
key := keyLookup(evidence)
|
||||
var ei EvidenceInfo
|
||||
b := store.db.Get(key)
|
||||
wire.ReadBinaryBytes(b, &ei)
|
||||
err := cdc.UnmarshalBinaryBare(b, &ei)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ei
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
)
|
||||
@@ -108,15 +107,3 @@ func TestStorePriority(t *testing.T) {
|
||||
assert.Equal(ev, cases[i].ev)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
const (
|
||||
evidenceTypeMockGood = byte(0x01)
|
||||
evidenceTypeMockBad = byte(0x02)
|
||||
)
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ types.Evidence }{},
|
||||
wire.ConcreteType{types.MockGoodEvidence{}, evidenceTypeMockGood},
|
||||
wire.ConcreteType{types.MockBadEvidence{}, evidenceTypeMockBad},
|
||||
)
|
||||
|
25
evidence/wire.go
Normal file
25
evidence/wire.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package evidence
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
RegisterEvidenceMessages(cdc)
|
||||
crypto.RegisterAmino(cdc)
|
||||
types.RegisterEvidences(cdc)
|
||||
RegisterMockEvidences(cdc) // For testing
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
func RegisterMockEvidences(cdc *amino.Codec) {
|
||||
cdc.RegisterConcrete(types.MockGoodEvidence{},
|
||||
"tendermint/MockGoodEvidence", nil)
|
||||
cdc.RegisterConcrete(types.MockBadEvidence{},
|
||||
"tendermint/MockBadEvidence", nil)
|
||||
}
|
@@ -1,13 +1,11 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/tendermint/tendermint/lite"
|
||||
liteErr "github.com/tendermint/tendermint/lite/errors"
|
||||
)
|
||||
@@ -19,7 +17,7 @@ const (
|
||||
MaxFullCommitSize = 1024 * 1024
|
||||
)
|
||||
|
||||
// SaveFullCommit exports the seed in binary / go-wire style
|
||||
// SaveFullCommit exports the seed in binary / go-amino style
|
||||
func SaveFullCommit(fc lite.FullCommit, path string) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -27,9 +25,11 @@ func SaveFullCommit(fc lite.FullCommit, path string) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var n int
|
||||
wire.WriteBinary(fc, f, &n, &err)
|
||||
return errors.WithStack(err)
|
||||
_, err = cdc.MarshalBinaryWriter(f, fc)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveFullCommitJSON exports the seed in a json format
|
||||
@@ -39,9 +39,15 @@ func SaveFullCommitJSON(fc lite.FullCommit, path string) error {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
defer f.Close()
|
||||
stream := json.NewEncoder(f)
|
||||
err = stream.Encode(fc)
|
||||
return errors.WithStack(err)
|
||||
bz, err := cdc.MarshalJSON(fc)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
_, err = f.Write(bz)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadFullCommit loads the full commit from the file system.
|
||||
@@ -56,9 +62,11 @@ func LoadFullCommit(path string) (lite.FullCommit, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var n int
|
||||
wire.ReadBinaryPtr(&fc, f, MaxFullCommitSize, &n, &err)
|
||||
return fc, errors.WithStack(err)
|
||||
_, err = cdc.UnmarshalBinaryReader(f, &fc, 0)
|
||||
if err != nil {
|
||||
return fc, errors.WithStack(err)
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
// LoadFullCommitJSON loads the commit from the file system in JSON format.
|
||||
@@ -73,7 +81,13 @@ func LoadFullCommitJSON(path string) (lite.FullCommit, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stream := json.NewDecoder(f)
|
||||
err = stream.Decode(&fc)
|
||||
return fc, errors.WithStack(err)
|
||||
bz, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return fc, errors.WithStack(err)
|
||||
}
|
||||
err = cdc.UnmarshalJSON(bz, &fc)
|
||||
if err != nil {
|
||||
return fc, errors.WithStack(err)
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
12
lite/files/wire.go
Normal file
12
lite/files/wire.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -23,7 +23,7 @@ type ValKeys []crypto.PrivKey
|
||||
func GenValKeys(n int) ValKeys {
|
||||
res := make(ValKeys, n)
|
||||
for i := range res {
|
||||
res[i] = crypto.GenPrivKeyEd25519().Wrap()
|
||||
res[i] = crypto.GenPrivKeyEd25519()
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -32,7 +32,7 @@ func GenValKeys(n int) ValKeys {
|
||||
func (v ValKeys) Change(i int) ValKeys {
|
||||
res := make(ValKeys, len(v))
|
||||
copy(res, v)
|
||||
res[i] = crypto.GenPrivKeyEd25519().Wrap()
|
||||
res[i] = crypto.GenPrivKeyEd25519()
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (v ValKeys) Extend(n int) ValKeys {
|
||||
func GenSecpValKeys(n int) ValKeys {
|
||||
res := make(ValKeys, n)
|
||||
for i := range res {
|
||||
res[i] = crypto.GenPrivKeySecp256k1().Wrap()
|
||||
res[i] = crypto.GenPrivKeySecp256k1()
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
@@ -3,10 +3,12 @@ package proxy
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/rpc/core"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
rpc "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
)
|
||||
|
||||
@@ -23,13 +25,15 @@ func StartProxy(c rpcclient.Client, listenAddr string, logger log.Logger) error
|
||||
return err
|
||||
}
|
||||
|
||||
cdc := amino.NewCodec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
r := RPCRoutes(c)
|
||||
|
||||
// build the handler...
|
||||
mux := http.NewServeMux()
|
||||
rpc.RegisterRPCFuncs(mux, r, logger)
|
||||
rpc.RegisterRPCFuncs(mux, r, cdc, logger)
|
||||
|
||||
wm := rpc.NewWebsocketManager(r, rpc.EventSubscriber(c))
|
||||
wm := rpc.NewWebsocketManager(r, cdc, rpc.EventSubscriber(c))
|
||||
wm.SetLogger(logger)
|
||||
core.SetLogger(logger)
|
||||
mux.HandleFunc(wsEndpoint, wm.WebsocketHandler)
|
||||
|
@@ -146,7 +146,7 @@ func (w Wrapper) Commit(height *int64) (*ctypes.ResultCommit, error) {
|
||||
// }
|
||||
|
||||
// // check to validate it if possible, and drop if not valid
|
||||
// switch t := tm.Unwrap().(type) {
|
||||
// switch t := tm.(type) {
|
||||
// case types.EventDataNewBlockHeader:
|
||||
// err := verifyHeader(s.client, t.Header)
|
||||
// if err != nil {
|
||||
|
@@ -1,13 +1,12 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tmlibs/clist"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -71,7 +70,7 @@ func (memR *MempoolReactor) RemovePeer(peer p2p.Peer, reason interface{}) {
|
||||
// Receive implements Reactor.
|
||||
// It adds any received transactions to the mempool.
|
||||
func (memR *MempoolReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) {
|
||||
_, msg, err := DecodeMessage(msgBytes)
|
||||
msg, err := DecodeMessage(msgBytes)
|
||||
if err != nil {
|
||||
memR.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
|
||||
memR.Switch.StopPeerForError(src, err)
|
||||
@@ -137,7 +136,7 @@ func (memR *MempoolReactor) broadcastTxRoutine(peer p2p.Peer) {
|
||||
}
|
||||
// send memTx
|
||||
msg := &TxMessage{Tx: memTx.tx}
|
||||
success := peer.Send(MempoolChannel, struct{ MempoolMessage }{msg})
|
||||
success := peer.Send(MempoolChannel, cdc.MustMarshalBinaryBare(msg))
|
||||
if !success {
|
||||
time.Sleep(peerCatchupSleepIntervalMS * time.Millisecond)
|
||||
continue
|
||||
@@ -158,24 +157,17 @@ func (memR *MempoolReactor) broadcastTxRoutine(peer p2p.Peer) {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeTx = byte(0x01)
|
||||
)
|
||||
|
||||
// MempoolMessage is a message sent or received by the MempoolReactor.
|
||||
type MempoolMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ MempoolMessage }{},
|
||||
wire.ConcreteType{&TxMessage{}, msgTypeTx},
|
||||
)
|
||||
func RegisterMempoolMessages(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*MempoolMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&TxMessage{}, "tendermint/mempool/TxMessage", nil)
|
||||
}
|
||||
|
||||
// DecodeMessage decodes a byte-array into a MempoolMessage.
|
||||
func DecodeMessage(bz []byte) (msgType byte, msg MempoolMessage, err error) {
|
||||
msgType = bz[0]
|
||||
n := new(int)
|
||||
r := bytes.NewReader(bz)
|
||||
msg = wire.ReadBinary(struct{ MempoolMessage }{}, r, maxMempoolMessageSize, n, &err).(struct{ MempoolMessage }).MempoolMessage
|
||||
func DecodeMessage(bz []byte) (msg MempoolMessage, err error) {
|
||||
err = cdc.UnmarshalBinaryBare(bz, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
|
11
mempool/wire.go
Normal file
11
mempool/wire.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package mempool
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
RegisterMempoolMessages(cdc)
|
||||
}
|
21
node/node.go
21
node/node.go
@@ -10,8 +10,8 @@ import (
|
||||
"strings"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"github.com/tendermint/tendermint/p2p/trust"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
rpccore "github.com/tendermint/tendermint/rpc/core"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
grpccore "github.com/tendermint/tendermint/rpc/grpc"
|
||||
rpc "github.com/tendermint/tendermint/rpc/lib"
|
||||
rpcserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
@@ -34,7 +35,7 @@ import (
|
||||
"github.com/tendermint/tendermint/state/txindex/kv"
|
||||
"github.com/tendermint/tendermint/state/txindex/null"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
priv_val "github.com/tendermint/tendermint/types/priv_validator"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
"github.com/tendermint/tendermint/version"
|
||||
|
||||
_ "net/http/pprof"
|
||||
@@ -79,7 +80,7 @@ type NodeProvider func(*cfg.Config, log.Logger) (*Node, error)
|
||||
// It implements NodeProvider.
|
||||
func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
|
||||
return NewNode(config,
|
||||
types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile()),
|
||||
pvm.LoadOrGenFilePV(config.PrivValidatorFile()),
|
||||
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
|
||||
DefaultGenesisDocProviderFunc(config),
|
||||
DefaultDBProvider,
|
||||
@@ -180,8 +181,8 @@ func NewNode(config *cfg.Config,
|
||||
// TODO: persist this key so external signer
|
||||
// can actually authenticate us
|
||||
privKey = crypto.GenPrivKeyEd25519()
|
||||
pvsc = priv_val.NewSocketClient(
|
||||
logger.With("module", "priv_val"),
|
||||
pvsc = pvm.NewSocketPV(
|
||||
logger.With("module", "pvm"),
|
||||
config.PrivValidatorListenAddr,
|
||||
privKey,
|
||||
)
|
||||
@@ -445,7 +446,7 @@ func (n *Node) OnStop() {
|
||||
n.eventBus.Stop()
|
||||
n.indexerService.Stop()
|
||||
|
||||
if pvsc, ok := n.privValidator.(*priv_val.SocketClient); ok {
|
||||
if pvsc, ok := n.privValidator.(*pvm.SocketPV); ok {
|
||||
if err := pvsc.Stop(); err != nil {
|
||||
n.Logger.Error("Error stopping priv validator socket client", "err", err)
|
||||
}
|
||||
@@ -489,6 +490,8 @@ func (n *Node) ConfigureRPC() {
|
||||
func (n *Node) startRPC() ([]net.Listener, error) {
|
||||
n.ConfigureRPC()
|
||||
listenAddrs := strings.Split(n.config.RPC.ListenAddress, ",")
|
||||
coreCodec := amino.NewCodec()
|
||||
ctypes.RegisterAmino(coreCodec)
|
||||
|
||||
if n.config.RPC.Unsafe {
|
||||
rpccore.AddUnsafeRoutes()
|
||||
@@ -499,10 +502,10 @@ func (n *Node) startRPC() ([]net.Listener, error) {
|
||||
for i, listenAddr := range listenAddrs {
|
||||
mux := http.NewServeMux()
|
||||
rpcLogger := n.Logger.With("module", "rpc-server")
|
||||
wm := rpcserver.NewWebsocketManager(rpccore.Routes, rpcserver.EventSubscriber(n.eventBus))
|
||||
wm := rpcserver.NewWebsocketManager(rpccore.Routes, coreCodec, rpcserver.EventSubscriber(n.eventBus))
|
||||
wm.SetLogger(rpcLogger.With("protocol", "websocket"))
|
||||
mux.HandleFunc("/websocket", wm.WebsocketHandler)
|
||||
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, rpcLogger)
|
||||
rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)
|
||||
listener, err := rpcserver.StartHTTPServer(listenAddr, mux, rpcLogger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -591,7 +594,7 @@ func (n *Node) makeNodeInfo(pubKey crypto.PubKey) p2p.NodeInfo {
|
||||
},
|
||||
Moniker: n.config.Moniker,
|
||||
Other: []string{
|
||||
cmn.Fmt("wire_version=%v", wire.Version),
|
||||
cmn.Fmt("amino_version=%v", amino.Version),
|
||||
cmn.Fmt("p2p_version=%v", p2p.Version),
|
||||
cmn.Fmt("consensus_version=%v", cs.Version),
|
||||
cmn.Fmt("rpc_version=%v/%v", rpc.Version, rpccore.Version),
|
||||
|
@@ -7,18 +7,21 @@ import (
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
flow "github.com/tendermint/tmlibs/flowrate"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
const (
|
||||
numBatchMsgPackets = 10
|
||||
maxPacketMsgPayloadSizeDefault = 1024 // NOTE: Must be below 16,384 bytes for 14 below.
|
||||
maxPacketMsgOverheadSize = 14 // NOTE: See connection_test for derivation.
|
||||
|
||||
numBatchPacketMsgs = 10
|
||||
minReadBufferSize = 1024
|
||||
minWriteBufferSize = 65536
|
||||
updateStats = 2 * time.Second
|
||||
@@ -53,35 +56,34 @@ The byte id and the relative priorities of each `Channel` are configured upon
|
||||
initialization of the connection.
|
||||
|
||||
There are two methods for sending messages:
|
||||
func (m MConnection) Send(chID byte, msg interface{}) bool {}
|
||||
func (m MConnection) TrySend(chID byte, msg interface{}) bool {}
|
||||
func (m MConnection) Send(chID byte, msgBytes []byte) bool {}
|
||||
func (m MConnection) TrySend(chID byte, msgBytes []byte}) bool {}
|
||||
|
||||
`Send(chID, msg)` is a blocking call that waits until `msg` is successfully queued
|
||||
for the channel with the given id byte `chID`, or until the request times out.
|
||||
The message `msg` is serialized using the `tendermint/wire` submodule's
|
||||
`WriteBinary()` reflection routine.
|
||||
`Send(chID, msgBytes)` is a blocking call that waits until `msg` is
|
||||
successfully queued for the channel with the given id byte `chID`, or until the
|
||||
request times out. The message `msg` is serialized using Go-Amino.
|
||||
|
||||
`TrySend(chID, msg)` is a nonblocking call that returns false if the channel's
|
||||
queue is full.
|
||||
`TrySend(chID, msgBytes)` is a nonblocking call that returns false if the
|
||||
channel's queue is full.
|
||||
|
||||
Inbound message bytes are handled with an onReceive callback function.
|
||||
*/
|
||||
type MConnection struct {
|
||||
cmn.BaseService
|
||||
|
||||
conn net.Conn
|
||||
bufReader *bufio.Reader
|
||||
bufWriter *bufio.Writer
|
||||
sendMonitor *flow.Monitor
|
||||
recvMonitor *flow.Monitor
|
||||
send chan struct{}
|
||||
pong chan struct{}
|
||||
channels []*Channel
|
||||
channelsIdx map[byte]*Channel
|
||||
onReceive receiveCbFunc
|
||||
onError errorCbFunc
|
||||
errored uint32
|
||||
config *MConnConfig
|
||||
conn net.Conn
|
||||
bufConnReader *bufio.Reader
|
||||
bufConnWriter *bufio.Writer
|
||||
sendMonitor *flow.Monitor
|
||||
recvMonitor *flow.Monitor
|
||||
send chan struct{}
|
||||
pong chan struct{}
|
||||
channels []*Channel
|
||||
channelsIdx map[byte]*Channel
|
||||
onReceive receiveCbFunc
|
||||
onError errorCbFunc
|
||||
errored uint32
|
||||
config *MConnConfig
|
||||
|
||||
quit chan struct{}
|
||||
flushTimer *cmn.ThrottleTimer // flush writes as necessary but throttled.
|
||||
@@ -102,7 +104,7 @@ type MConnConfig struct {
|
||||
RecvRate int64 `mapstructure:"recv_rate"`
|
||||
|
||||
// Maximum payload size
|
||||
MaxMsgPacketPayloadSize int `mapstructure:"max_msg_packet_payload_size"`
|
||||
MaxPacketMsgPayloadSize int `mapstructure:"max_packet_msg_payload_size"`
|
||||
|
||||
// Interval to flush writes (throttled)
|
||||
FlushThrottle time.Duration `mapstructure:"flush_throttle"`
|
||||
@@ -114,8 +116,8 @@ type MConnConfig struct {
|
||||
PongTimeout time.Duration `mapstructure:"pong_timeout"`
|
||||
}
|
||||
|
||||
func (cfg *MConnConfig) maxMsgPacketTotalSize() int {
|
||||
return cfg.MaxMsgPacketPayloadSize + maxMsgPacketOverheadSize
|
||||
func (cfg *MConnConfig) maxPacketMsgTotalSize() int {
|
||||
return cfg.MaxPacketMsgPayloadSize + maxPacketMsgOverheadSize
|
||||
}
|
||||
|
||||
// DefaultMConnConfig returns the default config.
|
||||
@@ -123,7 +125,7 @@ func DefaultMConnConfig() *MConnConfig {
|
||||
return &MConnConfig{
|
||||
SendRate: defaultSendRate,
|
||||
RecvRate: defaultRecvRate,
|
||||
MaxMsgPacketPayloadSize: defaultMaxMsgPacketPayloadSize,
|
||||
MaxPacketMsgPayloadSize: maxPacketMsgPayloadSizeDefault,
|
||||
FlushThrottle: defaultFlushThrottle,
|
||||
PingInterval: defaultPingInterval,
|
||||
PongTimeout: defaultPongTimeout,
|
||||
@@ -147,16 +149,16 @@ func NewMConnectionWithConfig(conn net.Conn, chDescs []*ChannelDescriptor, onRec
|
||||
}
|
||||
|
||||
mconn := &MConnection{
|
||||
conn: conn,
|
||||
bufReader: bufio.NewReaderSize(conn, minReadBufferSize),
|
||||
bufWriter: bufio.NewWriterSize(conn, minWriteBufferSize),
|
||||
sendMonitor: flow.New(0, 0),
|
||||
recvMonitor: flow.New(0, 0),
|
||||
send: make(chan struct{}, 1),
|
||||
pong: make(chan struct{}, 1),
|
||||
onReceive: onReceive,
|
||||
onError: onError,
|
||||
config: config,
|
||||
conn: conn,
|
||||
bufConnReader: bufio.NewReaderSize(conn, minReadBufferSize),
|
||||
bufConnWriter: bufio.NewWriterSize(conn, minWriteBufferSize),
|
||||
sendMonitor: flow.New(0, 0),
|
||||
recvMonitor: flow.New(0, 0),
|
||||
send: make(chan struct{}, 1),
|
||||
pong: make(chan struct{}, 1),
|
||||
onReceive: onReceive,
|
||||
onError: onError,
|
||||
config: config,
|
||||
}
|
||||
|
||||
// Create channels
|
||||
@@ -221,7 +223,7 @@ func (c *MConnection) String() string {
|
||||
|
||||
func (c *MConnection) flush() {
|
||||
c.Logger.Debug("Flush", "conn", c)
|
||||
err := c.bufWriter.Flush()
|
||||
err := c.bufConnWriter.Flush()
|
||||
if err != nil {
|
||||
c.Logger.Error("MConnection flush failed", "err", err)
|
||||
}
|
||||
@@ -230,8 +232,7 @@ func (c *MConnection) flush() {
|
||||
// Catch panics, usually caused by remote disconnects.
|
||||
func (c *MConnection) _recover() {
|
||||
if r := recover(); r != nil {
|
||||
stack := debug.Stack()
|
||||
err := cmn.StackError{r, stack}
|
||||
err := cmn.ErrorWrap(r, "recovered panic in MConnection")
|
||||
c.stopForError(err)
|
||||
}
|
||||
}
|
||||
@@ -246,12 +247,12 @@ func (c *MConnection) stopForError(r interface{}) {
|
||||
}
|
||||
|
||||
// Queues a message to be sent to channel.
|
||||
func (c *MConnection) Send(chID byte, msg interface{}) bool {
|
||||
func (c *MConnection) Send(chID byte, msgBytes []byte) bool {
|
||||
if !c.IsRunning() {
|
||||
return false
|
||||
}
|
||||
|
||||
c.Logger.Debug("Send", "channel", chID, "conn", c, "msg", msg) //, "bytes", wire.BinaryBytes(msg))
|
||||
c.Logger.Debug("Send", "channel", chID, "conn", c, "msgBytes", fmt.Sprintf("%X", msgBytes))
|
||||
|
||||
// Send message to channel.
|
||||
channel, ok := c.channelsIdx[chID]
|
||||
@@ -260,7 +261,7 @@ func (c *MConnection) Send(chID byte, msg interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
success := channel.sendBytes(wire.BinaryBytes(msg))
|
||||
success := channel.sendBytes(msgBytes)
|
||||
if success {
|
||||
// Wake up sendRoutine if necessary
|
||||
select {
|
||||
@@ -268,19 +269,19 @@ func (c *MConnection) Send(chID byte, msg interface{}) bool {
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
c.Logger.Error("Send failed", "channel", chID, "conn", c, "msg", msg)
|
||||
c.Logger.Error("Send failed", "channel", chID, "conn", c, "msgBytes", fmt.Sprintf("%X", msgBytes))
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
// Queues a message to be sent to channel.
|
||||
// Nonblocking, returns true if successful.
|
||||
func (c *MConnection) TrySend(chID byte, msg interface{}) bool {
|
||||
func (c *MConnection) TrySend(chID byte, msgBytes []byte) bool {
|
||||
if !c.IsRunning() {
|
||||
return false
|
||||
}
|
||||
|
||||
c.Logger.Debug("TrySend", "channel", chID, "conn", c, "msg", msg)
|
||||
c.Logger.Debug("TrySend", "channel", chID, "conn", c, "msgBytes", fmt.Sprintf("%X", msgBytes))
|
||||
|
||||
// Send message to channel.
|
||||
channel, ok := c.channelsIdx[chID]
|
||||
@@ -289,7 +290,7 @@ func (c *MConnection) TrySend(chID byte, msg interface{}) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
ok = channel.trySendBytes(wire.BinaryBytes(msg))
|
||||
ok = channel.trySendBytes(msgBytes)
|
||||
if ok {
|
||||
// Wake up sendRoutine if necessary
|
||||
select {
|
||||
@@ -322,12 +323,13 @@ func (c *MConnection) sendRoutine() {
|
||||
|
||||
FOR_LOOP:
|
||||
for {
|
||||
var n int
|
||||
var _n int64
|
||||
var err error
|
||||
SELECTION:
|
||||
select {
|
||||
case <-c.flushTimer.Ch:
|
||||
// NOTE: flushTimer.Set() must be called every time
|
||||
// something is written to .bufWriter.
|
||||
// something is written to .bufConnWriter.
|
||||
c.flush()
|
||||
case <-c.chStatsTimer.Chan():
|
||||
for _, channel := range c.channels {
|
||||
@@ -335,8 +337,11 @@ FOR_LOOP:
|
||||
}
|
||||
case <-c.pingTimer.Chan():
|
||||
c.Logger.Debug("Send Ping")
|
||||
wire.WriteByte(packetTypePing, c.bufWriter, &n, &err)
|
||||
c.sendMonitor.Update(int(n))
|
||||
_n, err = cdc.MarshalBinaryWriter(c.bufConnWriter, PacketPing{})
|
||||
if err != nil {
|
||||
break SELECTION
|
||||
}
|
||||
c.sendMonitor.Update(int(_n))
|
||||
c.Logger.Debug("Starting pong timer", "dur", c.config.PongTimeout)
|
||||
c.pongTimer = time.AfterFunc(c.config.PongTimeout, func() {
|
||||
select {
|
||||
@@ -354,14 +359,17 @@ FOR_LOOP:
|
||||
}
|
||||
case <-c.pong:
|
||||
c.Logger.Debug("Send Pong")
|
||||
wire.WriteByte(packetTypePong, c.bufWriter, &n, &err)
|
||||
c.sendMonitor.Update(int(n))
|
||||
_n, err = cdc.MarshalBinaryWriter(c.bufConnWriter, PacketPong{})
|
||||
if err != nil {
|
||||
break SELECTION
|
||||
}
|
||||
c.sendMonitor.Update(int(_n))
|
||||
c.flush()
|
||||
case <-c.quit:
|
||||
break FOR_LOOP
|
||||
case <-c.send:
|
||||
// Send some msgPackets
|
||||
eof := c.sendSomeMsgPackets()
|
||||
// Send some PacketMsgs
|
||||
eof := c.sendSomePacketMsgs()
|
||||
if !eof {
|
||||
// Keep sendRoutine awake.
|
||||
select {
|
||||
@@ -387,15 +395,15 @@ FOR_LOOP:
|
||||
|
||||
// Returns true if messages from channels were exhausted.
|
||||
// Blocks in accordance to .sendMonitor throttling.
|
||||
func (c *MConnection) sendSomeMsgPackets() bool {
|
||||
func (c *MConnection) sendSomePacketMsgs() bool {
|
||||
// Block until .sendMonitor says we can write.
|
||||
// Once we're ready we send more than we asked for,
|
||||
// but amortized it should even out.
|
||||
c.sendMonitor.Limit(c.config.maxMsgPacketTotalSize(), atomic.LoadInt64(&c.config.SendRate), true)
|
||||
c.sendMonitor.Limit(c.config.maxPacketMsgTotalSize(), atomic.LoadInt64(&c.config.SendRate), true)
|
||||
|
||||
// Now send some msgPackets.
|
||||
for i := 0; i < numBatchMsgPackets; i++ {
|
||||
if c.sendMsgPacket() {
|
||||
// Now send some PacketMsgs.
|
||||
for i := 0; i < numBatchPacketMsgs; i++ {
|
||||
if c.sendPacketMsg() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -403,8 +411,8 @@ func (c *MConnection) sendSomeMsgPackets() bool {
|
||||
}
|
||||
|
||||
// Returns true if messages from channels were exhausted.
|
||||
func (c *MConnection) sendMsgPacket() bool {
|
||||
// Choose a channel to create a msgPacket from.
|
||||
func (c *MConnection) sendPacketMsg() bool {
|
||||
// Choose a channel to create a PacketMsg from.
|
||||
// The chosen channel will be the one whose recentlySent/priority is the least.
|
||||
var leastRatio float32 = math.MaxFloat32
|
||||
var leastChannel *Channel
|
||||
@@ -425,22 +433,22 @@ func (c *MConnection) sendMsgPacket() bool {
|
||||
if leastChannel == nil {
|
||||
return true
|
||||
} else {
|
||||
// c.Logger.Info("Found a msgPacket to send")
|
||||
// c.Logger.Info("Found a PacketMsg to send")
|
||||
}
|
||||
|
||||
// Make & send a msgPacket from this channel
|
||||
n, err := leastChannel.writeMsgPacketTo(c.bufWriter)
|
||||
// Make & send a PacketMsg from this channel
|
||||
_n, err := leastChannel.writePacketMsgTo(c.bufConnWriter)
|
||||
if err != nil {
|
||||
c.Logger.Error("Failed to write msgPacket", "err", err)
|
||||
c.Logger.Error("Failed to write PacketMsg", "err", err)
|
||||
c.stopForError(err)
|
||||
return true
|
||||
}
|
||||
c.sendMonitor.Update(int(n))
|
||||
c.sendMonitor.Update(int(_n))
|
||||
c.flushTimer.Set()
|
||||
return false
|
||||
}
|
||||
|
||||
// recvRoutine reads msgPackets and reconstructs the message using the channels' "recving" buffer.
|
||||
// recvRoutine reads PacketMsgs and reconstructs the message using the channels' "recving" buffer.
|
||||
// After a whole message has been assembled, it's pushed to onReceive().
|
||||
// Blocks depending on how the connection is throttled.
|
||||
// Otherwise, it never blocks.
|
||||
@@ -450,28 +458,28 @@ func (c *MConnection) recvRoutine() {
|
||||
FOR_LOOP:
|
||||
for {
|
||||
// Block until .recvMonitor says we can read.
|
||||
c.recvMonitor.Limit(c.config.maxMsgPacketTotalSize(), atomic.LoadInt64(&c.config.RecvRate), true)
|
||||
c.recvMonitor.Limit(c.config.maxPacketMsgTotalSize(), atomic.LoadInt64(&c.config.RecvRate), true)
|
||||
|
||||
// Peek into bufConnReader for debugging
|
||||
/*
|
||||
// Peek into bufReader for debugging
|
||||
if numBytes := c.bufReader.Buffered(); numBytes > 0 {
|
||||
log.Info("Peek connection buffer", "numBytes", numBytes, "bytes", log15.Lazy{func() []byte {
|
||||
bytes, err := c.bufReader.Peek(cmn.MinInt(numBytes, 100))
|
||||
if err == nil {
|
||||
return bytes
|
||||
} else {
|
||||
log.Warn("Error peeking connection buffer", "err", err)
|
||||
return nil
|
||||
}
|
||||
}})
|
||||
if numBytes := c.bufConnReader.Buffered(); numBytes > 0 {
|
||||
bz, err := c.bufConnReader.Peek(cmn.MinInt(numBytes, 100))
|
||||
if err == nil {
|
||||
// return
|
||||
} else {
|
||||
c.Logger.Debug("Error peeking connection buffer", "err", err)
|
||||
// return nil
|
||||
}
|
||||
c.Logger.Info("Peek connection buffer", "numBytes", numBytes, "bz", bz)
|
||||
}
|
||||
*/
|
||||
|
||||
// Read packet type
|
||||
var n int
|
||||
var packet Packet
|
||||
var _n int64
|
||||
var err error
|
||||
pktType := wire.ReadByte(c.bufReader, &n, &err)
|
||||
c.recvMonitor.Update(int(n))
|
||||
_n, err = cdc.UnmarshalBinaryReader(c.bufConnReader, &packet, int64(c.config.maxPacketMsgTotalSize()))
|
||||
c.recvMonitor.Update(int(_n))
|
||||
if err != nil {
|
||||
if c.IsRunning() {
|
||||
c.Logger.Error("Connection failed @ recvRoutine (reading byte)", "conn", c, "err", err)
|
||||
@@ -481,8 +489,8 @@ FOR_LOOP:
|
||||
}
|
||||
|
||||
// Read more depending on packet type.
|
||||
switch pktType {
|
||||
case packetTypePing:
|
||||
switch pkt := packet.(type) {
|
||||
case PacketPing:
|
||||
// TODO: prevent abuse, as they cause flush()'s.
|
||||
// https://github.com/tendermint/tendermint/issues/1190
|
||||
c.Logger.Debug("Receive Ping")
|
||||
@@ -491,24 +499,14 @@ FOR_LOOP:
|
||||
default:
|
||||
// never block
|
||||
}
|
||||
case packetTypePong:
|
||||
case PacketPong:
|
||||
c.Logger.Debug("Receive Pong")
|
||||
select {
|
||||
case c.pongTimeoutCh <- false:
|
||||
default:
|
||||
// never block
|
||||
}
|
||||
case packetTypeMsg:
|
||||
pkt, n, err := msgPacket{}, int(0), error(nil)
|
||||
wire.ReadBinaryPtr(&pkt, c.bufReader, c.config.maxMsgPacketTotalSize(), &n, &err)
|
||||
c.recvMonitor.Update(int(n))
|
||||
if err != nil {
|
||||
if c.IsRunning() {
|
||||
c.Logger.Error("Connection failed @ recvRoutine", "conn", c, "err", err)
|
||||
c.stopForError(err)
|
||||
}
|
||||
break FOR_LOOP
|
||||
}
|
||||
case PacketMsg:
|
||||
channel, ok := c.channelsIdx[pkt.ChannelID]
|
||||
if !ok || channel == nil {
|
||||
err := fmt.Errorf("Unknown channel %X", pkt.ChannelID)
|
||||
@@ -517,7 +515,7 @@ FOR_LOOP:
|
||||
break FOR_LOOP
|
||||
}
|
||||
|
||||
msgBytes, err := channel.recvMsgPacket(pkt)
|
||||
msgBytes, err := channel.recvPacketMsg(pkt)
|
||||
if err != nil {
|
||||
if c.IsRunning() {
|
||||
c.Logger.Error("Connection failed @ recvRoutine", "conn", c, "err", err)
|
||||
@@ -531,7 +529,7 @@ FOR_LOOP:
|
||||
c.onReceive(pkt.ChannelID, msgBytes)
|
||||
}
|
||||
default:
|
||||
err := fmt.Errorf("Unknown message type %X", pktType)
|
||||
err := fmt.Errorf("Unknown message type %v", reflect.TypeOf(packet))
|
||||
c.Logger.Error("Connection failed @ recvRoutine", "conn", c, "err", err)
|
||||
c.stopForError(err)
|
||||
break FOR_LOOP
|
||||
@@ -623,7 +621,7 @@ type Channel struct {
|
||||
sending []byte
|
||||
recentlySent int64 // exponential moving average
|
||||
|
||||
maxMsgPacketPayloadSize int
|
||||
maxPacketMsgPayloadSize int
|
||||
|
||||
Logger log.Logger
|
||||
}
|
||||
@@ -638,7 +636,7 @@ func newChannel(conn *MConnection, desc ChannelDescriptor) *Channel {
|
||||
desc: desc,
|
||||
sendQueue: make(chan []byte, desc.SendQueueCapacity),
|
||||
recving: make([]byte, 0, desc.RecvBufferCapacity),
|
||||
maxMsgPacketPayloadSize: conn.config.MaxMsgPacketPayloadSize,
|
||||
maxPacketMsgPayloadSize: conn.config.MaxPacketMsgPayloadSize,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,8 +681,8 @@ func (ch *Channel) canSend() bool {
|
||||
return ch.loadSendQueueSize() < defaultSendQueueCapacity
|
||||
}
|
||||
|
||||
// Returns true if any msgPackets are pending to be sent.
|
||||
// Call before calling nextMsgPacket()
|
||||
// Returns true if any PacketMsgs are pending to be sent.
|
||||
// Call before calling nextPacketMsg()
|
||||
// Goroutine-safe
|
||||
func (ch *Channel) isSendPending() bool {
|
||||
if len(ch.sending) == 0 {
|
||||
@@ -696,12 +694,12 @@ func (ch *Channel) isSendPending() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Creates a new msgPacket to send.
|
||||
// Creates a new PacketMsg to send.
|
||||
// Not goroutine-safe
|
||||
func (ch *Channel) nextMsgPacket() msgPacket {
|
||||
packet := msgPacket{}
|
||||
func (ch *Channel) nextPacketMsg() PacketMsg {
|
||||
packet := PacketMsg{}
|
||||
packet.ChannelID = byte(ch.desc.ID)
|
||||
maxSize := ch.maxMsgPacketPayloadSize
|
||||
maxSize := ch.maxPacketMsgPayloadSize
|
||||
packet.Bytes = ch.sending[:cmn.MinInt(maxSize, len(ch.sending))]
|
||||
if len(ch.sending) <= maxSize {
|
||||
packet.EOF = byte(0x01)
|
||||
@@ -714,30 +712,23 @@ func (ch *Channel) nextMsgPacket() msgPacket {
|
||||
return packet
|
||||
}
|
||||
|
||||
// Writes next msgPacket to w.
|
||||
// Writes next PacketMsg to w and updates c.recentlySent.
|
||||
// Not goroutine-safe
|
||||
func (ch *Channel) writeMsgPacketTo(w io.Writer) (n int, err error) {
|
||||
packet := ch.nextMsgPacket()
|
||||
ch.Logger.Debug("Write Msg Packet", "conn", ch.conn, "packet", packet)
|
||||
writeMsgPacketTo(packet, w, &n, &err)
|
||||
if err == nil {
|
||||
ch.recentlySent += int64(n)
|
||||
}
|
||||
func (ch *Channel) writePacketMsgTo(w io.Writer) (n int64, err error) {
|
||||
var packet = ch.nextPacketMsg()
|
||||
n, err = cdc.MarshalBinaryWriter(w, packet)
|
||||
ch.recentlySent += n
|
||||
return
|
||||
}
|
||||
|
||||
func writeMsgPacketTo(packet msgPacket, w io.Writer, n *int, err *error) {
|
||||
wire.WriteByte(packetTypeMsg, w, n, err)
|
||||
wire.WriteBinary(packet, w, n, err)
|
||||
}
|
||||
|
||||
// Handles incoming msgPackets. It returns a message bytes if message is
|
||||
// complete. NOTE message bytes may change on next call to recvMsgPacket.
|
||||
// Handles incoming PacketMsgs. It returns a message bytes if message is
|
||||
// complete. NOTE message bytes may change on next call to recvPacketMsg.
|
||||
// Not goroutine-safe
|
||||
func (ch *Channel) recvMsgPacket(packet msgPacket) ([]byte, error) {
|
||||
ch.Logger.Debug("Read Msg Packet", "conn", ch.conn, "packet", packet)
|
||||
if ch.desc.RecvMessageCapacity < len(ch.recving)+len(packet.Bytes) {
|
||||
return nil, wire.ErrBinaryReadOverflow
|
||||
func (ch *Channel) recvPacketMsg(packet PacketMsg) ([]byte, error) {
|
||||
ch.Logger.Debug("Read PacketMsg", "conn", ch.conn, "packet", packet)
|
||||
var recvCap, recvReceived = ch.desc.RecvMessageCapacity, len(ch.recving) + len(packet.Bytes)
|
||||
if recvCap < recvReceived {
|
||||
return nil, fmt.Errorf("Received message exceeds available capacity: %v < %v", recvCap, recvReceived)
|
||||
}
|
||||
ch.recving = append(ch.recving, packet.Bytes...)
|
||||
if packet.EOF == byte(0x01) {
|
||||
@@ -761,24 +752,36 @@ func (ch *Channel) updateStats() {
|
||||
ch.recentlySent = int64(float64(ch.recentlySent) * 0.8)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//----------------------------------------
|
||||
// Packet
|
||||
|
||||
const (
|
||||
defaultMaxMsgPacketPayloadSize = 1024
|
||||
type Packet interface {
|
||||
AssertIsPacket()
|
||||
}
|
||||
|
||||
maxMsgPacketOverheadSize = 10 // It's actually lower but good enough
|
||||
packetTypePing = byte(0x01)
|
||||
packetTypePong = byte(0x02)
|
||||
packetTypeMsg = byte(0x03)
|
||||
)
|
||||
func RegisterPacket(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*Packet)(nil), nil)
|
||||
cdc.RegisterConcrete(PacketPing{}, "tendermint/p2p/PacketPing", nil)
|
||||
cdc.RegisterConcrete(PacketPong{}, "tendermint/p2p/PacketPong", nil)
|
||||
cdc.RegisterConcrete(PacketMsg{}, "tendermint/p2p/PacketMsg", nil)
|
||||
}
|
||||
|
||||
// Messages in channels are chopped into smaller msgPackets for multiplexing.
|
||||
type msgPacket struct {
|
||||
func (_ PacketPing) AssertIsPacket() {}
|
||||
func (_ PacketPong) AssertIsPacket() {}
|
||||
func (_ PacketMsg) AssertIsPacket() {}
|
||||
|
||||
type PacketPing struct {
|
||||
}
|
||||
|
||||
type PacketPong struct {
|
||||
}
|
||||
|
||||
type PacketMsg struct {
|
||||
ChannelID byte
|
||||
EOF byte // 1 means message ends here.
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
func (p msgPacket) String() string {
|
||||
return fmt.Sprintf("MsgPacket{%X:%X T:%X}", p.ChannelID, p.Bytes, p.EOF)
|
||||
func (mp PacketMsg) String() string {
|
||||
return fmt.Sprintf("PacketMsg{%X:%X T:%X}", mp.ChannelID, mp.Bytes, mp.EOF)
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
@@ -32,41 +33,37 @@ func createMConnectionWithCallbacks(conn net.Conn, onReceive func(chID byte, msg
|
||||
}
|
||||
|
||||
func TestMConnectionSend(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
server, client := NetPipe()
|
||||
defer server.Close() // nolint: errcheck
|
||||
defer client.Close() // nolint: errcheck
|
||||
|
||||
mconn := createTestMConnection(client)
|
||||
err := mconn.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn.Stop()
|
||||
|
||||
msg := "Ant-Man"
|
||||
assert.True(mconn.Send(0x01, msg))
|
||||
msg := []byte("Ant-Man")
|
||||
assert.True(t, mconn.Send(0x01, msg))
|
||||
// Note: subsequent Send/TrySend calls could pass because we are reading from
|
||||
// the send queue in a separate goroutine.
|
||||
_, err = server.Read(make([]byte, len(msg)))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.True(mconn.CanSend(0x01))
|
||||
assert.True(t, mconn.CanSend(0x01))
|
||||
|
||||
msg = "Spider-Man"
|
||||
assert.True(mconn.TrySend(0x01, msg))
|
||||
msg = []byte("Spider-Man")
|
||||
assert.True(t, mconn.TrySend(0x01, msg))
|
||||
_, err = server.Read(make([]byte, len(msg)))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
assert.False(mconn.CanSend(0x05), "CanSend should return false because channel is unknown")
|
||||
assert.False(mconn.Send(0x05, "Absorbing Man"), "Send should return false because channel is unknown")
|
||||
assert.False(t, mconn.CanSend(0x05), "CanSend should return false because channel is unknown")
|
||||
assert.False(t, mconn.Send(0x05, []byte("Absorbing Man")), "Send should return false because channel is unknown")
|
||||
}
|
||||
|
||||
func TestMConnectionReceive(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
server, client := NetPipe()
|
||||
defer server.Close() // nolint: errcheck
|
||||
defer client.Close() // nolint: errcheck
|
||||
@@ -81,20 +78,20 @@ func TestMConnectionReceive(t *testing.T) {
|
||||
}
|
||||
mconn1 := createMConnectionWithCallbacks(client, onReceive, onError)
|
||||
err := mconn1.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn1.Stop()
|
||||
|
||||
mconn2 := createTestMConnection(server)
|
||||
err = mconn2.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn2.Stop()
|
||||
|
||||
msg := "Cyclops"
|
||||
assert.True(mconn2.Send(0x01, msg))
|
||||
msg := []byte("Cyclops")
|
||||
assert.True(t, mconn2.Send(0x01, msg))
|
||||
|
||||
select {
|
||||
case receivedBytes := <-receivedCh:
|
||||
assert.Equal([]byte(msg), receivedBytes[2:]) // first 3 bytes are internal
|
||||
assert.Equal(t, []byte(msg), receivedBytes)
|
||||
case err := <-errorsCh:
|
||||
t.Fatalf("Expected %s, got %+v", msg, err)
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
@@ -103,20 +100,18 @@ func TestMConnectionReceive(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMConnectionStatus(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
server, client := NetPipe()
|
||||
defer server.Close() // nolint: errcheck
|
||||
defer client.Close() // nolint: errcheck
|
||||
|
||||
mconn := createTestMConnection(client)
|
||||
err := mconn.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn.Stop()
|
||||
|
||||
status := mconn.Status()
|
||||
assert.NotNil(status)
|
||||
assert.Zero(status.Channels[0].SendQueueSize)
|
||||
assert.NotNil(t, status)
|
||||
assert.Zero(t, status.Channels[0].SendQueueSize)
|
||||
}
|
||||
|
||||
func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
|
||||
@@ -140,7 +135,10 @@ func TestMConnectionPongTimeoutResultsInError(t *testing.T) {
|
||||
serverGotPing := make(chan struct{})
|
||||
go func() {
|
||||
// read ping
|
||||
server.Read(make([]byte, 1))
|
||||
var pkt PacketPing
|
||||
const maxPacketPingSize = 1024
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, maxPacketPingSize)
|
||||
assert.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
}()
|
||||
<-serverGotPing
|
||||
@@ -175,21 +173,22 @@ func TestMConnectionMultiplePongsInTheBeginning(t *testing.T) {
|
||||
defer mconn.Stop()
|
||||
|
||||
// sending 3 pongs in a row (abuse)
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
|
||||
serverGotPing := make(chan struct{})
|
||||
go func() {
|
||||
// read ping (one byte)
|
||||
_, err = server.Read(make([]byte, 1))
|
||||
var packet, err = Packet(nil), error(nil)
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &packet, 1024)
|
||||
require.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
// respond with pong
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
}()
|
||||
<-serverGotPing
|
||||
@@ -225,17 +224,18 @@ func TestMConnectionMultiplePings(t *testing.T) {
|
||||
|
||||
// sending 3 pings in a row (abuse)
|
||||
// see https://github.com/tendermint/tendermint/issues/1190
|
||||
_, err = server.Write([]byte{packetTypePing})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Read(make([]byte, 1))
|
||||
var pkt PacketPong
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, 1024)
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write([]byte{packetTypePing})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Read(make([]byte, 1))
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, 1024)
|
||||
require.Nil(t, err)
|
||||
_, err = server.Write([]byte{packetTypePing})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPing{}))
|
||||
require.Nil(t, err)
|
||||
_, err = server.Read(make([]byte, 1))
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, 1024)
|
||||
require.Nil(t, err)
|
||||
|
||||
assert.True(t, mconn.IsRunning())
|
||||
@@ -262,18 +262,21 @@ func TestMConnectionPingPongs(t *testing.T) {
|
||||
serverGotPing := make(chan struct{})
|
||||
go func() {
|
||||
// read ping
|
||||
server.Read(make([]byte, 1))
|
||||
var pkt PacketPing
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, 1024)
|
||||
require.Nil(t, err)
|
||||
serverGotPing <- struct{}{}
|
||||
// respond with pong
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
|
||||
time.Sleep(mconn.config.PingInterval)
|
||||
|
||||
// read ping
|
||||
server.Read(make([]byte, 1))
|
||||
_, err = cdc.UnmarshalBinaryReader(server, &pkt, 1024)
|
||||
require.Nil(t, err)
|
||||
// respond with pong
|
||||
_, err = server.Write([]byte{packetTypePong})
|
||||
_, err = server.Write(cdc.MustMarshalBinary(PacketPong{}))
|
||||
require.Nil(t, err)
|
||||
}()
|
||||
<-serverGotPing
|
||||
@@ -290,8 +293,6 @@ func TestMConnectionPingPongs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMConnectionStopsAndReturnsError(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
server, client := NetPipe()
|
||||
defer server.Close() // nolint: errcheck
|
||||
defer client.Close() // nolint: errcheck
|
||||
@@ -306,7 +307,7 @@ func TestMConnectionStopsAndReturnsError(t *testing.T) {
|
||||
}
|
||||
mconn := createMConnectionWithCallbacks(client, onReceive, onError)
|
||||
err := mconn.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn.Stop()
|
||||
|
||||
if err := client.Close(); err != nil {
|
||||
@@ -317,14 +318,14 @@ func TestMConnectionStopsAndReturnsError(t *testing.T) {
|
||||
case receivedBytes := <-receivedCh:
|
||||
t.Fatalf("Expected error, got %v", receivedBytes)
|
||||
case err := <-errorsCh:
|
||||
assert.NotNil(err)
|
||||
assert.False(mconn.IsRunning())
|
||||
assert.NotNil(t, err)
|
||||
assert.False(t, mconn.IsRunning())
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
t.Fatal("Did not receive error in 500ms")
|
||||
}
|
||||
}
|
||||
|
||||
func newClientAndServerConnsForReadErrors(require *require.Assertions, chOnErr chan struct{}) (*MConnection, *MConnection) {
|
||||
func newClientAndServerConnsForReadErrors(t *testing.T, chOnErr chan struct{}) (*MConnection, *MConnection) {
|
||||
server, client := NetPipe()
|
||||
|
||||
onReceive := func(chID byte, msgBytes []byte) {}
|
||||
@@ -338,7 +339,7 @@ func newClientAndServerConnsForReadErrors(require *require.Assertions, chOnErr c
|
||||
mconnClient := NewMConnection(client, chDescs, onReceive, onError)
|
||||
mconnClient.SetLogger(log.TestingLogger().With("module", "client"))
|
||||
err := mconnClient.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
|
||||
// create server conn with 1 channel
|
||||
// it fires on chOnErr when there's an error
|
||||
@@ -349,7 +350,7 @@ func newClientAndServerConnsForReadErrors(require *require.Assertions, chOnErr c
|
||||
mconnServer := createMConnectionWithCallbacks(server, onReceive, onError)
|
||||
mconnServer.SetLogger(serverLogger)
|
||||
err = mconnServer.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
return mconnClient, mconnServer
|
||||
}
|
||||
|
||||
@@ -364,50 +365,45 @@ func expectSend(ch chan struct{}) bool {
|
||||
}
|
||||
|
||||
func TestMConnectionReadErrorBadEncoding(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
chOnErr := make(chan struct{})
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(require, chOnErr)
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
|
||||
defer mconnClient.Stop()
|
||||
defer mconnServer.Stop()
|
||||
|
||||
client := mconnClient.conn
|
||||
msg := "Ant-Man"
|
||||
|
||||
// send badly encoded msgPacket
|
||||
var n int
|
||||
var err error
|
||||
wire.WriteByte(packetTypeMsg, client, &n, &err)
|
||||
wire.WriteByteSlice([]byte(msg), client, &n, &err)
|
||||
assert.True(expectSend(chOnErr), "badly encoded msgPacket")
|
||||
bz := cdc.MustMarshalBinary(PacketMsg{})
|
||||
bz[4] += 0x01 // Invalid prefix bytes.
|
||||
|
||||
// Write it.
|
||||
_, err := client.Write(bz)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, expectSend(chOnErr), "badly encoded msgPacket")
|
||||
}
|
||||
|
||||
func TestMConnectionReadErrorUnknownChannel(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
chOnErr := make(chan struct{})
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(require, chOnErr)
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
|
||||
defer mconnClient.Stop()
|
||||
defer mconnServer.Stop()
|
||||
|
||||
msg := "Ant-Man"
|
||||
msg := []byte("Ant-Man")
|
||||
|
||||
// fail to send msg on channel unknown by client
|
||||
assert.False(mconnClient.Send(0x03, msg))
|
||||
assert.False(t, mconnClient.Send(0x03, msg))
|
||||
|
||||
// send msg on channel unknown by the server.
|
||||
// should cause an error
|
||||
assert.True(mconnClient.Send(0x02, msg))
|
||||
assert.True(expectSend(chOnErr), "unknown channel")
|
||||
assert.True(t, mconnClient.Send(0x02, msg))
|
||||
assert.True(t, expectSend(chOnErr), "unknown channel")
|
||||
}
|
||||
|
||||
func TestMConnectionReadErrorLongMessage(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
chOnErr := make(chan struct{})
|
||||
chOnRcv := make(chan struct{})
|
||||
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(require, chOnErr)
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
|
||||
defer mconnClient.Stop()
|
||||
defer mconnServer.Stop()
|
||||
|
||||
@@ -418,65 +414,81 @@ func TestMConnectionReadErrorLongMessage(t *testing.T) {
|
||||
client := mconnClient.conn
|
||||
|
||||
// send msg thats just right
|
||||
var n int
|
||||
var err error
|
||||
packet := msgPacket{
|
||||
var buf = new(bytes.Buffer)
|
||||
// - Uvarint length of MustMarshalBinary(packet) = 1 or 2 bytes
|
||||
// (as long as it's less than 16,384 bytes)
|
||||
// - Prefix bytes = 4 bytes
|
||||
// - ChannelID field key + byte = 2 bytes
|
||||
// - EOF field key + byte = 2 bytes
|
||||
// - Bytes field key = 1 bytes
|
||||
// - Uvarint length of MustMarshalBinary(bytes) = 1 or 2 bytes
|
||||
// - Struct terminator = 1 byte
|
||||
// = up to 14 bytes overhead for the packet.
|
||||
var packet = PacketMsg{
|
||||
ChannelID: 0x01,
|
||||
Bytes: make([]byte, mconnClient.config.maxMsgPacketTotalSize()-5),
|
||||
EOF: 1,
|
||||
Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize),
|
||||
}
|
||||
writeMsgPacketTo(packet, client, &n, &err)
|
||||
assert.True(expectSend(chOnRcv), "msg just right")
|
||||
_, err = cdc.MarshalBinaryWriter(buf, packet)
|
||||
assert.Nil(t, err)
|
||||
_, err = client.Write(buf.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, expectSend(chOnRcv), "msg just right")
|
||||
assert.False(t, expectSend(chOnErr), "msg just right")
|
||||
|
||||
// send msg thats too long
|
||||
packet = msgPacket{
|
||||
buf = new(bytes.Buffer)
|
||||
packet = PacketMsg{
|
||||
ChannelID: 0x01,
|
||||
Bytes: make([]byte, mconnClient.config.maxMsgPacketTotalSize()-4),
|
||||
EOF: 1,
|
||||
Bytes: make([]byte, mconnClient.config.MaxPacketMsgPayloadSize+1),
|
||||
}
|
||||
writeMsgPacketTo(packet, client, &n, &err)
|
||||
assert.True(expectSend(chOnErr), "msg too long")
|
||||
_, err = cdc.MarshalBinaryWriter(buf, packet)
|
||||
assert.Nil(t, err)
|
||||
_, err = client.Write(buf.Bytes())
|
||||
assert.NotNil(t, err)
|
||||
assert.False(t, expectSend(chOnRcv), "msg too long")
|
||||
assert.True(t, expectSend(chOnErr), "msg too long")
|
||||
}
|
||||
|
||||
func TestMConnectionReadErrorUnknownMsgType(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
chOnErr := make(chan struct{})
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(require, chOnErr)
|
||||
mconnClient, mconnServer := newClientAndServerConnsForReadErrors(t, chOnErr)
|
||||
defer mconnClient.Stop()
|
||||
defer mconnServer.Stop()
|
||||
|
||||
// send msg with unknown msg type
|
||||
var n int
|
||||
var err error
|
||||
wire.WriteByte(0x04, mconnClient.conn, &n, &err)
|
||||
assert.True(expectSend(chOnErr), "unknown msg type")
|
||||
err := error(nil)
|
||||
err = amino.EncodeUvarint(mconnClient.conn, 4)
|
||||
assert.Nil(t, err)
|
||||
_, err = mconnClient.conn.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF})
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, expectSend(chOnErr), "unknown msg type")
|
||||
}
|
||||
|
||||
func TestMConnectionTrySend(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
server, client := NetPipe()
|
||||
defer server.Close()
|
||||
defer client.Close()
|
||||
|
||||
mconn := createTestMConnection(client)
|
||||
err := mconn.Start()
|
||||
require.Nil(err)
|
||||
require.Nil(t, err)
|
||||
defer mconn.Stop()
|
||||
|
||||
msg := "Semicolon-Woman"
|
||||
msg := []byte("Semicolon-Woman")
|
||||
resultCh := make(chan string, 2)
|
||||
assert.True(mconn.TrySend(0x01, msg))
|
||||
assert.True(t, mconn.TrySend(0x01, msg))
|
||||
server.Read(make([]byte, len(msg)))
|
||||
assert.True(mconn.CanSend(0x01))
|
||||
assert.True(mconn.TrySend(0x01, msg))
|
||||
assert.False(mconn.CanSend(0x01))
|
||||
assert.True(t, mconn.CanSend(0x01))
|
||||
assert.True(t, mconn.TrySend(0x01, msg))
|
||||
assert.False(t, mconn.CanSend(0x01))
|
||||
go func() {
|
||||
mconn.TrySend(0x01, msg)
|
||||
resultCh <- "TrySend"
|
||||
}()
|
||||
assert.False(mconn.CanSend(0x01))
|
||||
assert.False(mconn.TrySend(0x01, msg))
|
||||
assert.Equal("TrySend", <-resultCh)
|
||||
assert.False(t, mconn.CanSend(0x01))
|
||||
assert.False(t, mconn.TrySend(0x01, msg))
|
||||
assert.Equal(t, "TrySend", <-resultCh)
|
||||
}
|
||||
|
@@ -21,16 +21,14 @@ import (
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
// 2 + 1024 == 1026 total frame size
|
||||
const dataLenSize = 2 // uint16 to describe the length, is <= dataMaxSize
|
||||
// 4 + 1024 == 1028 total frame size
|
||||
const dataLenSize = 4
|
||||
const dataMaxSize = 1024
|
||||
const totalFrameSize = dataMaxSize + dataLenSize
|
||||
const sealedFrameSize = totalFrameSize + secretbox.Overhead
|
||||
const authSigMsgSize = (32 + 1) + (64 + 1) // fixed size (length prefixed) byte arrays
|
||||
|
||||
// Implements net.Conn
|
||||
type SecretConnection struct {
|
||||
@@ -123,7 +121,7 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) {
|
||||
data = nil
|
||||
}
|
||||
chunkLength := len(chunk)
|
||||
binary.BigEndian.PutUint16(frame, uint16(chunkLength))
|
||||
binary.BigEndian.PutUint32(frame, uint32(chunkLength))
|
||||
copy(frame[dataLenSize:], chunk)
|
||||
|
||||
// encrypt the frame
|
||||
@@ -146,8 +144,8 @@ func (sc *SecretConnection) Write(data []byte) (n int, err error) {
|
||||
// CONTRACT: data smaller than dataMaxSize is read atomically.
|
||||
func (sc *SecretConnection) Read(data []byte) (n int, err error) {
|
||||
if 0 < len(sc.recvBuffer) {
|
||||
n_ := copy(data, sc.recvBuffer)
|
||||
sc.recvBuffer = sc.recvBuffer[n_:]
|
||||
n = copy(data, sc.recvBuffer)
|
||||
sc.recvBuffer = sc.recvBuffer[n:]
|
||||
return
|
||||
}
|
||||
|
||||
@@ -167,7 +165,7 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) {
|
||||
incr2Nonce(sc.recvNonce)
|
||||
// end decryption
|
||||
|
||||
var chunkLength = binary.BigEndian.Uint16(frame) // read the first two bytes
|
||||
var chunkLength = binary.BigEndian.Uint32(frame) // read the first two bytes
|
||||
if chunkLength > dataMaxSize {
|
||||
return 0, errors.New("chunkLength is greater than dataMaxSize")
|
||||
}
|
||||
@@ -194,32 +192,44 @@ func genEphKeys() (ephPub, ephPriv *[32]byte) {
|
||||
var err error
|
||||
ephPub, ephPriv, err = box.GenerateKey(crand.Reader)
|
||||
if err != nil {
|
||||
cmn.PanicCrisis("Could not generate ephemeral keypairs")
|
||||
panic("Could not generate ephemeral keypairs")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[32]byte, err error) {
|
||||
var err1, err2 error
|
||||
|
||||
cmn.Parallel(
|
||||
func() {
|
||||
_, err1 = conn.Write(locEphPub[:])
|
||||
// Send our pubkey and receive theirs in tandem.
|
||||
var trs, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _, err1 = cdc.MarshalBinaryWriter(conn, locEphPub)
|
||||
if err1 != nil {
|
||||
return nil, err1, true // abort
|
||||
} else {
|
||||
return nil, nil, false
|
||||
}
|
||||
},
|
||||
func() {
|
||||
remEphPub = new([32]byte)
|
||||
_, err2 = io.ReadFull(conn, remEphPub[:])
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _remEphPub [32]byte
|
||||
var _, err2 = cdc.UnmarshalBinaryReader(conn, &_remEphPub, 1024*1024) // TODO
|
||||
if err2 != nil {
|
||||
return nil, err2, true // abort
|
||||
} else {
|
||||
return _remEphPub, nil, false
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
// If error:
|
||||
if trs.FirstError() != nil {
|
||||
err = trs.FirstError()
|
||||
return
|
||||
}
|
||||
|
||||
return remEphPub, nil
|
||||
// Otherwise:
|
||||
var _remEphPub = trs.FirstValue().([32]byte)
|
||||
return &_remEphPub, nil
|
||||
|
||||
}
|
||||
|
||||
func computeSharedSecret(remPubKey, locPrivKey *[32]byte) (shrSecret *[32]byte) {
|
||||
@@ -268,33 +278,37 @@ type authSigMessage struct {
|
||||
Sig crypto.Signature
|
||||
}
|
||||
|
||||
func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature crypto.Signature) (*authSigMessage, error) {
|
||||
var recvMsg authSigMessage
|
||||
var err1, err2 error
|
||||
func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature crypto.Signature) (recvMsg authSigMessage, err error) {
|
||||
|
||||
cmn.Parallel(
|
||||
func() {
|
||||
msgBytes := wire.BinaryBytes(authSigMessage{pubKey.Wrap(), signature.Wrap()})
|
||||
_, err1 = sc.Write(msgBytes)
|
||||
},
|
||||
func() {
|
||||
readBuffer := make([]byte, authSigMsgSize)
|
||||
_, err2 = io.ReadFull(sc, readBuffer)
|
||||
if err2 != nil {
|
||||
return
|
||||
// Send our info and receive theirs in tandem.
|
||||
var trs, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _, err1 = cdc.MarshalBinaryWriter(sc, authSigMessage{pubKey, signature})
|
||||
if err1 != nil {
|
||||
return nil, err1, true // abort
|
||||
} else {
|
||||
return nil, nil, false
|
||||
}
|
||||
n := int(0) // not used.
|
||||
recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), authSigMsgSize, &n, &err2).(authSigMessage)
|
||||
})
|
||||
},
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
var _recvMsg authSigMessage
|
||||
var _, err2 = cdc.UnmarshalBinaryReader(sc, &_recvMsg, 1024*1024) // TODO
|
||||
if err2 != nil {
|
||||
return nil, err2, true // abort
|
||||
} else {
|
||||
return _recvMsg, nil, false
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
// If error:
|
||||
if trs.FirstError() != nil {
|
||||
err = trs.FirstError()
|
||||
return
|
||||
}
|
||||
|
||||
return &recvMsg, nil
|
||||
var _recvMsg = trs.FirstValue().(authSigMessage)
|
||||
return _recvMsg, nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
@@ -1,9 +1,12 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
@@ -30,39 +33,48 @@ func makeKVStoreConnPair() (fooConn, barConn kvstoreConn) {
|
||||
}
|
||||
|
||||
func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection) {
|
||||
fooConn, barConn := makeKVStoreConnPair()
|
||||
fooPrvKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||
fooPubKey := fooPrvKey.PubKey()
|
||||
barPrvKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||
barPubKey := barPrvKey.PubKey()
|
||||
|
||||
cmn.Parallel(
|
||||
func() {
|
||||
var err error
|
||||
var fooConn, barConn = makeKVStoreConnPair()
|
||||
var fooPrvKey = crypto.GenPrivKeyEd25519()
|
||||
var fooPubKey = fooPrvKey.PubKey()
|
||||
var barPrvKey = crypto.GenPrivKeyEd25519()
|
||||
var barPubKey = barPrvKey.PubKey()
|
||||
|
||||
// Make connections from both sides in parallel.
|
||||
var trs, ok = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
fooSecConn, err = MakeSecretConnection(fooConn, fooPrvKey)
|
||||
if err != nil {
|
||||
tb.Errorf("Failed to establish SecretConnection for foo: %v", err)
|
||||
return
|
||||
return nil, err, true
|
||||
}
|
||||
remotePubBytes := fooSecConn.RemotePubKey()
|
||||
if !remotePubBytes.Equals(barPubKey) {
|
||||
tb.Errorf("Unexpected fooSecConn.RemotePubKey. Expected %v, got %v",
|
||||
err = fmt.Errorf("Unexpected fooSecConn.RemotePubKey. Expected %v, got %v",
|
||||
barPubKey, fooSecConn.RemotePubKey())
|
||||
tb.Error(err)
|
||||
return nil, err, false
|
||||
}
|
||||
return nil, nil, false
|
||||
},
|
||||
func() {
|
||||
var err error
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
barSecConn, err = MakeSecretConnection(barConn, barPrvKey)
|
||||
if barSecConn == nil {
|
||||
tb.Errorf("Failed to establish SecretConnection for bar: %v", err)
|
||||
return
|
||||
return nil, err, true
|
||||
}
|
||||
remotePubBytes := barSecConn.RemotePubKey()
|
||||
if !remotePubBytes.Equals(fooPubKey) {
|
||||
tb.Errorf("Unexpected barSecConn.RemotePubKey. Expected %v, got %v",
|
||||
err = fmt.Errorf("Unexpected barSecConn.RemotePubKey. Expected %v, got %v",
|
||||
fooPubKey, barSecConn.RemotePubKey())
|
||||
tb.Error(err)
|
||||
return nil, nil, false
|
||||
}
|
||||
})
|
||||
return nil, nil, false
|
||||
},
|
||||
)
|
||||
require.Nil(tb, trs.FirstError())
|
||||
require.True(tb, ok, "Unexpected task abortion")
|
||||
|
||||
return
|
||||
}
|
||||
@@ -89,59 +101,76 @@ func TestSecretConnectionReadWrite(t *testing.T) {
|
||||
}
|
||||
|
||||
// A helper that will run with (fooConn, fooWrites, fooReads) and vice versa
|
||||
genNodeRunner := func(nodeConn kvstoreConn, nodeWrites []string, nodeReads *[]string) func() {
|
||||
return func() {
|
||||
// Node handskae
|
||||
nodePrvKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||
genNodeRunner := func(id string, nodeConn kvstoreConn, nodeWrites []string, nodeReads *[]string) cmn.Task {
|
||||
return func(_ int) (interface{}, error, bool) {
|
||||
// Initiate cryptographic private key and secret connection trhough nodeConn.
|
||||
nodePrvKey := crypto.GenPrivKeyEd25519()
|
||||
nodeSecretConn, err := MakeSecretConnection(nodeConn, nodePrvKey)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to establish SecretConnection for node: %v", err)
|
||||
return
|
||||
return nil, err, true
|
||||
}
|
||||
// In parallel, handle reads and writes
|
||||
cmn.Parallel(
|
||||
func() {
|
||||
// Node writes
|
||||
// In parallel, handle some reads and writes.
|
||||
var trs, ok = cmn.Parallel(
|
||||
func(_ int) (interface{}, error, bool) {
|
||||
// Node writes:
|
||||
for _, nodeWrite := range nodeWrites {
|
||||
n, err := nodeSecretConn.Write([]byte(nodeWrite))
|
||||
if err != nil {
|
||||
t.Errorf("Failed to write to nodeSecretConn: %v", err)
|
||||
return
|
||||
return nil, err, true
|
||||
}
|
||||
if n != len(nodeWrite) {
|
||||
t.Errorf("Failed to write all bytes. Expected %v, wrote %v", len(nodeWrite), n)
|
||||
return
|
||||
err = fmt.Errorf("Failed to write all bytes. Expected %v, wrote %v", len(nodeWrite), n)
|
||||
t.Error(err)
|
||||
return nil, err, true
|
||||
}
|
||||
}
|
||||
if err := nodeConn.PipeWriter.Close(); err != nil {
|
||||
t.Error(err)
|
||||
return nil, err, true
|
||||
}
|
||||
return nil, nil, false
|
||||
},
|
||||
func() {
|
||||
// Node reads
|
||||
func(_ int) (interface{}, error, bool) {
|
||||
// Node reads:
|
||||
readBuffer := make([]byte, dataMaxSize)
|
||||
for {
|
||||
n, err := nodeSecretConn.Read(readBuffer)
|
||||
if err == io.EOF {
|
||||
return
|
||||
return nil, nil, false
|
||||
} else if err != nil {
|
||||
t.Errorf("Failed to read from nodeSecretConn: %v", err)
|
||||
return
|
||||
return nil, err, true
|
||||
}
|
||||
*nodeReads = append(*nodeReads, string(readBuffer[:n]))
|
||||
}
|
||||
if err := nodeConn.PipeReader.Close(); err != nil {
|
||||
t.Error(err)
|
||||
return nil, err, true
|
||||
}
|
||||
})
|
||||
return nil, nil, false
|
||||
},
|
||||
)
|
||||
assert.True(t, ok, "Unexpected task abortion")
|
||||
|
||||
// If error:
|
||||
if trs.FirstError() != nil {
|
||||
return nil, trs.FirstError(), true
|
||||
}
|
||||
|
||||
// Otherwise:
|
||||
return nil, nil, false
|
||||
}
|
||||
}
|
||||
|
||||
// Run foo & bar in parallel
|
||||
cmn.Parallel(
|
||||
genNodeRunner(fooConn, fooWrites, &fooReads),
|
||||
genNodeRunner(barConn, barWrites, &barReads),
|
||||
var trs, ok = cmn.Parallel(
|
||||
genNodeRunner("foo", fooConn, fooWrites, &fooReads),
|
||||
genNodeRunner("bar", barConn, barWrites, &barReads),
|
||||
)
|
||||
require.Nil(t, trs.FirstError())
|
||||
require.True(t, ok, "unexpected task abortion")
|
||||
|
||||
// A helper to ensure that the writes and reads match.
|
||||
// Additionally, small writes (<= dataMaxSize) must be atomically read.
|
||||
@@ -209,3 +238,12 @@ func BenchmarkSecretConnection(b *testing.B) {
|
||||
}
|
||||
//barSecConn.Close() race condition
|
||||
}
|
||||
|
||||
func fingerprint(bz []byte) []byte {
|
||||
const fbsize = 40
|
||||
if len(bz) < fbsize {
|
||||
return bz
|
||||
} else {
|
||||
return bz[:fbsize]
|
||||
}
|
||||
}
|
||||
|
13
p2p/conn/wire.go
Normal file
13
p2p/conn/wire.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc *amino.Codec = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
crypto.RegisterAmino(cdc)
|
||||
RegisterPacket(cdc)
|
||||
}
|
@@ -3,7 +3,6 @@ package p2p
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
@@ -64,7 +63,7 @@ func loadNodeKey(filePath string) (*NodeKey, error) {
|
||||
return nil, err
|
||||
}
|
||||
nodeKey := new(NodeKey)
|
||||
err = json.Unmarshal(jsonBytes, nodeKey)
|
||||
err = cdc.UnmarshalJSON(jsonBytes, nodeKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading NodeKey from %v: %v\n", filePath, err)
|
||||
}
|
||||
@@ -72,12 +71,12 @@ func loadNodeKey(filePath string) (*NodeKey, error) {
|
||||
}
|
||||
|
||||
func genNodeKey(filePath string) (*NodeKey, error) {
|
||||
privKey := crypto.GenPrivKeyEd25519().Wrap()
|
||||
privKey := crypto.GenPrivKeyEd25519()
|
||||
nodeKey := &NodeKey{
|
||||
PrivKey: privKey,
|
||||
}
|
||||
|
||||
jsonBytes, err := json.Marshal(nodeKey)
|
||||
jsonBytes, err := cdc.MarshalJSON(nodeKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -66,7 +65,7 @@ func NewNetAddressString(addr string) (*NetAddress, error) {
|
||||
idStr := spl[0]
|
||||
idBytes, err := hex.DecodeString(idStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("Address (%s) contains invalid ID", addr))
|
||||
return nil, cmn.ErrorWrap(err, fmt.Sprintf("Address (%s) contains invalid ID", addr))
|
||||
}
|
||||
if len(idBytes) != IDByteLength {
|
||||
return nil, fmt.Errorf("Address (%s) contains ID of invalid length (%d). Should be %d hex-encoded bytes",
|
||||
|
63
p2p/peer.go
63
p2p/peer.go
@@ -5,10 +5,7 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-crypto"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -25,8 +22,8 @@ type Peer interface {
|
||||
NodeInfo() NodeInfo // peer's info
|
||||
Status() tmconn.ConnectionStatus
|
||||
|
||||
Send(byte, interface{}) bool
|
||||
TrySend(byte, interface{}) bool
|
||||
Send(byte, []byte) bool
|
||||
TrySend(byte, []byte) bool
|
||||
|
||||
Set(string, interface{})
|
||||
Get(string) interface{}
|
||||
@@ -114,13 +111,13 @@ func newOutboundPeerConn(addr *NetAddress, config *PeerConfig, persistent bool,
|
||||
|
||||
conn, err := dial(addr, config)
|
||||
if err != nil {
|
||||
return pc, errors.Wrap(err, "Error creating peer")
|
||||
return pc, cmn.ErrorWrap(err, "Error creating peer")
|
||||
}
|
||||
|
||||
pc, err = newPeerConn(conn, config, true, persistent, ourNodePrivKey)
|
||||
if err != nil {
|
||||
if err2 := conn.Close(); err2 != nil {
|
||||
return pc, errors.Wrap(err, err2.Error())
|
||||
return pc, cmn.ErrorWrap(err, err2.Error())
|
||||
}
|
||||
return pc, err
|
||||
}
|
||||
@@ -128,7 +125,7 @@ func newOutboundPeerConn(addr *NetAddress, config *PeerConfig, persistent bool,
|
||||
// ensure dialed ID matches connection ID
|
||||
if config.AuthEnc && addr.ID != pc.ID() {
|
||||
if err2 := conn.Close(); err2 != nil {
|
||||
return pc, errors.Wrap(err, err2.Error())
|
||||
return pc, cmn.ErrorWrap(err, err2.Error())
|
||||
}
|
||||
return pc, ErrSwitchAuthenticationFailure{addr, pc.ID()}
|
||||
}
|
||||
@@ -157,13 +154,13 @@ func newPeerConn(rawConn net.Conn,
|
||||
if config.AuthEnc {
|
||||
// Set deadline for secret handshake
|
||||
if err := conn.SetDeadline(time.Now().Add(config.HandshakeTimeout * time.Second)); err != nil {
|
||||
return pc, errors.Wrap(err, "Error setting deadline while encrypting connection")
|
||||
return pc, cmn.ErrorWrap(err, "Error setting deadline while encrypting connection")
|
||||
}
|
||||
|
||||
// Encrypt connection
|
||||
conn, err = tmconn.MakeSecretConnection(conn, ourNodePrivKey)
|
||||
if err != nil {
|
||||
return pc, errors.Wrap(err, "Error creating peer")
|
||||
return pc, cmn.ErrorWrap(err, "Error creating peer")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,9 +225,9 @@ func (p *peer) Status() tmconn.ConnectionStatus {
|
||||
return p.mconn.Status()
|
||||
}
|
||||
|
||||
// Send msg to the channel identified by chID byte. Returns false if the send
|
||||
// queue is full after timeout, specified by MConnection.
|
||||
func (p *peer) Send(chID byte, msg interface{}) bool {
|
||||
// Send msg bytes to the channel identified by chID byte. Returns false if the
|
||||
// send queue is full after timeout, specified by MConnection.
|
||||
func (p *peer) Send(chID byte, msgBytes []byte) bool {
|
||||
if !p.IsRunning() {
|
||||
// see Switch#Broadcast, where we fetch the list of peers and loop over
|
||||
// them - while we're looping, one peer may be removed and stopped.
|
||||
@@ -238,18 +235,18 @@ func (p *peer) Send(chID byte, msg interface{}) bool {
|
||||
} else if !p.hasChannel(chID) {
|
||||
return false
|
||||
}
|
||||
return p.mconn.Send(chID, msg)
|
||||
return p.mconn.Send(chID, msgBytes)
|
||||
}
|
||||
|
||||
// TrySend msg to the channel identified by chID byte. Immediately returns
|
||||
// TrySend msg bytes to the channel identified by chID byte. Immediately returns
|
||||
// false if the send queue is full.
|
||||
func (p *peer) TrySend(chID byte, msg interface{}) bool {
|
||||
func (p *peer) TrySend(chID byte, msgBytes []byte) bool {
|
||||
if !p.IsRunning() {
|
||||
return false
|
||||
} else if !p.hasChannel(chID) {
|
||||
return false
|
||||
}
|
||||
return p.mconn.TrySend(chID, msg)
|
||||
return p.mconn.TrySend(chID, msgBytes)
|
||||
}
|
||||
|
||||
// Get the data for a given key.
|
||||
@@ -290,30 +287,26 @@ func (pc *peerConn) CloseConn() {
|
||||
func (pc *peerConn) HandshakeTimeout(ourNodeInfo NodeInfo, timeout time.Duration) (peerNodeInfo NodeInfo, err error) {
|
||||
// Set deadline for handshake so we don't block forever on conn.ReadFull
|
||||
if err := pc.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
|
||||
return peerNodeInfo, errors.Wrap(err, "Error setting deadline")
|
||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error setting deadline")
|
||||
}
|
||||
|
||||
var err1 error
|
||||
var err2 error
|
||||
cmn.Parallel(
|
||||
func() {
|
||||
var n int
|
||||
wire.WriteBinary(&ourNodeInfo, pc.conn, &n, &err1)
|
||||
var trs, _ = cmn.Parallel(
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
_, err = cdc.MarshalBinaryWriter(pc.conn, ourNodeInfo)
|
||||
return
|
||||
},
|
||||
func() {
|
||||
var n int
|
||||
wire.ReadBinary(&peerNodeInfo, pc.conn, MaxNodeInfoSize(), &n, &err2)
|
||||
})
|
||||
if err1 != nil {
|
||||
return peerNodeInfo, errors.Wrap(err1, "Error during handshake/write")
|
||||
}
|
||||
if err2 != nil {
|
||||
return peerNodeInfo, errors.Wrap(err2, "Error during handshake/read")
|
||||
func(_ int) (val interface{}, err error, abort bool) {
|
||||
_, err = cdc.UnmarshalBinaryReader(pc.conn, &peerNodeInfo, int64(MaxNodeInfoSize()))
|
||||
return
|
||||
},
|
||||
)
|
||||
if err := trs.FirstError(); err != nil {
|
||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error during handshake")
|
||||
}
|
||||
|
||||
// Remove deadline
|
||||
if err := pc.conn.SetDeadline(time.Time{}); err != nil {
|
||||
return peerNodeInfo, errors.Wrap(err, "Error removing deadline")
|
||||
return peerNodeInfo, cmn.ErrorWrap(err, "Error removing deadline")
|
||||
}
|
||||
|
||||
return peerNodeInfo, nil
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
// Returns an empty kvstore peer
|
||||
func randPeer() *peer {
|
||||
pubKey := crypto.GenPrivKeyEd25519().Wrap().PubKey()
|
||||
pubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||
return &peer{
|
||||
nodeInfo: NodeInfo{
|
||||
ListenAddr: cmn.Fmt("%v.%v.%v.%v:46656", rand.Int()%256, rand.Int()%256, rand.Int()%256, rand.Int()%256),
|
||||
|
@@ -20,7 +20,7 @@ func TestPeerBasic(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
// simulate remote peer
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519().Wrap(), Config: DefaultPeerConfig()}
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()}
|
||||
rp.Start()
|
||||
defer rp.Stop()
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestPeerWithoutAuthEnc(t *testing.T) {
|
||||
config.AuthEnc = false
|
||||
|
||||
// simulate remote peer
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519().Wrap(), Config: config}
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: config}
|
||||
rp.Start()
|
||||
defer rp.Stop()
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestPeerSend(t *testing.T) {
|
||||
config.AuthEnc = false
|
||||
|
||||
// simulate remote peer
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519().Wrap(), Config: config}
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: config}
|
||||
rp.Start()
|
||||
defer rp.Stop()
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestPeerSend(t *testing.T) {
|
||||
defer p.Stop()
|
||||
|
||||
assert.True(p.CanSend(testCh))
|
||||
assert.True(p.Send(testCh, "Asylum"))
|
||||
assert.True(p.Send(testCh, []byte("Asylum")))
|
||||
}
|
||||
|
||||
func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig) (*peer, error) {
|
||||
@@ -89,7 +89,7 @@ func createOutboundPeerAndPerformHandshake(addr *NetAddress, config *PeerConfig)
|
||||
{ID: testCh, Priority: 1},
|
||||
}
|
||||
reactorsByCh := map[byte]Reactor{testCh: NewTestReactor(chDescs, true)}
|
||||
pk := crypto.GenPrivKeyEd25519().Wrap()
|
||||
pk := crypto.GenPrivKeyEd25519()
|
||||
pc, err := newOutboundPeerConn(addr, config, false, pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package pex
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
@@ -9,8 +8,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
@@ -165,7 +163,7 @@ func (r *PEXReactor) RemovePeer(p Peer, reason interface{}) {
|
||||
|
||||
// Receive implements Reactor by handling incoming PEX messages.
|
||||
func (r *PEXReactor) Receive(chID byte, src Peer, msgBytes []byte) {
|
||||
_, msg, err := DecodeMessage(msgBytes)
|
||||
msg, err := DecodeMessage(msgBytes)
|
||||
if err != nil {
|
||||
r.Logger.Error("Error decoding message", "src", src, "chId", chID, "msg", msg, "err", err, "bytes", msgBytes)
|
||||
r.Switch.StopPeerForError(src, err)
|
||||
@@ -235,7 +233,7 @@ func (r *PEXReactor) RequestAddrs(p Peer) {
|
||||
return
|
||||
}
|
||||
r.requestsSent.Set(id, struct{}{})
|
||||
p.Send(PexChannel, struct{ PexMessage }{&pexRequestMessage{}})
|
||||
p.Send(PexChannel, cdc.MustMarshalBinary(&pexRequestMessage{}))
|
||||
}
|
||||
|
||||
// ReceiveAddrs adds the given addrs to the addrbook if theres an open
|
||||
@@ -245,7 +243,7 @@ func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
|
||||
id := string(src.ID())
|
||||
|
||||
if !r.requestsSent.Has(id) {
|
||||
return errors.New("Received unsolicited pexAddrsMessage")
|
||||
return cmn.NewError("Received unsolicited pexAddrsMessage")
|
||||
}
|
||||
|
||||
r.requestsSent.Delete(id)
|
||||
@@ -261,7 +259,7 @@ func (r *PEXReactor) ReceiveAddrs(addrs []*p2p.NetAddress, src Peer) error {
|
||||
|
||||
// SendAddrs sends addrs to the peer.
|
||||
func (r *PEXReactor) SendAddrs(p Peer, netAddrs []*p2p.NetAddress) {
|
||||
p.Send(PexChannel, struct{ PexMessage }{&pexAddrsMessage{Addrs: netAddrs}})
|
||||
p.Send(PexChannel, cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: netAddrs}))
|
||||
}
|
||||
|
||||
// SetEnsurePeersPeriod sets period to ensure peers connected.
|
||||
@@ -583,27 +581,19 @@ func (r *PEXReactor) attemptDisconnects() {
|
||||
//-----------------------------------------------------------------------------
|
||||
// Messages
|
||||
|
||||
const (
|
||||
msgTypeRequest = byte(0x01)
|
||||
msgTypeAddrs = byte(0x02)
|
||||
)
|
||||
|
||||
// PexMessage is a primary type for PEX messages. Underneath, it could contain
|
||||
// either pexRequestMessage, or pexAddrsMessage messages.
|
||||
type PexMessage interface{}
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ PexMessage }{},
|
||||
wire.ConcreteType{&pexRequestMessage{}, msgTypeRequest},
|
||||
wire.ConcreteType{&pexAddrsMessage{}, msgTypeAddrs},
|
||||
)
|
||||
func RegisterPexMessage(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*PexMessage)(nil), nil)
|
||||
cdc.RegisterConcrete(&pexRequestMessage{}, "tendermint/p2p/PexRequestMessage", nil)
|
||||
cdc.RegisterConcrete(&pexAddrsMessage{}, "tendermint/p2p/PexAddrsMessage", nil)
|
||||
}
|
||||
|
||||
// DecodeMessage implements interface registered above.
|
||||
func DecodeMessage(bz []byte) (msgType byte, msg PexMessage, err error) {
|
||||
msgType = bz[0]
|
||||
n := new(int)
|
||||
r := bytes.NewReader(bz)
|
||||
msg = wire.ReadBinary(struct{ PexMessage }{}, r, maxPexMessageSize, n, &err).(struct{ PexMessage }).PexMessage
|
||||
func DecodeMessage(bz []byte) (msg PexMessage, err error) {
|
||||
err = cdc.UnmarshalBinary(bz, &msg)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/p2p/conn"
|
||||
@@ -114,12 +113,12 @@ func TestPEXReactorReceive(t *testing.T) {
|
||||
|
||||
size := book.Size()
|
||||
addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
|
||||
msg := wire.BinaryBytes(struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}})
|
||||
msg := cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: addrs})
|
||||
r.Receive(PexChannel, peer, msg)
|
||||
assert.Equal(t, size+1, book.Size())
|
||||
|
||||
msg = wire.BinaryBytes(struct{ PexMessage }{&pexRequestMessage{}})
|
||||
r.Receive(PexChannel, peer, msg)
|
||||
msg = cdc.MustMarshalBinary(&pexRequestMessage{})
|
||||
r.Receive(PexChannel, peer, msg) // should not panic.
|
||||
}
|
||||
|
||||
func TestPEXReactorRequestMessageAbuse(t *testing.T) {
|
||||
@@ -133,7 +132,7 @@ func TestPEXReactorRequestMessageAbuse(t *testing.T) {
|
||||
assert.True(t, sw.Peers().Has(peer.ID()))
|
||||
|
||||
id := string(peer.ID())
|
||||
msg := wire.BinaryBytes(struct{ PexMessage }{&pexRequestMessage{}})
|
||||
msg := cdc.MustMarshalBinary(&pexRequestMessage{})
|
||||
|
||||
// first time creates the entry
|
||||
r.Receive(PexChannel, peer, msg)
|
||||
@@ -169,7 +168,7 @@ func TestPEXReactorAddrsMessageAbuse(t *testing.T) {
|
||||
assert.True(t, sw.Peers().Has(peer.ID()))
|
||||
|
||||
addrs := []*p2p.NetAddress{peer.NodeInfo().NetAddress()}
|
||||
msg := wire.BinaryBytes(struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}})
|
||||
msg := cdc.MustMarshalBinary(&pexAddrsMessage{Addrs: addrs})
|
||||
|
||||
// receive some addrs. should clear the request
|
||||
r.Receive(PexChannel, peer, msg)
|
||||
@@ -239,7 +238,7 @@ func TestPEXReactorUsesSeedsIfNeeded(t *testing.T) {
|
||||
defer peer.Stop()
|
||||
|
||||
// 3. check that the peer connects to seed immediately
|
||||
assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 1*time.Second, 1)
|
||||
assertPeersWithTimeout(t, []*p2p.Switch{peer}, 10*time.Millisecond, 3*time.Second, 1)
|
||||
}
|
||||
|
||||
func TestPEXReactorCrawlStatus(t *testing.T) {
|
||||
@@ -302,7 +301,7 @@ func newMockPeer() mockPeer {
|
||||
_, netAddr := p2p.CreateRoutableAddr()
|
||||
mp := mockPeer{
|
||||
addr: netAddr,
|
||||
pubKey: crypto.GenPrivKeyEd25519().Wrap().PubKey(),
|
||||
pubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
||||
}
|
||||
mp.BaseService = cmn.NewBaseService(nil, "MockPeer", mp)
|
||||
mp.Start()
|
||||
@@ -318,11 +317,11 @@ func (mp mockPeer) NodeInfo() p2p.NodeInfo {
|
||||
ListenAddr: mp.addr.DialString(),
|
||||
}
|
||||
}
|
||||
func (mp mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
|
||||
func (mp mockPeer) Send(byte, interface{}) bool { return false }
|
||||
func (mp mockPeer) TrySend(byte, interface{}) bool { return false }
|
||||
func (mp mockPeer) Set(string, interface{}) {}
|
||||
func (mp mockPeer) Get(string) interface{} { return nil }
|
||||
func (mp mockPeer) Status() conn.ConnectionStatus { return conn.ConnectionStatus{} }
|
||||
func (mp mockPeer) Send(byte, []byte) bool { return false }
|
||||
func (mp mockPeer) TrySend(byte, []byte) bool { return false }
|
||||
func (mp mockPeer) Set(string, interface{}) {}
|
||||
func (mp mockPeer) Get(string) interface{} { return nil }
|
||||
|
||||
func assertPeersWithTimeout(
|
||||
t *testing.T,
|
||||
|
11
p2p/pex/wire.go
Normal file
11
p2p/pex/wire.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package pex
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc *amino.Codec = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
RegisterPexMessage(cdc)
|
||||
}
|
@@ -8,8 +8,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/p2p/conn"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
@@ -85,7 +83,7 @@ func NewSwitch(config *cfg.P2PConfig) *Switch {
|
||||
sw.peerConfig.MConfig.FlushThrottle = time.Duration(config.FlushThrottleTimeout) * time.Millisecond
|
||||
sw.peerConfig.MConfig.SendRate = config.SendRate
|
||||
sw.peerConfig.MConfig.RecvRate = config.RecvRate
|
||||
sw.peerConfig.MConfig.MaxMsgPacketPayloadSize = config.MaxMsgPacketPayloadSize
|
||||
sw.peerConfig.MConfig.MaxPacketMsgPayloadSize = config.MaxPacketMsgPayloadSize
|
||||
sw.peerConfig.AuthEnc = config.AuthEnc
|
||||
|
||||
sw.BaseService = *cmn.NewBaseService(nil, "P2P Switch", sw)
|
||||
@@ -171,7 +169,7 @@ func (sw *Switch) OnStart() error {
|
||||
for _, reactor := range sw.reactors {
|
||||
err := reactor.Start()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to start %v", reactor)
|
||||
return cmn.ErrorWrap(err, "failed to start %v", reactor)
|
||||
}
|
||||
}
|
||||
// Start listeners
|
||||
@@ -206,18 +204,18 @@ func (sw *Switch) OnStop() {
|
||||
// Broadcast runs a go routine for each attempted send, which will block trying
|
||||
// to send for defaultSendTimeoutSeconds. Returns a channel which receives
|
||||
// success values for each attempted send (false if times out). Channel will be
|
||||
// closed once msg send to all peers.
|
||||
// closed once msg bytes are sent to all peers (or time out).
|
||||
//
|
||||
// NOTE: Broadcast uses goroutines, so order of broadcast may not be preserved.
|
||||
func (sw *Switch) Broadcast(chID byte, msg interface{}) chan bool {
|
||||
func (sw *Switch) Broadcast(chID byte, msgBytes []byte) chan bool {
|
||||
successChan := make(chan bool, len(sw.peers.List()))
|
||||
sw.Logger.Debug("Broadcast", "channel", chID, "msg", msg)
|
||||
sw.Logger.Debug("Broadcast", "channel", chID, "msgBytes", fmt.Sprintf("%X", msgBytes))
|
||||
var wg sync.WaitGroup
|
||||
for _, peer := range sw.peers.List() {
|
||||
wg.Add(1)
|
||||
go func(peer Peer) {
|
||||
defer wg.Done()
|
||||
success := peer.Send(chID, msg)
|
||||
success := peer.Send(chID, msgBytes)
|
||||
successChan <- success
|
||||
}(peer)
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
@@ -125,9 +124,9 @@ func TestSwitches(t *testing.T) {
|
||||
}
|
||||
|
||||
// Lets send some messages
|
||||
ch0Msg := "channel zero"
|
||||
ch1Msg := "channel foo"
|
||||
ch2Msg := "channel bar"
|
||||
ch0Msg := []byte("channel zero")
|
||||
ch1Msg := []byte("channel foo")
|
||||
ch2Msg := []byte("channel bar")
|
||||
|
||||
s1.Broadcast(byte(0x00), ch0Msg)
|
||||
s1.Broadcast(byte(0x01), ch1Msg)
|
||||
@@ -138,15 +137,15 @@ func TestSwitches(t *testing.T) {
|
||||
assertMsgReceivedWithTimeout(t, ch2Msg, byte(0x02), s2.Reactor("bar").(*TestReactor), 10*time.Millisecond, 5*time.Second)
|
||||
}
|
||||
|
||||
func assertMsgReceivedWithTimeout(t *testing.T, msg string, channel byte, reactor *TestReactor, checkPeriod, timeout time.Duration) {
|
||||
func assertMsgReceivedWithTimeout(t *testing.T, msgBytes []byte, channel byte, reactor *TestReactor, checkPeriod, timeout time.Duration) {
|
||||
ticker := time.NewTicker(checkPeriod)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
msgs := reactor.getMsgs(channel)
|
||||
if len(msgs) > 0 {
|
||||
if !bytes.Equal(msgs[0].Bytes, wire.BinaryBytes(msg)) {
|
||||
t.Fatalf("Unexpected message bytes. Wanted: %X, Got: %X", wire.BinaryBytes(msg), msgs[0].Bytes)
|
||||
if !bytes.Equal(msgs[0].Bytes, msgBytes) {
|
||||
t.Fatalf("Unexpected message bytes. Wanted: %X, Got: %X", msgBytes, msgs[0].Bytes)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -238,7 +237,7 @@ func TestSwitchStopsNonPersistentPeerOnError(t *testing.T) {
|
||||
defer sw.Stop()
|
||||
|
||||
// simulate remote peer
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519().Wrap(), Config: DefaultPeerConfig()}
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()}
|
||||
rp.Start()
|
||||
defer rp.Stop()
|
||||
|
||||
@@ -268,7 +267,7 @@ func TestSwitchReconnectsToPersistentPeer(t *testing.T) {
|
||||
defer sw.Stop()
|
||||
|
||||
// simulate remote peer
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519().Wrap(), Config: DefaultPeerConfig()}
|
||||
rp := &remotePeer{PrivKey: crypto.GenPrivKeyEd25519(), Config: DefaultPeerConfig()}
|
||||
rp.Start()
|
||||
defer rp.Stop()
|
||||
|
||||
@@ -338,7 +337,7 @@ func BenchmarkSwitchBroadcast(b *testing.B) {
|
||||
// Send random message from foo channel to another
|
||||
for i := 0; i < b.N; i++ {
|
||||
chID := byte(i % 4)
|
||||
successChan := s1.Broadcast(chID, "test data")
|
||||
successChan := s1.Broadcast(chID, []byte("test data"))
|
||||
for s := range successChan {
|
||||
if s {
|
||||
numSuccess++
|
||||
|
@@ -24,7 +24,7 @@ func CreateRandomPeer(outbound bool) *peer {
|
||||
},
|
||||
nodeInfo: NodeInfo{
|
||||
ListenAddr: netAddr.DialString(),
|
||||
PubKey: crypto.GenPrivKeyEd25519().Wrap().PubKey(),
|
||||
PubKey: crypto.GenPrivKeyEd25519().PubKey(),
|
||||
},
|
||||
mconn: &conn.MConnection{},
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func MakeSwitch(cfg *cfg.P2PConfig, i int, network, version string, initSwitch f
|
||||
// new switch, add reactors
|
||||
// TODO: let the config be passed in?
|
||||
nodeKey := &NodeKey{
|
||||
PrivKey: crypto.GenPrivKeyEd25519().Wrap(),
|
||||
PrivKey: crypto.GenPrivKeyEd25519(),
|
||||
}
|
||||
sw := NewSwitch(cfg)
|
||||
sw.SetLogger(log.TestingLogger())
|
||||
|
@@ -5,8 +5,6 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
@@ -19,26 +17,26 @@ type UPNPCapabilities struct {
|
||||
func makeUPNPListener(intPort int, extPort int, logger log.Logger) (NAT, net.Listener, net.IP, error) {
|
||||
nat, err := Discover()
|
||||
if err != nil {
|
||||
return nil, nil, nil, errors.Errorf("NAT upnp could not be discovered: %v", err)
|
||||
return nil, nil, nil, fmt.Errorf("NAT upnp could not be discovered: %v", err)
|
||||
}
|
||||
logger.Info(cmn.Fmt("ourIP: %v", nat.(*upnpNAT).ourIP))
|
||||
|
||||
ext, err := nat.GetExternalAddress()
|
||||
if err != nil {
|
||||
return nat, nil, nil, errors.Errorf("External address error: %v", err)
|
||||
return nat, nil, nil, fmt.Errorf("External address error: %v", err)
|
||||
}
|
||||
logger.Info(cmn.Fmt("External address: %v", ext))
|
||||
|
||||
port, err := nat.AddPortMapping("tcp", extPort, intPort, "Tendermint UPnP Probe", 0)
|
||||
if err != nil {
|
||||
return nat, nil, ext, errors.Errorf("Port mapping error: %v", err)
|
||||
return nat, nil, ext, fmt.Errorf("Port mapping error: %v", err)
|
||||
}
|
||||
logger.Info(cmn.Fmt("Port mapping mapped: %v", port))
|
||||
|
||||
// also run the listener, open for all remote addresses.
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%v", intPort))
|
||||
if err != nil {
|
||||
return nat, nil, ext, errors.Errorf("Error establishing listener: %v", err)
|
||||
return nat, nil, ext, fmt.Errorf("Error establishing listener: %v", err)
|
||||
}
|
||||
return nat, listener, ext, nil
|
||||
}
|
||||
|
12
p2p/wire.go
Normal file
12
p2p/wire.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package p2p
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -1,16 +1,16 @@
|
||||
package client_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
"github.com/tendermint/tendermint/rpc/client"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
var waitForEventTimeout = 5 * time.Second
|
||||
@@ -23,116 +23,127 @@ func MakeTxKV() ([]byte, []byte, []byte) {
|
||||
}
|
||||
|
||||
func TestHeaderEvents(t *testing.T) {
|
||||
require := require.New(t)
|
||||
for i, c := range GetClients() {
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
i, c := i, c // capture params
|
||||
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
|
||||
evtTyp := types.EventNewBlockHeader
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
_, ok := evt.Unwrap().(types.EventDataNewBlockHeader)
|
||||
require.True(ok, "%d: %#v", i, evt)
|
||||
// TODO: more checks...
|
||||
evtTyp := types.EventNewBlockHeader
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
_, ok := evt.(types.EventDataNewBlockHeader)
|
||||
require.True(t, ok, "%d: %#v", i, evt)
|
||||
// TODO: more checks...
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockEvents(t *testing.T) {
|
||||
require := require.New(t)
|
||||
for i, c := range GetClients() {
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
i, c := i, c // capture params
|
||||
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
|
||||
|
||||
// listen for a new block; ensure height increases by 1
|
||||
var firstBlockHeight int64
|
||||
for j := 0; j < 3; j++ {
|
||||
evtTyp := types.EventNewBlock
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(err, "%d: %+v", j, err)
|
||||
blockEvent, ok := evt.Unwrap().(types.EventDataNewBlock)
|
||||
require.True(ok, "%d: %#v", j, evt)
|
||||
|
||||
block := blockEvent.Block
|
||||
if j == 0 {
|
||||
firstBlockHeight = block.Header.Height
|
||||
continue
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
|
||||
require.Equal(block.Header.Height, firstBlockHeight+int64(j))
|
||||
}
|
||||
// listen for a new block; ensure height increases by 1
|
||||
var firstBlockHeight int64
|
||||
for j := 0; j < 3; j++ {
|
||||
evtTyp := types.EventNewBlock
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(t, err, "%d: %+v", j, err)
|
||||
blockEvent, ok := evt.(types.EventDataNewBlock)
|
||||
require.True(t, ok, "%d: %#v", j, evt)
|
||||
|
||||
block := blockEvent.Block
|
||||
if j == 0 {
|
||||
firstBlockHeight = block.Header.Height
|
||||
continue
|
||||
}
|
||||
|
||||
require.Equal(t, block.Header.Height, firstBlockHeight+int64(j))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxEventsSentWithBroadcastTxAsync(t *testing.T) {
|
||||
require := require.New(t)
|
||||
for i, c := range GetClients() {
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
i, c := i, c // capture params
|
||||
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
|
||||
|
||||
// make the tx
|
||||
_, _, tx := MakeTxKV()
|
||||
evtTyp := types.EventTx
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
|
||||
// send async
|
||||
txres, err := c.BroadcastTxAsync(tx)
|
||||
require.Nil(err, "%+v", err)
|
||||
require.Equal(txres.Code, abci.CodeTypeOK) // FIXME
|
||||
// make the tx
|
||||
_, _, tx := MakeTxKV()
|
||||
evtTyp := types.EventTx
|
||||
|
||||
// and wait for confirmation
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
// and make sure it has the proper info
|
||||
txe, ok := evt.Unwrap().(types.EventDataTx)
|
||||
require.True(ok, "%d: %#v", i, evt)
|
||||
// make sure this is the proper tx
|
||||
require.EqualValues(tx, txe.Tx)
|
||||
require.True(txe.Result.IsOK())
|
||||
// send async
|
||||
txres, err := c.BroadcastTxAsync(tx)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
require.Equal(t, txres.Code, abci.CodeTypeOK) // FIXME
|
||||
|
||||
// and wait for confirmation
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
// and make sure it has the proper info
|
||||
txe, ok := evt.(types.EventDataTx)
|
||||
require.True(t, ok, "%d: %#v", i, evt)
|
||||
// make sure this is the proper tx
|
||||
require.EqualValues(t, tx, txe.Tx)
|
||||
require.True(t, txe.Result.IsOK())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxEventsSentWithBroadcastTxSync(t *testing.T) {
|
||||
require := require.New(t)
|
||||
for i, c := range GetClients() {
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
i, c := i, c // capture params
|
||||
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
|
||||
|
||||
// make the tx
|
||||
_, _, tx := MakeTxKV()
|
||||
evtTyp := types.EventTx
|
||||
// start for this test it if it wasn't already running
|
||||
if !c.IsRunning() {
|
||||
// if so, then we start it, listen, and stop it.
|
||||
err := c.Start()
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
defer c.Stop()
|
||||
}
|
||||
|
||||
// send sync
|
||||
txres, err := c.BroadcastTxSync(tx)
|
||||
require.Nil(err, "%+v", err)
|
||||
require.Equal(txres.Code, abci.CodeTypeOK) // FIXME
|
||||
// make the tx
|
||||
_, _, tx := MakeTxKV()
|
||||
evtTyp := types.EventTx
|
||||
|
||||
// and wait for confirmation
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
// and make sure it has the proper info
|
||||
txe, ok := evt.Unwrap().(types.EventDataTx)
|
||||
require.True(ok, "%d: %#v", i, evt)
|
||||
// make sure this is the proper tx
|
||||
require.EqualValues(tx, txe.Tx)
|
||||
require.True(txe.Result.IsOK())
|
||||
// send sync
|
||||
txres, err := c.BroadcastTxSync(tx)
|
||||
require.Nil(t, err, "%+v", err)
|
||||
require.Equal(t, txres.Code, abci.CodeTypeOK) // FIXME
|
||||
|
||||
// and wait for confirmation
|
||||
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
|
||||
require.Nil(t, err, "%d: %+v", i, err)
|
||||
// and make sure it has the proper info
|
||||
txe, ok := evt.(types.EventDataTx)
|
||||
require.True(t, ok, "%d: %#v", i, evt)
|
||||
// make sure this is the proper tx
|
||||
require.EqualValues(t, tx, txe.Tx)
|
||||
require.True(t, txe.Result.IsOK())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -65,7 +65,7 @@ func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (type
|
||||
query := types.QueryForEvent(evtTyp)
|
||||
err := c.Subscribe(ctx, subscriber, query, evts)
|
||||
if err != nil {
|
||||
return types.TMEventData{}, errors.Wrap(err, "failed to subscribe")
|
||||
return nil, errors.Wrap(err, "failed to subscribe")
|
||||
}
|
||||
|
||||
// make sure to unregister after the test is over
|
||||
@@ -75,6 +75,6 @@ func WaitForOneEvent(c EventsClient, evtTyp string, timeout time.Duration) (type
|
||||
case evt := <-evts:
|
||||
return evt.(types.TMEventData), nil
|
||||
case <-ctx.Done():
|
||||
return types.TMEventData{}, errors.New("timed out waiting for event")
|
||||
return nil, errors.New("timed out waiting for event")
|
||||
}
|
||||
}
|
||||
|
@@ -2,11 +2,11 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
@@ -32,10 +32,14 @@ type HTTP struct {
|
||||
// New takes a remote endpoint in the form tcp://<host>:<port>
|
||||
// and the websocket path (which always seems to be "/websocket")
|
||||
func NewHTTP(remote, wsEndpoint string) *HTTP {
|
||||
rc := rpcclient.NewJSONRPCClient(remote)
|
||||
cdc := rc.Codec()
|
||||
ctypes.RegisterAmino(cdc)
|
||||
|
||||
return &HTTP{
|
||||
rpc: rpcclient.NewJSONRPCClient(remote),
|
||||
rpc: rc,
|
||||
remote: remote,
|
||||
WSEvents: newWSEvents(remote, wsEndpoint),
|
||||
WSEvents: newWSEvents(cdc, remote, wsEndpoint),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +212,7 @@ func (c *HTTP) Validators(height *int64) (*ctypes.ResultValidators, error) {
|
||||
|
||||
type WSEvents struct {
|
||||
cmn.BaseService
|
||||
cdc *amino.Codec
|
||||
remote string
|
||||
endpoint string
|
||||
ws *rpcclient.WSClient
|
||||
@@ -216,8 +221,9 @@ type WSEvents struct {
|
||||
subscriptions map[string]chan<- interface{}
|
||||
}
|
||||
|
||||
func newWSEvents(remote, endpoint string) *WSEvents {
|
||||
func newWSEvents(cdc *amino.Codec, remote, endpoint string) *WSEvents {
|
||||
wsEvents := &WSEvents{
|
||||
cdc: cdc,
|
||||
endpoint: endpoint,
|
||||
remote: remote,
|
||||
subscriptions: make(map[string]chan<- interface{}),
|
||||
@@ -231,6 +237,8 @@ func (w *WSEvents) OnStart() error {
|
||||
w.ws = rpcclient.NewWSClient(w.remote, w.endpoint, rpcclient.OnReconnect(func() {
|
||||
w.redoSubscriptions()
|
||||
}))
|
||||
w.ws.SetCodec(w.cdc)
|
||||
|
||||
err := w.ws.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -326,7 +334,7 @@ func (w *WSEvents) eventListener() {
|
||||
continue
|
||||
}
|
||||
result := new(ctypes.ResultEvent)
|
||||
err := json.Unmarshal(resp.Result, result)
|
||||
err := w.cdc.UnmarshalJSON(resp.Result, result)
|
||||
if err != nil {
|
||||
w.Logger.Error("failed to unmarshal response", "err", err)
|
||||
continue
|
||||
|
@@ -61,7 +61,7 @@ import (
|
||||
//
|
||||
// go func() {
|
||||
// for e := range txs {
|
||||
// fmt.Println("got ", e.(types.TMEventData).Unwrap().(types.EventDataTx))
|
||||
// fmt.Println("got ", e.(types.EventDataTx))
|
||||
// }
|
||||
// }()
|
||||
// ```
|
||||
@@ -104,7 +104,7 @@ func Subscribe(wsCtx rpctypes.WSRPCContext, query string) (*ctypes.ResultSubscri
|
||||
go func() {
|
||||
for event := range ch {
|
||||
tmResult := &ctypes.ResultEvent{query, event.(tmtypes.TMEventData)}
|
||||
wsCtx.TryWriteRPCResponse(rpctypes.NewRPCSuccessResponse(wsCtx.Request.ID+"#event", tmResult))
|
||||
wsCtx.TryWriteRPCResponse(rpctypes.NewRPCSuccessResponse(wsCtx.Codec(), wsCtx.Request.ID+"#event", tmResult))
|
||||
}
|
||||
}()
|
||||
|
||||
|
@@ -189,7 +189,7 @@ func BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
|
||||
timer := time.NewTimer(60 * 2 * time.Second)
|
||||
select {
|
||||
case deliverTxResMsg := <-deliverTxResCh:
|
||||
deliverTxRes := deliverTxResMsg.(types.TMEventData).Unwrap().(types.EventDataTx)
|
||||
deliverTxRes := deliverTxResMsg.(types.EventDataTx)
|
||||
// The tx was included in a block.
|
||||
deliverTxR := deliverTxRes.Result
|
||||
logger.Info("DeliverTx passed ", "tx", cmn.HexBytes(tx), "response", deliverTxR)
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
)
|
||||
|
||||
// TODO: better system than "unsafe" prefix
|
||||
// NOTE: Amino is registered in rpc/core/types/wire.go.
|
||||
var Routes = map[string]*rpc.RPCFunc{
|
||||
// subscribe/unsubscribe are reserved for websocket events.
|
||||
"subscribe": rpc.NewWSRPCFunc(Subscribe, "query"),
|
||||
|
13
rpc/core/types/wire.go
Normal file
13
rpc/core/types/wire.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package core_types
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func RegisterAmino(cdc *amino.Codec) {
|
||||
types.RegisterEventDatas(cdc)
|
||||
types.RegisterEvidences(cdc)
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
type Tx []byte
|
||||
@@ -27,9 +29,11 @@ func TestArgToJSON(t *testing.T) {
|
||||
{Foo{7, "hello"}, `{"Bar":7,"Baz":"hello"}`},
|
||||
}
|
||||
|
||||
cdc := amino.NewCodec()
|
||||
|
||||
for i, tc := range cases {
|
||||
args := map[string]interface{}{"data": tc.input}
|
||||
err := argsToJson(args)
|
||||
err := argsToJSON(cdc, args)
|
||||
require.Nil(err, "%d: %+v", i, err)
|
||||
require.Equal(1, len(args), "%d", i)
|
||||
data, ok := args["data"].(string)
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/go-amino"
|
||||
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
)
|
||||
@@ -19,6 +20,8 @@ import (
|
||||
// HTTPClient is a common interface for JSONRPCClient and URIClient.
|
||||
type HTTPClient interface {
|
||||
Call(method string, params map[string]interface{}, result interface{}) (interface{}, error)
|
||||
Codec() *amino.Codec
|
||||
SetCodec(*amino.Codec)
|
||||
}
|
||||
|
||||
// TODO: Deprecate support for IP:PORT or /path/to/socket
|
||||
@@ -66,6 +69,7 @@ func makeHTTPClient(remoteAddr string) (string, *http.Client) {
|
||||
type JSONRPCClient struct {
|
||||
address string
|
||||
client *http.Client
|
||||
cdc *amino.Codec
|
||||
}
|
||||
|
||||
// NewJSONRPCClient returns a JSONRPCClient pointed at the given address.
|
||||
@@ -74,11 +78,12 @@ func NewJSONRPCClient(remote string) *JSONRPCClient {
|
||||
return &JSONRPCClient{
|
||||
address: address,
|
||||
client: client,
|
||||
cdc: amino.NewCodec(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *JSONRPCClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
|
||||
request, err := types.MapToRequest("jsonrpc-client", method, params)
|
||||
request, err := types.MapToRequest(c.cdc, "jsonrpc-client", method, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -100,7 +105,15 @@ func (c *JSONRPCClient) Call(method string, params map[string]interface{}, resul
|
||||
return nil, err
|
||||
}
|
||||
// log.Info(Fmt("RPC response: %v", string(responseBytes)))
|
||||
return unmarshalResponseBytes(responseBytes, result)
|
||||
return unmarshalResponseBytes(c.cdc, responseBytes, result)
|
||||
}
|
||||
|
||||
func (c *JSONRPCClient) Codec() *amino.Codec {
|
||||
return c.cdc
|
||||
}
|
||||
|
||||
func (c *JSONRPCClient) SetCodec(cdc *amino.Codec) {
|
||||
c.cdc = cdc
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
@@ -109,6 +122,7 @@ func (c *JSONRPCClient) Call(method string, params map[string]interface{}, resul
|
||||
type URIClient struct {
|
||||
address string
|
||||
client *http.Client
|
||||
cdc *amino.Codec
|
||||
}
|
||||
|
||||
func NewURIClient(remote string) *URIClient {
|
||||
@@ -116,11 +130,12 @@ func NewURIClient(remote string) *URIClient {
|
||||
return &URIClient{
|
||||
address: address,
|
||||
client: client,
|
||||
cdc: amino.NewCodec(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *URIClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
|
||||
values, err := argsToURLValues(params)
|
||||
values, err := argsToURLValues(c.cdc, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,15 +150,22 @@ func (c *URIClient) Call(method string, params map[string]interface{}, result in
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return unmarshalResponseBytes(responseBytes, result)
|
||||
return unmarshalResponseBytes(c.cdc, responseBytes, result)
|
||||
}
|
||||
|
||||
func (c *URIClient) Codec() *amino.Codec {
|
||||
return c.cdc
|
||||
}
|
||||
|
||||
func (c *URIClient) SetCodec(cdc *amino.Codec) {
|
||||
c.cdc = cdc
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
|
||||
func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
|
||||
// read response
|
||||
// if rpc/core/types is imported, the result will unmarshal
|
||||
// into the correct type
|
||||
func unmarshalResponseBytes(cdc *amino.Codec, responseBytes []byte, result interface{}) (interface{}, error) {
|
||||
// Read response. If rpc/core/types is imported, the result will unmarshal
|
||||
// into the correct type.
|
||||
// log.Notice("response", "response", string(responseBytes))
|
||||
var err error
|
||||
response := &types.RPCResponse{}
|
||||
@@ -154,20 +176,20 @@ func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface
|
||||
if response.Error != nil {
|
||||
return nil, errors.Errorf("Response error: %v", response.Error)
|
||||
}
|
||||
// unmarshal the RawMessage into the result
|
||||
err = json.Unmarshal(response.Result, result)
|
||||
// Unmarshal the RawMessage into the result.
|
||||
err = cdc.UnmarshalJSON(response.Result, result)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("Error unmarshalling rpc response result: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func argsToURLValues(args map[string]interface{}) (url.Values, error) {
|
||||
func argsToURLValues(cdc *amino.Codec, args map[string]interface{}) (url.Values, error) {
|
||||
values := make(url.Values)
|
||||
if len(args) == 0 {
|
||||
return values, nil
|
||||
}
|
||||
err := argsToJson(args)
|
||||
err := argsToJSON(cdc, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -177,7 +199,7 @@ func argsToURLValues(args map[string]interface{}) (url.Values, error) {
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func argsToJson(args map[string]interface{}) error {
|
||||
func argsToJSON(cdc *amino.Codec, args map[string]interface{}) error {
|
||||
for k, v := range args {
|
||||
rt := reflect.TypeOf(v)
|
||||
isByteSlice := rt.Kind() == reflect.Slice && rt.Elem().Kind() == reflect.Uint8
|
||||
@@ -187,7 +209,7 @@ func argsToJson(args map[string]interface{}) error {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := json.Marshal(v)
|
||||
data, err := cdc.MarshalJSON(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
metrics "github.com/rcrowley/go-metrics"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
@@ -31,6 +32,7 @@ type WSClient struct {
|
||||
cmn.BaseService
|
||||
|
||||
conn *websocket.Conn
|
||||
cdc *amino.Codec
|
||||
|
||||
Address string // IP:PORT or /path/to/socket
|
||||
Endpoint string // /websocket/url/endpoint
|
||||
@@ -77,6 +79,7 @@ type WSClient struct {
|
||||
func NewWSClient(remoteAddr, endpoint string, options ...func(*WSClient)) *WSClient {
|
||||
addr, dialer := makeHTTPDialer(remoteAddr)
|
||||
c := &WSClient{
|
||||
cdc: amino.NewCodec(),
|
||||
Address: addr,
|
||||
Dialer: dialer,
|
||||
Endpoint: endpoint,
|
||||
@@ -206,7 +209,7 @@ func (c *WSClient) Send(ctx context.Context, request types.RPCRequest) error {
|
||||
|
||||
// Call the given method. See Send description.
|
||||
func (c *WSClient) Call(ctx context.Context, method string, params map[string]interface{}) error {
|
||||
request, err := types.MapToRequest("ws-client", method, params)
|
||||
request, err := types.MapToRequest(c.cdc, "ws-client", method, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -216,13 +219,21 @@ func (c *WSClient) Call(ctx context.Context, method string, params map[string]in
|
||||
// CallWithArrayParams the given method with params in a form of array. See
|
||||
// Send description.
|
||||
func (c *WSClient) CallWithArrayParams(ctx context.Context, method string, params []interface{}) error {
|
||||
request, err := types.ArrayToRequest("ws-client", method, params)
|
||||
request, err := types.ArrayToRequest(c.cdc, "ws-client", method, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Send(ctx, request)
|
||||
}
|
||||
|
||||
func (c *WSClient) Codec() *amino.Codec {
|
||||
return c.cdc
|
||||
}
|
||||
|
||||
func (c *WSClient) SetCodec(cdc *amino.Codec) {
|
||||
c.cdc = cdc
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Private methods
|
||||
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -60,6 +61,9 @@ var Routes = map[string]*server.RPCFunc{
|
||||
"echo_int": server.NewRPCFunc(EchoIntResult, "arg"),
|
||||
}
|
||||
|
||||
// Amino codec required to encode/decode everything above.
|
||||
var RoutesCdc = amino.NewCodec()
|
||||
|
||||
func EchoResult(v string) (*ResultEcho, error) {
|
||||
return &ResultEcho{v}, nil
|
||||
}
|
||||
@@ -114,8 +118,8 @@ func setup() {
|
||||
|
||||
tcpLogger := logger.With("socket", "tcp")
|
||||
mux := http.NewServeMux()
|
||||
server.RegisterRPCFuncs(mux, Routes, tcpLogger)
|
||||
wm := server.NewWebsocketManager(Routes, server.ReadWait(5*time.Second), server.PingPeriod(1*time.Second))
|
||||
server.RegisterRPCFuncs(mux, Routes, RoutesCdc, tcpLogger)
|
||||
wm := server.NewWebsocketManager(Routes, RoutesCdc, server.ReadWait(5*time.Second), server.PingPeriod(1*time.Second))
|
||||
wm.SetLogger(tcpLogger)
|
||||
mux.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
|
||||
go func() {
|
||||
@@ -127,8 +131,8 @@ func setup() {
|
||||
|
||||
unixLogger := logger.With("socket", "unix")
|
||||
mux2 := http.NewServeMux()
|
||||
server.RegisterRPCFuncs(mux2, Routes, unixLogger)
|
||||
wm = server.NewWebsocketManager(Routes)
|
||||
server.RegisterRPCFuncs(mux2, Routes, RoutesCdc, unixLogger)
|
||||
wm = server.NewWebsocketManager(Routes, RoutesCdc)
|
||||
wm.SetLogger(unixLogger)
|
||||
mux2.HandleFunc(websocketEndpoint, wm.WebsocketHandler)
|
||||
go func() {
|
||||
|
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -24,14 +25,14 @@ import (
|
||||
|
||||
// RegisterRPCFuncs adds a route for each function in the funcMap, as well as general jsonrpc and websocket handlers for all functions.
|
||||
// "result" is the interface on which the result objects are registered, and is popualted with every RPCResponse
|
||||
func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc, logger log.Logger) {
|
||||
func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc, cdc *amino.Codec, logger log.Logger) {
|
||||
// HTTP endpoints
|
||||
for funcName, rpcFunc := range funcMap {
|
||||
mux.HandleFunc("/"+funcName, makeHTTPHandler(rpcFunc, logger))
|
||||
mux.HandleFunc("/"+funcName, makeHTTPHandler(rpcFunc, cdc, logger))
|
||||
}
|
||||
|
||||
// JSONRPC endpoints
|
||||
mux.HandleFunc("/", makeJSONRPCHandler(funcMap, logger))
|
||||
mux.HandleFunc("/", makeJSONRPCHandler(funcMap, cdc, logger))
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
@@ -98,7 +99,7 @@ func funcReturnTypes(f interface{}) []reflect.Type {
|
||||
// rpc.json
|
||||
|
||||
// jsonrpc calls grab the given method's function info and runs reflect.Call
|
||||
func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.HandlerFunc {
|
||||
func makeJSONRPCHandler(funcMap map[string]*RPCFunc, cdc *amino.Codec, logger log.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@@ -135,7 +136,7 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han
|
||||
}
|
||||
var args []reflect.Value
|
||||
if len(request.Params) > 0 {
|
||||
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||
args, err = jsonParamsToArgsRPC(rpcFunc, cdc, request.Params)
|
||||
if err != nil {
|
||||
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError(request.ID, errors.Wrap(err, "Error converting json params to arguments")))
|
||||
return
|
||||
@@ -148,18 +149,18 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc, logger log.Logger) http.Han
|
||||
WriteRPCResponseHTTP(w, types.RPCInternalError(request.ID, err))
|
||||
return
|
||||
}
|
||||
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(request.ID, result))
|
||||
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(cdc, request.ID, result))
|
||||
}
|
||||
}
|
||||
|
||||
func mapParamsToArgs(rpcFunc *RPCFunc, params map[string]*json.RawMessage, argsOffset int) ([]reflect.Value, error) {
|
||||
func mapParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, params map[string]json.RawMessage, argsOffset int) ([]reflect.Value, error) {
|
||||
values := make([]reflect.Value, len(rpcFunc.argNames))
|
||||
for i, argName := range rpcFunc.argNames {
|
||||
argType := rpcFunc.args[i+argsOffset]
|
||||
|
||||
if p, ok := params[argName]; ok && p != nil && len(*p) > 0 {
|
||||
if p, ok := params[argName]; ok && p != nil && len(p) > 0 {
|
||||
val := reflect.New(argType)
|
||||
err := json.Unmarshal(*p, val.Interface())
|
||||
err := cdc.UnmarshalJSON(p, val.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -172,7 +173,7 @@ func mapParamsToArgs(rpcFunc *RPCFunc, params map[string]*json.RawMessage, argsO
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func arrayParamsToArgs(rpcFunc *RPCFunc, params []*json.RawMessage, argsOffset int) ([]reflect.Value, error) {
|
||||
func arrayParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, params []json.RawMessage, argsOffset int) ([]reflect.Value, error) {
|
||||
if len(rpcFunc.argNames) != len(params) {
|
||||
return nil, errors.Errorf("Expected %v parameters (%v), got %v (%v)",
|
||||
len(rpcFunc.argNames), rpcFunc.argNames, len(params), params)
|
||||
@@ -182,7 +183,7 @@ func arrayParamsToArgs(rpcFunc *RPCFunc, params []*json.RawMessage, argsOffset i
|
||||
for i, p := range params {
|
||||
argType := rpcFunc.args[i+argsOffset]
|
||||
val := reflect.New(argType)
|
||||
err := json.Unmarshal(*p, val.Interface())
|
||||
err := cdc.UnmarshalJSON(p, val.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -191,39 +192,41 @@ func arrayParamsToArgs(rpcFunc *RPCFunc, params []*json.RawMessage, argsOffset i
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// raw is unparsed json (from json.RawMessage) encoding either a map or an array.
|
||||
// `raw` is unparsed json (from json.RawMessage) encoding either a map or an array.
|
||||
// `argsOffset` should be 0 for RPC calls, and 1 for WS requests, where len(rpcFunc.args) != len(rpcFunc.argNames).
|
||||
//
|
||||
// argsOffset should be 0 for RPC calls, and 1 for WS requests, where len(rpcFunc.args) != len(rpcFunc.argNames).
|
||||
// Example:
|
||||
// rpcFunc.args = [rpctypes.WSRPCContext string]
|
||||
// rpcFunc.argNames = ["arg"]
|
||||
func jsonParamsToArgs(rpcFunc *RPCFunc, raw []byte, argsOffset int) ([]reflect.Value, error) {
|
||||
// first, try to get the map..
|
||||
var m map[string]*json.RawMessage
|
||||
func jsonParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, raw []byte, argsOffset int) ([]reflect.Value, error) {
|
||||
|
||||
// TODO: Make more efficient, perhaps by checking the first character for '{' or '['?
|
||||
// First, try to get the map.
|
||||
var m map[string]json.RawMessage
|
||||
err := json.Unmarshal(raw, &m)
|
||||
if err == nil {
|
||||
return mapParamsToArgs(rpcFunc, m, argsOffset)
|
||||
return mapParamsToArgs(rpcFunc, cdc, m, argsOffset)
|
||||
}
|
||||
|
||||
// otherwise, try an array
|
||||
var a []*json.RawMessage
|
||||
// Otherwise, try an array.
|
||||
var a []json.RawMessage
|
||||
err = json.Unmarshal(raw, &a)
|
||||
if err == nil {
|
||||
return arrayParamsToArgs(rpcFunc, a, argsOffset)
|
||||
return arrayParamsToArgs(rpcFunc, cdc, a, argsOffset)
|
||||
}
|
||||
|
||||
// otherwise, bad format, we cannot parse
|
||||
// Otherwise, bad format, we cannot parse
|
||||
return nil, errors.Errorf("Unknown type for JSON params: %v. Expected map or array", err)
|
||||
}
|
||||
|
||||
// Convert a []interface{} OR a map[string]interface{} to properly typed values
|
||||
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, params json.RawMessage) ([]reflect.Value, error) {
|
||||
return jsonParamsToArgs(rpcFunc, params, 0)
|
||||
func jsonParamsToArgsRPC(rpcFunc *RPCFunc, cdc *amino.Codec, params json.RawMessage) ([]reflect.Value, error) {
|
||||
return jsonParamsToArgs(rpcFunc, cdc, params, 0)
|
||||
}
|
||||
|
||||
// Same as above, but with the first param the websocket connection
|
||||
func jsonParamsToArgsWS(rpcFunc *RPCFunc, params json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
|
||||
values, err := jsonParamsToArgs(rpcFunc, params, 1)
|
||||
func jsonParamsToArgsWS(rpcFunc *RPCFunc, cdc *amino.Codec, params json.RawMessage, wsCtx types.WSRPCContext) ([]reflect.Value, error) {
|
||||
values, err := jsonParamsToArgs(rpcFunc, cdc, params, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -235,7 +238,7 @@ func jsonParamsToArgsWS(rpcFunc *RPCFunc, params json.RawMessage, wsCtx types.WS
|
||||
// rpc.http
|
||||
|
||||
// convert from a function name to the http handler
|
||||
func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWriter, *http.Request) {
|
||||
func makeHTTPHandler(rpcFunc *RPCFunc, cdc *amino.Codec, logger log.Logger) func(http.ResponseWriter, *http.Request) {
|
||||
// Exception for websocket endpoints
|
||||
if rpcFunc.ws {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -245,7 +248,7 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit
|
||||
// All other endpoints
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Debug("HTTP HANDLER", "req", r)
|
||||
args, err := httpParamsToArgs(rpcFunc, r)
|
||||
args, err := httpParamsToArgs(rpcFunc, cdc, r)
|
||||
if err != nil {
|
||||
WriteRPCResponseHTTP(w, types.RPCInvalidParamsError("", errors.Wrap(err, "Error converting http params to arguments")))
|
||||
return
|
||||
@@ -257,13 +260,13 @@ func makeHTTPHandler(rpcFunc *RPCFunc, logger log.Logger) func(http.ResponseWrit
|
||||
WriteRPCResponseHTTP(w, types.RPCInternalError("", err))
|
||||
return
|
||||
}
|
||||
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse("", result))
|
||||
WriteRPCResponseHTTP(w, types.NewRPCSuccessResponse(cdc, "", result))
|
||||
}
|
||||
}
|
||||
|
||||
// Covert an http query to a list of properly typed values.
|
||||
// To be properly decoded the arg must be a concrete type from tendermint (if its an interface).
|
||||
func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error) {
|
||||
func httpParamsToArgs(rpcFunc *RPCFunc, cdc *amino.Codec, r *http.Request) ([]reflect.Value, error) {
|
||||
values := make([]reflect.Value, len(rpcFunc.args))
|
||||
|
||||
for i, name := range rpcFunc.argNames {
|
||||
@@ -278,7 +281,7 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error
|
||||
continue
|
||||
}
|
||||
|
||||
v, err, ok := nonJsonToArg(argType, arg)
|
||||
v, err, ok := nonJSONToArg(cdc, argType, arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -287,7 +290,7 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error
|
||||
continue
|
||||
}
|
||||
|
||||
values[i], err = _jsonStringToArg(argType, arg)
|
||||
values[i], err = _jsonStringToArg(cdc, argType, arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -296,9 +299,9 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) {
|
||||
func _jsonStringToArg(cdc *amino.Codec, ty reflect.Type, arg string) (reflect.Value, error) {
|
||||
v := reflect.New(ty)
|
||||
err := json.Unmarshal([]byte(arg), v.Interface())
|
||||
err := cdc.UnmarshalJSON([]byte(arg), v.Interface())
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
@@ -306,7 +309,7 @@ func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func nonJsonToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) {
|
||||
func nonJSONToArg(cdc *amino.Codec, ty reflect.Type, arg string) (reflect.Value, error, bool) {
|
||||
isQuotedString := strings.HasPrefix(arg, `"`) && strings.HasSuffix(arg, `"`)
|
||||
isHexString := strings.HasPrefix(strings.ToLower(arg), "0x")
|
||||
expectingString := ty.Kind() == reflect.String
|
||||
@@ -332,7 +335,7 @@ func nonJsonToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) {
|
||||
|
||||
if isQuotedString && expectingByteSlice {
|
||||
v := reflect.New(reflect.TypeOf(""))
|
||||
err := json.Unmarshal([]byte(arg), v.Interface())
|
||||
err := cdc.UnmarshalJSON([]byte(arg), v.Interface())
|
||||
if err != nil {
|
||||
return reflect.ValueOf(nil), err, false
|
||||
}
|
||||
@@ -354,7 +357,7 @@ const (
|
||||
defaultWSPingPeriod = (defaultWSReadWait * 9) / 10
|
||||
)
|
||||
|
||||
// a single websocket connection contains listener id, underlying ws
|
||||
// A single websocket connection contains listener id, underlying ws
|
||||
// connection, and the event switch for subscribing to events.
|
||||
//
|
||||
// In case of an error, the connection is stopped.
|
||||
@@ -366,6 +369,7 @@ type wsConnection struct {
|
||||
writeChan chan types.RPCResponse
|
||||
|
||||
funcMap map[string]*RPCFunc
|
||||
cdc *amino.Codec
|
||||
|
||||
// write channel capacity
|
||||
writeChanCapacity int
|
||||
@@ -389,11 +393,12 @@ type wsConnection struct {
|
||||
// description of how to configure ping period and pong wait time. NOTE: if the
|
||||
// write buffer is full, pongs may be dropped, which may cause clients to
|
||||
// disconnect. see https://github.com/gorilla/websocket/issues/97
|
||||
func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, options ...func(*wsConnection)) *wsConnection {
|
||||
func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, cdc *amino.Codec, options ...func(*wsConnection)) *wsConnection {
|
||||
wsc := &wsConnection{
|
||||
remoteAddr: baseConn.RemoteAddr().String(),
|
||||
baseConn: baseConn,
|
||||
funcMap: funcMap,
|
||||
cdc: cdc,
|
||||
writeWait: defaultWSWriteWait,
|
||||
writeChanCapacity: defaultWSWriteChanCapacity,
|
||||
readWait: defaultWSReadWait,
|
||||
@@ -503,6 +508,12 @@ func (wsc *wsConnection) TryWriteRPCResponse(resp types.RPCResponse) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Codec returns an amino codec used to decode parameters and encode results.
|
||||
// It implements WSRPCConnection.
|
||||
func (wsc *wsConnection) Codec() *amino.Codec {
|
||||
return wsc.cdc
|
||||
}
|
||||
|
||||
// Read from the socket and subscribe to or unsubscribe from events
|
||||
func (wsc *wsConnection) readRoutine() {
|
||||
defer func() {
|
||||
@@ -569,11 +580,11 @@ func (wsc *wsConnection) readRoutine() {
|
||||
if rpcFunc.ws {
|
||||
wsCtx := types.WSRPCContext{Request: request, WSRPCConnection: wsc}
|
||||
if len(request.Params) > 0 {
|
||||
args, err = jsonParamsToArgsWS(rpcFunc, request.Params, wsCtx)
|
||||
args, err = jsonParamsToArgsWS(rpcFunc, wsc.cdc, request.Params, wsCtx)
|
||||
}
|
||||
} else {
|
||||
if len(request.Params) > 0 {
|
||||
args, err = jsonParamsToArgsRPC(rpcFunc, request.Params)
|
||||
args, err = jsonParamsToArgsRPC(rpcFunc, wsc.cdc, request.Params)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -590,7 +601,7 @@ func (wsc *wsConnection) readRoutine() {
|
||||
wsc.WriteRPCResponse(types.RPCInternalError(request.ID, err))
|
||||
continue
|
||||
} else {
|
||||
wsc.WriteRPCResponse(types.NewRPCSuccessResponse(request.ID, result))
|
||||
wsc.WriteRPCResponse(types.NewRPCSuccessResponse(wsc.cdc, request.ID, result))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -666,6 +677,7 @@ func (wsc *wsConnection) writeMessageWithDeadline(msgType int, msg []byte) error
|
||||
type WebsocketManager struct {
|
||||
websocket.Upgrader
|
||||
funcMap map[string]*RPCFunc
|
||||
cdc *amino.Codec
|
||||
logger log.Logger
|
||||
wsConnOptions []func(*wsConnection)
|
||||
}
|
||||
@@ -673,9 +685,10 @@ type WebsocketManager struct {
|
||||
// NewWebsocketManager returns a new WebsocketManager that routes according to
|
||||
// the given funcMap and connects to the server with the given connection
|
||||
// options.
|
||||
func NewWebsocketManager(funcMap map[string]*RPCFunc, wsConnOptions ...func(*wsConnection)) *WebsocketManager {
|
||||
func NewWebsocketManager(funcMap map[string]*RPCFunc, cdc *amino.Codec, wsConnOptions ...func(*wsConnection)) *WebsocketManager {
|
||||
return &WebsocketManager{
|
||||
funcMap: funcMap,
|
||||
cdc: cdc,
|
||||
Upgrader: websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
// TODO ???
|
||||
@@ -702,7 +715,7 @@ func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
|
||||
// register connection
|
||||
con := NewWSConnection(wsConn, wm.funcMap, wm.wsConnOptions...)
|
||||
con := NewWSConnection(wsConn, wm.funcMap, wm.cdc, wm.wsConnOptions...)
|
||||
con.SetLogger(wm.logger.With("remote", wsConn.RemoteAddr()))
|
||||
wm.logger.Info("New websocket connection", "remote", con.remoteAddr)
|
||||
err = con.Start() // Blocking
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
rs "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
types "github.com/tendermint/tendermint/rpc/lib/types"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -21,10 +22,11 @@ func testMux() *http.ServeMux {
|
||||
funcMap := map[string]*rs.RPCFunc{
|
||||
"c": rs.NewRPCFunc(func(s string, i int) (string, error) { return "foo", nil }, "s,i"),
|
||||
}
|
||||
cdc := amino.NewCodec()
|
||||
mux := http.NewServeMux()
|
||||
buf := new(bytes.Buffer)
|
||||
logger := log.NewTMLogger(buf)
|
||||
rs.RegisterRPCFuncs(mux, funcMap, logger)
|
||||
rs.RegisterRPCFuncs(mux, funcMap, cdc, logger)
|
||||
|
||||
return mux
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -138,6 +139,7 @@ func TestParseRPC(t *testing.T) {
|
||||
|
||||
demo := func(height int, name string) {}
|
||||
call := NewRPCFunc(demo, "height,name")
|
||||
cdc := amino.NewCodec()
|
||||
|
||||
cases := []struct {
|
||||
raw string
|
||||
@@ -158,7 +160,7 @@ func TestParseRPC(t *testing.T) {
|
||||
for idx, tc := range cases {
|
||||
i := strconv.Itoa(idx)
|
||||
data := []byte(tc.raw)
|
||||
vals, err := jsonParamsToArgs(call, data, 0)
|
||||
vals, err := jsonParamsToArgs(call, cdc, data, 0)
|
||||
if tc.fail {
|
||||
assert.NotNil(err, i)
|
||||
} else {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
rpcserver "github.com/tendermint/tendermint/rpc/lib/server"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
@@ -24,8 +25,9 @@ type Result struct {
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
cdc := amino.NewCodec()
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
rpcserver.RegisterRPCFuncs(mux, routes, logger)
|
||||
rpcserver.RegisterRPCFuncs(mux, routes, cdc, logger)
|
||||
_, err := rpcserver.StartHTTPServer("0.0.0.0:8008", mux, logger)
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tendermint/go-amino"
|
||||
tmpubsub "github.com/tendermint/tmlibs/pubsub"
|
||||
)
|
||||
|
||||
@@ -33,8 +34,16 @@ func (req RPCRequest) String() string {
|
||||
return fmt.Sprintf("[%s %s]", req.ID, req.Method)
|
||||
}
|
||||
|
||||
func MapToRequest(id string, method string, params map[string]interface{}) (RPCRequest, error) {
|
||||
payload, err := json.Marshal(params)
|
||||
func MapToRequest(cdc *amino.Codec, id string, method string, params map[string]interface{}) (RPCRequest, error) {
|
||||
var params_ = make(map[string]json.RawMessage, len(params))
|
||||
for name, value := range params {
|
||||
valueJSON, err := cdc.MarshalJSON(value)
|
||||
if err != nil {
|
||||
return RPCRequest{}, err
|
||||
}
|
||||
params_[name] = valueJSON
|
||||
}
|
||||
payload, err := json.Marshal(params_) // NOTE: Amino doesn't handle maps yet.
|
||||
if err != nil {
|
||||
return RPCRequest{}, err
|
||||
}
|
||||
@@ -42,8 +51,16 @@ func MapToRequest(id string, method string, params map[string]interface{}) (RPCR
|
||||
return request, nil
|
||||
}
|
||||
|
||||
func ArrayToRequest(id string, method string, params []interface{}) (RPCRequest, error) {
|
||||
payload, err := json.Marshal(params)
|
||||
func ArrayToRequest(cdc *amino.Codec, id string, method string, params []interface{}) (RPCRequest, error) {
|
||||
var params_ = make([]json.RawMessage, len(params))
|
||||
for i, value := range params {
|
||||
valueJSON, err := cdc.MarshalJSON(value)
|
||||
if err != nil {
|
||||
return RPCRequest{}, err
|
||||
}
|
||||
params_[i] = valueJSON
|
||||
}
|
||||
payload, err := json.Marshal(params_) // NOTE: Amino doesn't handle maps yet.
|
||||
if err != nil {
|
||||
return RPCRequest{}, err
|
||||
}
|
||||
@@ -75,12 +92,12 @@ type RPCResponse struct {
|
||||
Error *RPCError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func NewRPCSuccessResponse(id string, res interface{}) RPCResponse {
|
||||
func NewRPCSuccessResponse(cdc *amino.Codec, id string, res interface{}) RPCResponse {
|
||||
var rawMsg json.RawMessage
|
||||
|
||||
if res != nil {
|
||||
var js []byte
|
||||
js, err := json.Marshal(res)
|
||||
js, err := cdc.MarshalJSON(res)
|
||||
if err != nil {
|
||||
return RPCInternalError(id, errors.Wrap(err, "Error marshalling response"))
|
||||
}
|
||||
@@ -138,6 +155,7 @@ type WSRPCConnection interface {
|
||||
WriteRPCResponse(resp RPCResponse)
|
||||
TryWriteRPCResponse(resp RPCResponse) bool
|
||||
GetEventSubscriber() EventSubscriber
|
||||
Codec() *amino.Codec
|
||||
}
|
||||
|
||||
// EventSubscriber mirros tendermint/tendermint/types.EventBusSubscriber
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
type SampleResult struct {
|
||||
@@ -16,8 +17,9 @@ type SampleResult struct {
|
||||
|
||||
func TestResponses(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
cdc := amino.NewCodec()
|
||||
|
||||
a := NewRPCSuccessResponse("1", &SampleResult{"hello"})
|
||||
a := NewRPCSuccessResponse(cdc, "1", &SampleResult{"hello"})
|
||||
b, _ := json.Marshal(a)
|
||||
s := `{"jsonrpc":"2.0","id":"1","result":{"Value":"hello"}}`
|
||||
assert.Equal(string(s), string(b))
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
core_grpc "github.com/tendermint/tendermint/rpc/grpc"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
)
|
||||
|
||||
var globalConfig *cfg.Config
|
||||
@@ -26,11 +27,15 @@ var globalConfig *cfg.Config
|
||||
func waitForRPC() {
|
||||
laddr := GetConfig().RPC.ListenAddress
|
||||
client := rpcclient.NewJSONRPCClient(laddr)
|
||||
ctypes.RegisterAmino(client.Codec())
|
||||
result := new(ctypes.ResultStatus)
|
||||
for {
|
||||
_, err := client.Call("status", map[string]interface{}{}, result)
|
||||
if err == nil {
|
||||
return
|
||||
} else {
|
||||
fmt.Println("error", err)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,10 +117,10 @@ func NewTendermint(app abci.Application) *nm.Node {
|
||||
config := GetConfig()
|
||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||
logger = log.NewFilter(logger, log.AllowError())
|
||||
privValidatorFile := config.PrivValidatorFile()
|
||||
privValidator := types.LoadOrGenPrivValidatorFS(privValidatorFile)
|
||||
pvFile := config.PrivValidatorFile()
|
||||
pv := pvm.LoadOrGenFilePV(pvFile)
|
||||
papp := proxy.NewLocalClientCreator(app)
|
||||
node, err := nm.NewNode(config, privValidator, papp,
|
||||
node, err := nm.NewNode(config, pv, papp,
|
||||
nm.DefaultGenesisDocProviderFunc(config),
|
||||
nm.DefaultDBProvider, logger)
|
||||
if err != nil {
|
||||
|
@@ -245,7 +245,7 @@ func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
|
||||
// ./lite/doc.go for details on how a light client tracks validators.
|
||||
func updateValidators(currentSet *types.ValidatorSet, updates []abci.Validator) error {
|
||||
for _, v := range updates {
|
||||
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
|
||||
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-amino encoded pubkey
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -66,8 +66,8 @@ func TestBeginBlockAbsentValidators(t *testing.T) {
|
||||
lastCommitPrecommits []*types.Vote
|
||||
expectedAbsentValidators []int32
|
||||
}{
|
||||
{"none absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now}, {ValidatorIndex: 1, Timestamp: now}}, []int32{}},
|
||||
{"one absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now}, nil}, []int32{1}},
|
||||
{"none absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, {ValidatorIndex: 1, Timestamp: now}}, []int32{}},
|
||||
{"one absent", []*types.Vote{{ValidatorIndex: 0, Timestamp: now, Type: types.VoteTypePrecommit}, nil}, []int32{1}},
|
||||
{"multiple absent", []*types.Vote{nil, nil}, []int32{0, 1}},
|
||||
}
|
||||
|
||||
|
@@ -6,8 +6,6 @@ import (
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
@@ -81,16 +79,13 @@ func (s State) Copy() State {
|
||||
|
||||
// Equals returns true if the States are identical.
|
||||
func (s State) Equals(s2 State) bool {
|
||||
return bytes.Equal(s.Bytes(), s2.Bytes())
|
||||
sbz, s2bz := s.Bytes(), s2.Bytes()
|
||||
return bytes.Equal(sbz, s2bz)
|
||||
}
|
||||
|
||||
// Bytes serializes the State using go-wire.
|
||||
// Bytes serializes the State using go-amino.
|
||||
func (s State) Bytes() []byte {
|
||||
bz, err := wire.MarshalBinary(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return cdc.MustMarshalBinaryBare(s)
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the State is equal to the empty State.
|
||||
|
@@ -7,11 +7,8 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/tendermint/go-crypto"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
@@ -42,7 +39,7 @@ func TestStateCopy(t *testing.T) {
|
||||
stateCopy := state.Copy()
|
||||
|
||||
assert.True(state.Equals(stateCopy),
|
||||
cmn.Fmt(`expected state and its copy to be identical. got %v\n expected %v\n`,
|
||||
cmn.Fmt("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n",
|
||||
stateCopy, state))
|
||||
|
||||
stateCopy.LastBlockHeight++
|
||||
@@ -62,7 +59,7 @@ func TestStateSaveLoad(t *testing.T) {
|
||||
|
||||
loadedState := LoadState(stateDB)
|
||||
assert.True(state.Equals(loadedState),
|
||||
cmn.Fmt(`expected state and its copy to be identical. got %v\n expected %v\n`,
|
||||
cmn.Fmt("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n",
|
||||
loadedState, state))
|
||||
}
|
||||
|
||||
@@ -78,8 +75,8 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
||||
// build mock responses
|
||||
block := makeBlock(state, 2)
|
||||
abciResponses := NewABCIResponses(block)
|
||||
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: []cmn.KVPair{}}
|
||||
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: []cmn.KVPair{}}
|
||||
abciResponses.DeliverTx[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Tags: nil}
|
||||
abciResponses.DeliverTx[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Tags: nil}
|
||||
abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{
|
||||
{
|
||||
PubKey: crypto.GenPrivKeyEd25519().PubKey().Bytes(),
|
||||
@@ -88,11 +85,11 @@ func TestABCIResponsesSaveLoad1(t *testing.T) {
|
||||
}}
|
||||
|
||||
saveABCIResponses(stateDB, block.Height, abciResponses)
|
||||
loadedAbciResponses, err := LoadABCIResponses(stateDB, block.Height)
|
||||
loadedABCIResponses, err := LoadABCIResponses(stateDB, block.Height)
|
||||
assert.Nil(err)
|
||||
assert.Equal(abciResponses, loadedAbciResponses,
|
||||
cmn.Fmt(`ABCIResponses don't match: Got %v, Expected %v`, loadedAbciResponses,
|
||||
abciResponses))
|
||||
assert.Equal(abciResponses, loadedABCIResponses,
|
||||
cmn.Fmt("ABCIResponses don't match:\ngot: %v\nexpected: %v\n",
|
||||
loadedABCIResponses, abciResponses))
|
||||
}
|
||||
|
||||
// TestResultsSaveLoad tests saving and loading abci results.
|
||||
@@ -109,8 +106,8 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
||||
expected types.ABCIResults
|
||||
}{
|
||||
0: {
|
||||
[]*abci.ResponseDeliverTx{},
|
||||
types.ABCIResults{},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
1: {
|
||||
[]*abci.ResponseDeliverTx{
|
||||
@@ -129,12 +126,12 @@ func TestABCIResponsesSaveLoad2(t *testing.T) {
|
||||
}},
|
||||
},
|
||||
types.ABCIResults{
|
||||
{383, []byte{}},
|
||||
{383, nil},
|
||||
{0, []byte("Gotcha!")},
|
||||
}},
|
||||
3: {
|
||||
nil,
|
||||
types.ABCIResults{},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -430,7 +427,7 @@ func makeHeaderPartsResponsesValPubKeyChange(state State, height int64,
|
||||
|
||||
block := makeBlock(state, height)
|
||||
abciResponses := &ABCIResponses{
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{}},
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
||||
}
|
||||
|
||||
// if the pubkey is new, remove the old and add the new
|
||||
@@ -452,7 +449,7 @@ func makeHeaderPartsResponsesValPowerChange(state State, height int64,
|
||||
|
||||
block := makeBlock(state, height)
|
||||
abciResponses := &ABCIResponses{
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.Validator{}},
|
||||
EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil},
|
||||
}
|
||||
|
||||
// if the pubkey is new, remove the old and add the new
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
@@ -69,7 +68,7 @@ func loadState(db dbm.DB, key []byte) (state State) {
|
||||
return state
|
||||
}
|
||||
|
||||
err := wire.UnmarshalBinary(buf, &state)
|
||||
err := cdc.UnmarshalBinaryBare(buf, &state)
|
||||
if err != nil {
|
||||
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
||||
cmn.Exit(cmn.Fmt(`LoadState: Data has been corrupted or its spec has changed:
|
||||
@@ -104,22 +103,23 @@ type ABCIResponses struct {
|
||||
|
||||
// NewABCIResponses returns a new ABCIResponses
|
||||
func NewABCIResponses(block *types.Block) *ABCIResponses {
|
||||
resDeliverTxs := make([]*abci.ResponseDeliverTx, block.NumTxs)
|
||||
if block.NumTxs == 0 {
|
||||
// This makes Amino encoding/decoding consistent.
|
||||
resDeliverTxs = nil
|
||||
}
|
||||
return &ABCIResponses{
|
||||
DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs),
|
||||
DeliverTx: resDeliverTxs,
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes serializes the ABCIResponse using go-wire
|
||||
func (a *ABCIResponses) Bytes() []byte {
|
||||
bz, err := wire.MarshalBinary(*a)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
// Bytes serializes the ABCIResponse using go-amino.
|
||||
func (arz *ABCIResponses) Bytes() []byte {
|
||||
return cdc.MustMarshalBinaryBare(arz)
|
||||
}
|
||||
|
||||
func (a *ABCIResponses) ResultsHash() []byte {
|
||||
results := types.NewResults(a.DeliverTx)
|
||||
func (arz *ABCIResponses) ResultsHash() []byte {
|
||||
results := types.NewResults(arz.DeliverTx)
|
||||
return results.Hash()
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) {
|
||||
}
|
||||
|
||||
abciResponses := new(ABCIResponses)
|
||||
err := wire.UnmarshalBinary(buf, abciResponses)
|
||||
err := cdc.UnmarshalBinaryBare(buf, abciResponses)
|
||||
if err != nil {
|
||||
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
||||
cmn.Exit(cmn.Fmt(`LoadABCIResponses: Data has been corrupted or its spec has
|
||||
@@ -159,13 +159,9 @@ type ValidatorsInfo struct {
|
||||
LastHeightChanged int64
|
||||
}
|
||||
|
||||
// Bytes serializes the ValidatorsInfo using go-wire
|
||||
// Bytes serializes the ValidatorsInfo using go-amino.
|
||||
func (valInfo *ValidatorsInfo) Bytes() []byte {
|
||||
bz, err := wire.MarshalBinary(*valInfo)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return cdc.MustMarshalBinaryBare(valInfo)
|
||||
}
|
||||
|
||||
// LoadValidators loads the ValidatorSet for a given height.
|
||||
@@ -194,7 +190,7 @@ func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo {
|
||||
}
|
||||
|
||||
v := new(ValidatorsInfo)
|
||||
err := wire.UnmarshalBinary(buf, v)
|
||||
err := cdc.UnmarshalBinaryBare(buf, v)
|
||||
if err != nil {
|
||||
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
||||
cmn.Exit(cmn.Fmt(`LoadValidators: Data has been corrupted or its spec has changed:
|
||||
@@ -227,13 +223,9 @@ type ConsensusParamsInfo struct {
|
||||
LastHeightChanged int64
|
||||
}
|
||||
|
||||
// Bytes serializes the ConsensusParamsInfo using go-wire
|
||||
// Bytes serializes the ConsensusParamsInfo using go-amino.
|
||||
func (params ConsensusParamsInfo) Bytes() []byte {
|
||||
bz, err := wire.MarshalBinary(params)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return cdc.MustMarshalBinaryBare(params)
|
||||
}
|
||||
|
||||
// LoadConsensusParams loads the ConsensusParams for a given height.
|
||||
@@ -263,7 +255,7 @@ func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo {
|
||||
}
|
||||
|
||||
paramsInfo := new(ConsensusParamsInfo)
|
||||
err := wire.UnmarshalBinary(buf, paramsInfo)
|
||||
err := cdc.UnmarshalBinaryBare(buf, paramsInfo)
|
||||
if err != nil {
|
||||
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
|
||||
cmn.Exit(cmn.Fmt(`LoadConsensusParams: Data has been corrupted or its spec has changed:
|
||||
|
@@ -34,7 +34,7 @@ func (is *IndexerService) OnStart() error {
|
||||
go func() {
|
||||
for event := range ch {
|
||||
// TODO: may be not perfomant to write one event at a time
|
||||
txResult := event.(types.TMEventData).Unwrap().(types.EventDataTx).TxResult
|
||||
txResult := event.(types.EventDataTx).TxResult
|
||||
is.idr.Index(&txResult)
|
||||
}
|
||||
}()
|
||||
|
@@ -9,8 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
wire "github.com/tendermint/go-wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/pubsub/query"
|
||||
@@ -68,7 +66,7 @@ func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) {
|
||||
}
|
||||
|
||||
txResult := new(types.TxResult)
|
||||
err := wire.UnmarshalBinary(rawBytes, &txResult)
|
||||
err := cdc.UnmarshalBinaryBare(rawBytes, &txResult)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error reading TxResult: %v", err)
|
||||
}
|
||||
@@ -91,7 +89,7 @@ func (txi *TxIndex) AddBatch(b *txindex.Batch) error {
|
||||
}
|
||||
|
||||
// index tx by hash
|
||||
rawBytes, err := wire.MarshalBinary(result)
|
||||
rawBytes, err := cdc.MarshalBinaryBare(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -116,7 +114,7 @@ func (txi *TxIndex) Index(result *types.TxResult) error {
|
||||
}
|
||||
|
||||
// index tx by hash
|
||||
rawBytes, err := wire.MarshalBinary(result)
|
||||
rawBytes, err := cdc.MarshalBinaryBare(result)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -9,18 +9,19 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/state/txindex"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
db "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/pubsub/query"
|
||||
|
||||
"github.com/tendermint/tendermint/state/txindex"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func TestTxIndex(t *testing.T) {
|
||||
indexer := NewTxIndex(db.NewMemDB())
|
||||
|
||||
tx := types.Tx("HELLO WORLD")
|
||||
txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []cmn.KVPair{}}}
|
||||
txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: nil}}
|
||||
hash := tx.Hash()
|
||||
|
||||
batch := txindex.NewBatch(1)
|
||||
@@ -35,7 +36,7 @@ func TestTxIndex(t *testing.T) {
|
||||
assert.Equal(t, txResult, loadedTxResult)
|
||||
|
||||
tx2 := types.Tx("BYE BYE WORLD")
|
||||
txResult2 := &types.TxResult{1, 0, tx2, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []cmn.KVPair{}}}
|
||||
txResult2 := &types.TxResult{1, 0, tx2, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: nil}}
|
||||
hash2 := tx2.Hash()
|
||||
|
||||
err = indexer.Index(txResult2)
|
||||
@@ -151,7 +152,7 @@ func txResultWithTags(tags []cmn.KVPair) *types.TxResult {
|
||||
|
||||
func benchmarkTxIndex(txsCount int, b *testing.B) {
|
||||
tx := types.Tx("HELLO WORLD")
|
||||
txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []cmn.KVPair{}}}
|
||||
txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: nil}}
|
||||
|
||||
dir, err := ioutil.TempDir("", "tx_index_db")
|
||||
if err != nil {
|
||||
|
10
state/txindex/kv/wire.go
Normal file
10
state/txindex/kv/wire.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
}
|
12
state/wire.go
Normal file
12
state/wire.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
crypto.RegisterAmino(cdc)
|
||||
}
|
@@ -5,9 +5,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/tendermint/wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
"github.com/tendermint/tmlibs/merkle"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
// Block defines the atomic unit of a Tendermint blockchain.
|
||||
// TODO: add Version byte
|
||||
type Block struct {
|
||||
mtx sync.Mutex
|
||||
*Header `json:"header"`
|
||||
*Data `json:"data"`
|
||||
Evidence EvidenceData `json:"evidence"`
|
||||
@@ -36,7 +37,7 @@ func MakeBlock(height int64, txs []Tx, commit *Commit) *Block {
|
||||
Txs: txs,
|
||||
},
|
||||
}
|
||||
block.FillHeader()
|
||||
block.fillHeader()
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -48,6 +49,12 @@ func (b *Block) AddEvidence(evidence []Evidence) {
|
||||
// ValidateBasic performs basic validation that doesn't involve state data.
|
||||
// It checks the internal consistency of the block.
|
||||
func (b *Block) ValidateBasic() error {
|
||||
if b == nil {
|
||||
return errors.New("Nil blocks are invalid")
|
||||
}
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
newTxs := int64(len(b.Data.Txs))
|
||||
if b.NumTxs != newTxs {
|
||||
return fmt.Errorf("Wrong Block.Header.NumTxs. Expected %v, got %v", newTxs, b.NumTxs)
|
||||
@@ -69,8 +76,8 @@ func (b *Block) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FillHeader fills in any remaining header fields that are a function of the block data
|
||||
func (b *Block) FillHeader() {
|
||||
// fillHeader fills in any remaining header fields that are a function of the block data
|
||||
func (b *Block) fillHeader() {
|
||||
if b.LastCommitHash == nil {
|
||||
b.LastCommitHash = b.LastCommit.Hash()
|
||||
}
|
||||
@@ -85,17 +92,25 @@ func (b *Block) FillHeader() {
|
||||
// Hash computes and returns the block hash.
|
||||
// If the block is incomplete, block hash is nil for safety.
|
||||
func (b *Block) Hash() cmn.HexBytes {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
b.mtx.Lock()
|
||||
defer b.mtx.Unlock()
|
||||
|
||||
if b == nil || b.Header == nil || b.Data == nil || b.LastCommit == nil {
|
||||
return nil
|
||||
}
|
||||
b.FillHeader()
|
||||
b.fillHeader()
|
||||
return b.Header.Hash()
|
||||
}
|
||||
|
||||
// MakePartSet returns a PartSet containing parts of a serialized block.
|
||||
// This is the form in which the block is gossipped to peers.
|
||||
func (b *Block) MakePartSet(partSize int) *PartSet {
|
||||
bz, err := wire.MarshalBinary(b)
|
||||
// We prefix the byte length, so that unmarshaling
|
||||
// can easily happen via a reader.
|
||||
bz, err := cdc.MarshalBinary(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -183,19 +198,19 @@ func (h *Header) Hash() cmn.HexBytes {
|
||||
return nil
|
||||
}
|
||||
return merkle.SimpleHashFromMap(map[string]merkle.Hasher{
|
||||
"ChainID": wireHasher(h.ChainID),
|
||||
"Height": wireHasher(h.Height),
|
||||
"Time": wireHasher(h.Time),
|
||||
"NumTxs": wireHasher(h.NumTxs),
|
||||
"TotalTxs": wireHasher(h.TotalTxs),
|
||||
"LastBlockID": wireHasher(h.LastBlockID),
|
||||
"LastCommit": wireHasher(h.LastCommitHash),
|
||||
"Data": wireHasher(h.DataHash),
|
||||
"Validators": wireHasher(h.ValidatorsHash),
|
||||
"App": wireHasher(h.AppHash),
|
||||
"Consensus": wireHasher(h.ConsensusHash),
|
||||
"Results": wireHasher(h.LastResultsHash),
|
||||
"Evidence": wireHasher(h.EvidenceHash),
|
||||
"ChainID": aminoHasher(h.ChainID),
|
||||
"Height": aminoHasher(h.Height),
|
||||
"Time": aminoHasher(h.Time),
|
||||
"NumTxs": aminoHasher(h.NumTxs),
|
||||
"TotalTxs": aminoHasher(h.TotalTxs),
|
||||
"LastBlockID": aminoHasher(h.LastBlockID),
|
||||
"LastCommit": aminoHasher(h.LastCommitHash),
|
||||
"Data": aminoHasher(h.DataHash),
|
||||
"Validators": aminoHasher(h.ValidatorsHash),
|
||||
"App": aminoHasher(h.AppHash),
|
||||
"Consensus": aminoHasher(h.ConsensusHash),
|
||||
"Results": aminoHasher(h.LastResultsHash),
|
||||
"Evidence": aminoHasher(h.EvidenceHash),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -364,7 +379,7 @@ func (commit *Commit) Hash() cmn.HexBytes {
|
||||
if commit.hash == nil {
|
||||
bs := make([]merkle.Hasher, len(commit.Precommits))
|
||||
for i, precommit := range commit.Precommits {
|
||||
bs[i] = wireHasher(precommit)
|
||||
bs[i] = aminoHasher(precommit)
|
||||
}
|
||||
commit.hash = merkle.SimpleHashFromHashers(bs)
|
||||
}
|
||||
@@ -499,7 +514,7 @@ func (blockID BlockID) Equals(other BlockID) bool {
|
||||
|
||||
// Key returns a machine-readable string representation of the BlockID
|
||||
func (blockID BlockID) Key() string {
|
||||
bz, err := wire.MarshalBinary(blockID.PartsHeader)
|
||||
bz, err := cdc.MarshalBinaryBare(blockID.PartsHeader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -519,23 +534,25 @@ type hasher struct {
|
||||
|
||||
func (h hasher) Hash() []byte {
|
||||
hasher := ripemd160.New()
|
||||
bz, err := wire.MarshalBinary(h.item)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = hasher.Write(bz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if h.item != nil && !cmn.IsTypedNil(h.item) && !cmn.IsEmpty(h.item) {
|
||||
bz, err := cdc.MarshalBinaryBare(h.item)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = hasher.Write(bz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return hasher.Sum(nil)
|
||||
|
||||
}
|
||||
|
||||
func tmHash(item interface{}) []byte {
|
||||
func aminoHash(item interface{}) []byte {
|
||||
h := hasher{item}
|
||||
return h.Hash()
|
||||
}
|
||||
|
||||
func wireHasher(item interface{}) merkle.Hasher {
|
||||
func aminoHasher(item interface{}) merkle.Hasher {
|
||||
return hasher{item}
|
||||
}
|
||||
|
@@ -13,8 +13,7 @@ func TestValidateBlock(t *testing.T) {
|
||||
lastID := makeBlockIDRandom()
|
||||
h := int64(3)
|
||||
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit,
|
||||
10, 1)
|
||||
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
|
||||
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@@ -3,14 +3,14 @@ package types
|
||||
import (
|
||||
"time"
|
||||
|
||||
wire "github.com/tendermint/tendermint/wire"
|
||||
"github.com/tendermint/go-amino"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
// canonical json is wire's json for structs with fields in alphabetical order
|
||||
// Canonical json is amino's json for structs with fields in alphabetical order
|
||||
|
||||
// TimeFormat is used for generating the sigs
|
||||
const TimeFormat = wire.RFC3339Millis
|
||||
const TimeFormat = amino.RFC3339Millis
|
||||
|
||||
type CanonicalJSONBlockID struct {
|
||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
||||
@@ -18,11 +18,13 @@ type CanonicalJSONBlockID struct {
|
||||
}
|
||||
|
||||
type CanonicalJSONPartSetHeader struct {
|
||||
Hash cmn.HexBytes `json:"hash"`
|
||||
Total int `json:"total"`
|
||||
Hash cmn.HexBytes `json:"hash,omitempty"`
|
||||
Total int `json:"total,omitempty"`
|
||||
}
|
||||
|
||||
type CanonicalJSONProposal struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
BlockPartsHeader CanonicalJSONPartSetHeader `json:"block_parts_header"`
|
||||
Height int64 `json:"height"`
|
||||
POLBlockID CanonicalJSONBlockID `json:"pol_block_id"`
|
||||
@@ -32,14 +34,18 @@ type CanonicalJSONProposal struct {
|
||||
}
|
||||
|
||||
type CanonicalJSONVote struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
BlockID CanonicalJSONBlockID `json:"block_id"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Type byte `json:"type"`
|
||||
VoteType byte `json:"type"`
|
||||
}
|
||||
|
||||
type CanonicalJSONHeartbeat struct {
|
||||
ChainID string `json:"@chain_id"`
|
||||
Type string `json:"@type"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
Sequence int `json:"sequence"`
|
||||
@@ -47,24 +53,6 @@ type CanonicalJSONHeartbeat struct {
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Messages including a "chain id" can only be applied to one chain, hence "Once"
|
||||
|
||||
type CanonicalJSONOnceProposal struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
Proposal CanonicalJSONProposal `json:"proposal"`
|
||||
}
|
||||
|
||||
type CanonicalJSONOnceVote struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
Vote CanonicalJSONVote `json:"vote"`
|
||||
}
|
||||
|
||||
type CanonicalJSONOnceHeartbeat struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
Heartbeat CanonicalJSONHeartbeat `json:"heartbeat"`
|
||||
}
|
||||
|
||||
//-----------------------------------
|
||||
// Canonicalize the structs
|
||||
|
||||
@@ -82,8 +70,10 @@ func CanonicalPartSetHeader(psh PartSetHeader) CanonicalJSONPartSetHeader {
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal {
|
||||
func CanonicalProposal(chainID string, proposal *Proposal) CanonicalJSONProposal {
|
||||
return CanonicalJSONProposal{
|
||||
ChainID: chainID,
|
||||
Type: "proposal",
|
||||
BlockPartsHeader: CanonicalPartSetHeader(proposal.BlockPartsHeader),
|
||||
Height: proposal.Height,
|
||||
Timestamp: CanonicalTime(proposal.Timestamp),
|
||||
@@ -93,28 +83,32 @@ func CanonicalProposal(proposal *Proposal) CanonicalJSONProposal {
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalVote(vote *Vote) CanonicalJSONVote {
|
||||
func CanonicalVote(chainID string, vote *Vote) CanonicalJSONVote {
|
||||
return CanonicalJSONVote{
|
||||
ChainID: chainID,
|
||||
Type: "vote",
|
||||
BlockID: CanonicalBlockID(vote.BlockID),
|
||||
Height: vote.Height,
|
||||
Round: vote.Round,
|
||||
Timestamp: CanonicalTime(vote.Timestamp),
|
||||
Type: vote.Type,
|
||||
VoteType: vote.Type,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalHeartbeat(heartbeat *Heartbeat) CanonicalJSONHeartbeat {
|
||||
func CanonicalHeartbeat(chainID string, heartbeat *Heartbeat) CanonicalJSONHeartbeat {
|
||||
return CanonicalJSONHeartbeat{
|
||||
heartbeat.Height,
|
||||
heartbeat.Round,
|
||||
heartbeat.Sequence,
|
||||
heartbeat.ValidatorAddress,
|
||||
heartbeat.ValidatorIndex,
|
||||
ChainID: chainID,
|
||||
Type: "heartbeat",
|
||||
Height: heartbeat.Height,
|
||||
Round: heartbeat.Round,
|
||||
Sequence: heartbeat.Sequence,
|
||||
ValidatorAddress: heartbeat.ValidatorAddress,
|
||||
ValidatorIndex: heartbeat.ValidatorIndex,
|
||||
}
|
||||
}
|
||||
|
||||
func CanonicalTime(t time.Time) string {
|
||||
// note that sending time over wire resets it to
|
||||
// Note that sending time over amino resets it to
|
||||
// local time, we need to force UTC here, so the
|
||||
// signatures match
|
||||
return t.UTC().Format(TimeFormat)
|
||||
|
@@ -74,15 +74,15 @@ func (b *EventBus) Publish(eventType string, eventData TMEventData) error {
|
||||
//--- block, tx, and vote events
|
||||
|
||||
func (b *EventBus) PublishEventNewBlock(event EventDataNewBlock) error {
|
||||
return b.Publish(EventNewBlock, TMEventData{event})
|
||||
return b.Publish(EventNewBlock, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventNewBlockHeader(event EventDataNewBlockHeader) error {
|
||||
return b.Publish(EventNewBlockHeader, TMEventData{event})
|
||||
return b.Publish(EventNewBlockHeader, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventVote(event EventDataVote) error {
|
||||
return b.Publish(EventVote, TMEventData{event})
|
||||
return b.Publish(EventVote, event)
|
||||
}
|
||||
|
||||
// PublishEventTx publishes tx event with tags from Result. Note it will add
|
||||
@@ -114,50 +114,50 @@ func (b *EventBus) PublishEventTx(event EventDataTx) error {
|
||||
logIfTagExists(TxHeightKey, tags, b.Logger)
|
||||
tags[TxHeightKey] = event.Height
|
||||
|
||||
b.pubsub.PublishWithTags(ctx, TMEventData{event}, tags)
|
||||
b.pubsub.PublishWithTags(ctx, event, tags)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventProposalHeartbeat(event EventDataProposalHeartbeat) error {
|
||||
return b.Publish(EventProposalHeartbeat, TMEventData{event})
|
||||
return b.Publish(EventProposalHeartbeat, event)
|
||||
}
|
||||
|
||||
//--- EventDataRoundState events
|
||||
|
||||
func (b *EventBus) PublishEventNewRoundStep(event EventDataRoundState) error {
|
||||
return b.Publish(EventNewRoundStep, TMEventData{event})
|
||||
return b.Publish(EventNewRoundStep, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventTimeoutPropose(event EventDataRoundState) error {
|
||||
return b.Publish(EventTimeoutPropose, TMEventData{event})
|
||||
return b.Publish(EventTimeoutPropose, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventTimeoutWait(event EventDataRoundState) error {
|
||||
return b.Publish(EventTimeoutWait, TMEventData{event})
|
||||
return b.Publish(EventTimeoutWait, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventNewRound(event EventDataRoundState) error {
|
||||
return b.Publish(EventNewRound, TMEventData{event})
|
||||
return b.Publish(EventNewRound, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventCompleteProposal(event EventDataRoundState) error {
|
||||
return b.Publish(EventCompleteProposal, TMEventData{event})
|
||||
return b.Publish(EventCompleteProposal, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventPolka(event EventDataRoundState) error {
|
||||
return b.Publish(EventPolka, TMEventData{event})
|
||||
return b.Publish(EventPolka, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventUnlock(event EventDataRoundState) error {
|
||||
return b.Publish(EventUnlock, TMEventData{event})
|
||||
return b.Publish(EventUnlock, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventRelock(event EventDataRoundState) error {
|
||||
return b.Publish(EventRelock, TMEventData{event})
|
||||
return b.Publish(EventRelock, event)
|
||||
}
|
||||
|
||||
func (b *EventBus) PublishEventLock(event EventDataRoundState) error {
|
||||
return b.Publish(EventLock, TMEventData{event})
|
||||
return b.Publish(EventLock, event)
|
||||
}
|
||||
|
||||
func logIfTagExists(tag string, tags map[string]interface{}, logger log.Logger) {
|
||||
|
@@ -73,7 +73,7 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
|
||||
eventType = randEvent()
|
||||
}
|
||||
|
||||
eventBus.Publish(eventType, TMEventData{"Gamora"})
|
||||
eventBus.Publish(eventType, EventDataString("Gamora"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ package types
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/go-wire/data"
|
||||
"github.com/tendermint/go-amino"
|
||||
tmpubsub "github.com/tendermint/tmlibs/pubsub"
|
||||
tmquery "github.com/tendermint/tmlibs/pubsub/query"
|
||||
)
|
||||
@@ -35,66 +35,31 @@ const (
|
||||
// ENCODING / DECODING
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var (
|
||||
EventDataNameNewBlock = "new_block"
|
||||
EventDataNameNewBlockHeader = "new_block_header"
|
||||
EventDataNameTx = "tx"
|
||||
EventDataNameRoundState = "round_state"
|
||||
EventDataNameVote = "vote"
|
||||
EventDataNameProposalHeartbeat = "proposal_heartbeat"
|
||||
)
|
||||
|
||||
// implements events.EventData
|
||||
type TMEventDataInner interface {
|
||||
type TMEventData interface {
|
||||
AssertIsTMEventData()
|
||||
// empty interface
|
||||
}
|
||||
|
||||
type TMEventData struct {
|
||||
TMEventDataInner `json:"unwrap"`
|
||||
func (_ EventDataNewBlock) AssertIsTMEventData() {}
|
||||
func (_ EventDataNewBlockHeader) AssertIsTMEventData() {}
|
||||
func (_ EventDataTx) AssertIsTMEventData() {}
|
||||
func (_ EventDataRoundState) AssertIsTMEventData() {}
|
||||
func (_ EventDataVote) AssertIsTMEventData() {}
|
||||
func (_ EventDataProposalHeartbeat) AssertIsTMEventData() {}
|
||||
func (_ EventDataString) AssertIsTMEventData() {}
|
||||
|
||||
func RegisterEventDatas(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*TMEventData)(nil), nil)
|
||||
cdc.RegisterConcrete(EventDataNewBlock{}, "tendermint/event/NewBlock", nil)
|
||||
cdc.RegisterConcrete(EventDataNewBlockHeader{}, "tendermint/event/NewBlockHeader", nil)
|
||||
cdc.RegisterConcrete(EventDataTx{}, "tendermint/event/Tx", nil)
|
||||
cdc.RegisterConcrete(EventDataRoundState{}, "tendermint/event/RoundState", nil)
|
||||
cdc.RegisterConcrete(EventDataVote{}, "tendermint/event/Vote", nil)
|
||||
cdc.RegisterConcrete(EventDataProposalHeartbeat{}, "tendermint/event/ProposalHeartbeat", nil)
|
||||
cdc.RegisterConcrete(EventDataString(""), "tendermint/event/ProposalString", nil)
|
||||
}
|
||||
|
||||
func (tmr TMEventData) MarshalJSON() ([]byte, error) {
|
||||
return tmEventDataMapper.ToJSON(tmr.TMEventDataInner)
|
||||
}
|
||||
|
||||
func (tmr *TMEventData) UnmarshalJSON(data []byte) (err error) {
|
||||
parsed, err := tmEventDataMapper.FromJSON(data)
|
||||
if err == nil && parsed != nil {
|
||||
tmr.TMEventDataInner = parsed.(TMEventDataInner)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tmr TMEventData) Unwrap() TMEventDataInner {
|
||||
tmrI := tmr.TMEventDataInner
|
||||
for wrap, ok := tmrI.(TMEventData); ok; wrap, ok = tmrI.(TMEventData) {
|
||||
tmrI = wrap.TMEventDataInner
|
||||
}
|
||||
return tmrI
|
||||
}
|
||||
|
||||
func (tmr TMEventData) Empty() bool {
|
||||
return tmr.TMEventDataInner == nil
|
||||
}
|
||||
|
||||
const (
|
||||
EventDataTypeNewBlock = byte(0x01)
|
||||
EventDataTypeFork = byte(0x02)
|
||||
EventDataTypeTx = byte(0x03)
|
||||
EventDataTypeNewBlockHeader = byte(0x04)
|
||||
EventDataTypeRoundState = byte(0x11)
|
||||
EventDataTypeVote = byte(0x12)
|
||||
EventDataTypeProposalHeartbeat = byte(0x20)
|
||||
)
|
||||
|
||||
var tmEventDataMapper = data.NewMapper(TMEventData{}).
|
||||
RegisterImplementation(EventDataNewBlock{}, EventDataNameNewBlock, EventDataTypeNewBlock).
|
||||
RegisterImplementation(EventDataNewBlockHeader{}, EventDataNameNewBlockHeader, EventDataTypeNewBlockHeader).
|
||||
RegisterImplementation(EventDataTx{}, EventDataNameTx, EventDataTypeTx).
|
||||
RegisterImplementation(EventDataRoundState{}, EventDataNameRoundState, EventDataTypeRoundState).
|
||||
RegisterImplementation(EventDataVote{}, EventDataNameVote, EventDataTypeVote).
|
||||
RegisterImplementation(EventDataProposalHeartbeat{}, EventDataNameProposalHeartbeat, EventDataTypeProposalHeartbeat)
|
||||
|
||||
// Most event messages are basic types (a block, a transaction)
|
||||
// but some (an input to a call tx or a receive) are more exotic
|
||||
|
||||
@@ -130,6 +95,8 @@ type EventDataVote struct {
|
||||
Vote *Vote
|
||||
}
|
||||
|
||||
type EventDataString string
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PUBSUB
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/go-amino"
|
||||
"github.com/tendermint/go-crypto"
|
||||
wire "github.com/tendermint/tendermint/wire"
|
||||
"github.com/tendermint/tmlibs/merkle"
|
||||
)
|
||||
|
||||
@@ -38,56 +38,11 @@ type Evidence interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
// EvidenceList is a list of Evidence. Evidences is not a word.
|
||||
type EvidenceList []Evidence
|
||||
|
||||
// Hash returns the simple merkle root hash of the EvidenceList.
|
||||
func (evl EvidenceList) Hash() []byte {
|
||||
// Recursive impl.
|
||||
// Copied from tmlibs/merkle to avoid allocations
|
||||
switch len(evl) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return evl[0].Hash()
|
||||
default:
|
||||
left := EvidenceList(evl[:(len(evl)+1)/2]).Hash()
|
||||
right := EvidenceList(evl[(len(evl)+1)/2:]).Hash()
|
||||
return merkle.SimpleHashFromTwoHashes(left, right)
|
||||
}
|
||||
func RegisterEvidences(cdc *amino.Codec) {
|
||||
cdc.RegisterInterface((*Evidence)(nil), nil)
|
||||
cdc.RegisterConcrete(&DuplicateVoteEvidence{}, "tendermint/DuplicateVoteEvidence", nil)
|
||||
}
|
||||
|
||||
func (evl EvidenceList) String() string {
|
||||
s := ""
|
||||
for _, e := range evl {
|
||||
s += fmt.Sprintf("%s\t\t", e)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if the evidence is in the EvidenceList.
|
||||
func (evl EvidenceList) Has(evidence Evidence) bool {
|
||||
for _, ev := range evl {
|
||||
if ev.Equal(evidence) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
const (
|
||||
evidenceTypeDuplicateVote = byte(0x01)
|
||||
)
|
||||
|
||||
var _ = wire.RegisterInterface(
|
||||
struct{ Evidence }{},
|
||||
wire.ConcreteType{&DuplicateVoteEvidence{}, evidenceTypeDuplicateVote},
|
||||
)
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
// DuplicateVoteEvidence contains evidence a validator signed two conflicting votes.
|
||||
@@ -120,7 +75,7 @@ func (dve *DuplicateVoteEvidence) Index() int {
|
||||
|
||||
// Hash returns the hash of the evidence.
|
||||
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
||||
return wireHasher(dve).Hash()
|
||||
return aminoHasher(dve).Hash()
|
||||
}
|
||||
|
||||
// Verify returns an error if the two votes aren't conflicting.
|
||||
@@ -165,8 +120,8 @@ func (dve *DuplicateVoteEvidence) Equal(ev Evidence) bool {
|
||||
}
|
||||
|
||||
// just check their hashes
|
||||
dveHash := wireHasher(dve).Hash()
|
||||
evHash := wireHasher(ev).Hash()
|
||||
dveHash := aminoHasher(dve).Hash()
|
||||
evHash := aminoHasher(ev).Hash()
|
||||
return bytes.Equal(dveHash, evHash)
|
||||
}
|
||||
|
||||
@@ -216,3 +171,42 @@ func (e MockBadEvidence) Equal(ev Evidence) bool {
|
||||
func (e MockBadEvidence) String() string {
|
||||
return fmt.Sprintf("BadEvidence: %d/%s/%d", e.Height_, e.Address_, e.Index_)
|
||||
}
|
||||
|
||||
//-------------------------------------------
|
||||
|
||||
// EvidenceList is a list of Evidence. Evidences is not a word.
|
||||
type EvidenceList []Evidence
|
||||
|
||||
// Hash returns the simple merkle root hash of the EvidenceList.
|
||||
func (evl EvidenceList) Hash() []byte {
|
||||
// Recursive impl.
|
||||
// Copied from tmlibs/merkle to avoid allocations
|
||||
switch len(evl) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return evl[0].Hash()
|
||||
default:
|
||||
left := EvidenceList(evl[:(len(evl)+1)/2]).Hash()
|
||||
right := EvidenceList(evl[(len(evl)+1)/2:]).Hash()
|
||||
return merkle.SimpleHashFromTwoHashes(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
func (evl EvidenceList) String() string {
|
||||
s := ""
|
||||
for _, e := range evl {
|
||||
s += fmt.Sprintf("%s\t\t", e)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Has returns true if the evidence is in the EvidenceList.
|
||||
func (evl EvidenceList) Has(evidence Evidence) bool {
|
||||
for _, ev := range evl {
|
||||
if ev.Equal(evidence) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
type voteData struct {
|
||||
@@ -13,25 +12,25 @@ type voteData struct {
|
||||
valid bool
|
||||
}
|
||||
|
||||
func makeVote(val *PrivValidatorFS, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote {
|
||||
func makeVote(val PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID BlockID) *Vote {
|
||||
v := &Vote{
|
||||
ValidatorAddress: val.PubKey.Address(),
|
||||
ValidatorAddress: val.GetAddress(),
|
||||
ValidatorIndex: valIndex,
|
||||
Height: height,
|
||||
Round: round,
|
||||
Type: byte(step),
|
||||
BlockID: blockID,
|
||||
}
|
||||
sig := val.PrivKey.Sign(v.SignBytes(chainID))
|
||||
v.Signature = sig
|
||||
err := val.SignVote(chainID, v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
|
||||
}
|
||||
|
||||
func TestEvidence(t *testing.T) {
|
||||
_, tmpFilePath := cmn.Tempfile("priv_validator_")
|
||||
val := GenPrivValidatorFS(tmpFilePath)
|
||||
val2 := GenPrivValidatorFS(tmpFilePath)
|
||||
val := NewMockPV()
|
||||
val2 := NewMockPV()
|
||||
blockID := makeBlockID("blockhash", 1000, "partshash")
|
||||
blockID2 := makeBlockID("blockhash2", 1000, "partshash")
|
||||
blockID3 := makeBlockID("blockhash", 10000, "partshash")
|
||||
@@ -41,7 +40,10 @@ func TestEvidence(t *testing.T) {
|
||||
|
||||
vote1 := makeVote(val, chainID, 0, 10, 2, 1, blockID)
|
||||
badVote := makeVote(val, chainID, 0, 10, 2, 1, blockID)
|
||||
badVote.Signature = val2.PrivKey.Sign(badVote.SignBytes(chainID))
|
||||
err := val2.SignVote(chainID, badVote)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cases := []voteData{
|
||||
{vote1, makeVote(val, chainID, 0, 10, 2, 1, blockID2), true}, // different block ids
|
||||
@@ -59,7 +61,7 @@ func TestEvidence(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
ev := &DuplicateVoteEvidence{
|
||||
PubKey: val.PubKey,
|
||||
PubKey: val.GetPubKey(),
|
||||
VoteA: c.vote1,
|
||||
VoteB: c.vote2,
|
||||
}
|
||||
|
@@ -5,9 +5,7 @@ import (
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-crypto"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -33,7 +31,7 @@ type GenesisDoc struct {
|
||||
|
||||
// SaveAs is a utility method for saving GenensisDoc as a JSON file.
|
||||
func (genDoc *GenesisDoc) SaveAs(file string) error {
|
||||
genDocBytes, err := json.Marshal(genDoc)
|
||||
genDocBytes, err := cdc.MarshalJSON(genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,7 +53,7 @@ func (genDoc *GenesisDoc) ValidatorHash() []byte {
|
||||
func (genDoc *GenesisDoc) ValidateAndComplete() error {
|
||||
|
||||
if genDoc.ChainID == "" {
|
||||
return errors.Errorf("Genesis doc must include non-empty chain_id")
|
||||
return cmn.NewError("Genesis doc must include non-empty chain_id")
|
||||
}
|
||||
|
||||
if genDoc.ConsensusParams == nil {
|
||||
@@ -67,12 +65,12 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error {
|
||||
}
|
||||
|
||||
if len(genDoc.Validators) == 0 {
|
||||
return errors.Errorf("The genesis file must have at least one validator")
|
||||
return cmn.NewError("The genesis file must have at least one validator")
|
||||
}
|
||||
|
||||
for _, v := range genDoc.Validators {
|
||||
if v.Power == 0 {
|
||||
return errors.Errorf("The genesis file cannot contain validators with no voting power: %v", v)
|
||||
return cmn.NewError("The genesis file cannot contain validators with no voting power: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +87,7 @@ func (genDoc *GenesisDoc) ValidateAndComplete() error {
|
||||
// GenesisDocFromJSON unmarshalls JSON data into a GenesisDoc.
|
||||
func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) {
|
||||
genDoc := GenesisDoc{}
|
||||
err := json.Unmarshal(jsonBlob, &genDoc)
|
||||
err := cdc.UnmarshalJSON(jsonBlob, &genDoc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -105,11 +103,11 @@ func GenesisDocFromJSON(jsonBlob []byte) (*GenesisDoc, error) {
|
||||
func GenesisDocFromFile(genDocFile string) (*GenesisDoc, error) {
|
||||
jsonBlob, err := ioutil.ReadFile(genDocFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Couldn't read GenesisDoc file")
|
||||
return nil, cmn.ErrorWrap(err, "Couldn't read GenesisDoc file")
|
||||
}
|
||||
genDoc, err := GenesisDocFromJSON(jsonBlob)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, cmn.Fmt("Error reading GenesisDoc at %v", genDocFile))
|
||||
return nil, cmn.ErrorWrap(err, cmn.Fmt("Error reading GenesisDoc at %v", genDocFile))
|
||||
}
|
||||
return genDoc, nil
|
||||
}
|
||||
|
@@ -1,35 +1,34 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-crypto"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenesis(t *testing.T) {
|
||||
func TestGenesisBad(t *testing.T) {
|
||||
// test some bad ones from raw json
|
||||
testCases := [][]byte{
|
||||
[]byte{}, // empty
|
||||
[]byte{1, 1, 1, 1, 1}, // junk
|
||||
[]byte(`{}`), // empty
|
||||
[]byte(`{"chain_id": "mychain"}`), // missing validators
|
||||
[]byte(`{"chain_id": "mychain", "validators": []`), // missing validators
|
||||
[]byte(`{"chain_id": "mychain", "validators": [{}]`), // missing validators
|
||||
[]byte(`{"validators":[{"pub_key":
|
||||
{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},
|
||||
"power":10,"name":""}]}`), // missing chain_id
|
||||
[]byte{}, // empty
|
||||
[]byte{1, 1, 1, 1, 1}, // junk
|
||||
[]byte(`{}`), // empty
|
||||
[]byte(`{"chain_id":"mychain"}`), // missing validators
|
||||
[]byte(`{"chain_id":"mychain","validators":[]}`), // missing validators
|
||||
[]byte(`{"chain_id":"mychain","validators":[{}]}`), // missing validators
|
||||
[]byte(`{"chain_id":"mychain","validators":null}`), // missing validators
|
||||
[]byte(`{"chain_id":"mychain"}`), // missing validators
|
||||
[]byte(`{"validators":[{"pub_key":{"type":"AC26791624DE60","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":10,"name":""}]}`), // missing chain_id
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
_, err := GenesisDocFromJSON(testCase)
|
||||
assert.Error(t, err, "expected error for empty genDoc json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenesisGood(t *testing.T) {
|
||||
// test a good one by raw json
|
||||
genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"ed25519","data":"961EAB8752E51A03618502F55C2B6E09C38C65635C64CCF3173ED452CF86C957"},"power":10,"name":""}],"app_hash":"","app_state":{"account_owner": "Bob"}}`)
|
||||
genDocBytes := []byte(`{"genesis_time":"0001-01-01T00:00:00Z","chain_id":"test-chain-QDKdJr","consensus_params":null,"validators":[{"pub_key":{"type":"AC26791624DE60","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="},"power":10,"name":""}],"app_hash":"","app_state":{"account_owner": "Bob"}}`)
|
||||
_, err := GenesisDocFromJSON(genDocBytes)
|
||||
assert.NoError(t, err, "expected no error for good genDoc json")
|
||||
|
||||
@@ -38,7 +37,7 @@ func TestGenesis(t *testing.T) {
|
||||
ChainID: "abc",
|
||||
Validators: []GenesisValidator{{crypto.GenPrivKeyEd25519().PubKey(), 10, "myval"}},
|
||||
}
|
||||
genDocBytes, err = json.Marshal(baseGenDoc)
|
||||
genDocBytes, err = cdc.MarshalJSON(baseGenDoc)
|
||||
assert.NoError(t, err, "error marshalling genDoc")
|
||||
|
||||
// test base gendoc and check consensus params were filled
|
||||
@@ -47,14 +46,14 @@ func TestGenesis(t *testing.T) {
|
||||
assert.NotNil(t, genDoc.ConsensusParams, "expected consensus params to be filled in")
|
||||
|
||||
// create json with consensus params filled
|
||||
genDocBytes, err = json.Marshal(genDoc)
|
||||
genDocBytes, err = cdc.MarshalJSON(genDoc)
|
||||
assert.NoError(t, err, "error marshalling genDoc")
|
||||
genDoc, err = GenesisDocFromJSON(genDocBytes)
|
||||
assert.NoError(t, err, "expected no error for valid genDoc json")
|
||||
|
||||
// test with invalid consensus params
|
||||
genDoc.ConsensusParams.BlockSize.MaxBytes = 0
|
||||
genDocBytes, err = json.Marshal(genDoc)
|
||||
genDocBytes, err = cdc.MarshalJSON(genDoc)
|
||||
assert.NoError(t, err, "error marshalling genDoc")
|
||||
genDoc, err = GenesisDocFromJSON(genDocBytes)
|
||||
assert.Error(t, err, "expected error for genDoc json with block size of 0")
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/tendermint/wire"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
)
|
||||
|
||||
@@ -14,7 +13,7 @@ import (
|
||||
// json field tags because we always want the JSON
|
||||
// representation to be in its canonical form.
|
||||
type Heartbeat struct {
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorAddress Address `json:"validator_address"`
|
||||
ValidatorIndex int `json:"validator_index"`
|
||||
Height int64 `json:"height"`
|
||||
Round int `json:"round"`
|
||||
@@ -25,10 +24,7 @@ type Heartbeat struct {
|
||||
// SignBytes returns the Heartbeat bytes for signing.
|
||||
// It panics if the Heartbeat is nil.
|
||||
func (heartbeat *Heartbeat) SignBytes(chainID string) []byte {
|
||||
bz, err := wire.MarshalJSON(CanonicalJSONOnceHeartbeat{
|
||||
chainID,
|
||||
CanonicalHeartbeat(heartbeat),
|
||||
})
|
||||
bz, err := cdc.MarshalJSON(CanonicalHeartbeat(chainID, heartbeat))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user