Browse Source

Merge pull request #1265 from tendermint/bucky/new-wire-api

Bucky/new wire api
pull/1274/head
Ethan Buchman 7 years ago
committed by GitHub
parent
commit
3cedd8cf07
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 410 additions and 260 deletions
  1. +7
    -6
      Gopkg.lock
  2. +3
    -3
      Gopkg.toml
  3. +3
    -3
      consensus/byzantine_test.go
  4. +19
    -5
      consensus/replay.go
  5. +7
    -2
      consensus/replay_file.go
  6. +1
    -1
      consensus/replay_test.go
  7. +1
    -1
      consensus/state.go
  8. +1
    -1
      consensus/types/height_vote_set.go
  9. +1
    -1
      consensus/wal_generator.go
  10. +1
    -1
      lite/helpers.go
  11. +1
    -1
      node/node.go
  12. +0
    -1
      rpc/lib/client/http_client.go
  13. +5
    -1
      state/state.go
  14. +27
    -20
      state/store.go
  15. +10
    -6
      state/txindex/kv/kv.go
  16. +27
    -18
      types/block.go
  17. +3
    -3
      types/canonical_json.go
  18. +3
    -3
      types/evidence.go
  19. +2
    -2
      types/evidence_test.go
  20. +9
    -6
      types/heartbeat.go
  21. +6
    -12
      types/heartbeat_test.go
  22. +0
    -5
      types/part_set.go
  23. +5
    -4
      types/priv_validator.go
  24. +4
    -4
      types/priv_validator/priv_validator_test.go
  25. +2
    -2
      types/priv_validator/sign_info.go
  26. +1
    -1
      types/priv_validator/unencrypted.go
  27. +8
    -6
      types/priv_validator_test.go
  28. +9
    -6
      types/proposal.go
  29. +12
    -11
      types/proposal_test.go
  30. +8
    -4
      types/results.go
  31. +8
    -16
      types/signable.go
  32. +1
    -1
      types/test_util.go
  33. +2
    -2
      types/tx.go
  34. +7
    -5
      types/tx_test.go
  35. +4
    -25
      types/validator.go
  36. +2
    -2
      types/validator_set.go
  37. +114
    -52
      types/validator_set_test.go
  38. +9
    -6
      types/vote.go
  39. +9
    -4
      types/vote_set.go
  40. +8
    -7
      types/vote_test.go
  41. +60
    -0
      wire/wire.go

+ 7
- 6
Gopkg.lock View File

@ -224,6 +224,7 @@
revision = "34011bf325bce385408353a30b101fe5e923eb6e"
[[projects]]
branch = "develop"
name = "github.com/tendermint/abci"
packages = [
"client",
@ -233,7 +234,7 @@
"server",
"types"
]
revision = "345a5a5a34aa31ad00626266f59e4ae7652ee274"
revision = "9e0e00bef42aebf6b402f66bf0f3dc607de8a6f3"
[[projects]]
branch = "master"
@ -248,8 +249,8 @@
[[projects]]
name = "github.com/tendermint/go-crypto"
packages = ["."]
revision = "dd20358a264c772b4a83e477b0cfce4c88a7001d"
version = "v0.4.1"
revision = "c3e19f3ea26f5c3357e0bcbb799b0761ef923755"
version = "v0.5.0"
[[projects]]
name = "github.com/tendermint/go-wire"
@ -257,8 +258,8 @@
".",
"data"
]
revision = "b6fc872b42d41158a60307db4da051dd6f179415"
version = "v0.7.2"
revision = "fa721242b042ecd4c6ed1a934ee740db4f74e45c"
version = "v0.7.3"
[[projects]]
name = "github.com/tendermint/tmlibs"
@ -371,6 +372,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "a65ef86e3db67769c1fa4ae1f67af8d5b95474f4b95ec799d8572e19b44b206a"
inputs-digest = "36505c5f341e1e80d7d55589a17727bbd9e89403624b4e02c9e8a21b1ed39d0f"
solver-name = "gps-cdcl"
solver-version = 1

+ 3
- 3
Gopkg.toml View File

@ -71,15 +71,15 @@
[[constraint]]
name = "github.com/tendermint/abci"
revision = "345a5a5a34aa31ad00626266f59e4ae7652ee274"
branch = "develop"
[[constraint]]
name = "github.com/tendermint/go-crypto"
version = "0.4.1"
version = "0.5.0"
[[constraint]]
name = "github.com/tendermint/go-wire"
version = "0.7.2"
version = "0.7.3"
[[constraint]]
name = "github.com/tendermint/tmlibs"


+ 3
- 3
consensus/byzantine_test.go View File

@ -289,17 +289,17 @@ func (privVal *ByzantinePrivValidator) GetPubKey() crypto.PubKey {
}
func (privVal *ByzantinePrivValidator) SignVote(chainID string, vote *types.Vote) (err error) {
vote.Signature, err = privVal.Sign(types.SignBytes(chainID, vote))
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(types.SignBytes(chainID, proposal))
proposal.Signature, _ = privVal.Sign(proposal.SignBytes(chainID))
return nil
}
func (privVal *ByzantinePrivValidator) SignHeartbeat(chainID string, heartbeat *types.Heartbeat) (err error) {
heartbeat.Signature, _ = privVal.Sign(types.SignBytes(chainID, heartbeat))
heartbeat.Signature, _ = privVal.Sign(heartbeat.SignBytes(chainID))
return nil
}


+ 19
- 5
consensus/replay.go View File

@ -2,6 +2,7 @@ package consensus
import (
"bytes"
"encoding/json"
"fmt"
"hash/crc32"
"io"
@ -190,13 +191,23 @@ type Handshaker struct {
stateDB dbm.DB
initialState sm.State
store types.BlockStore
appState json.RawMessage
logger log.Logger
nBlocks int // number of blocks applied to the state
}
func NewHandshaker(stateDB dbm.DB, state sm.State, store types.BlockStore) *Handshaker {
return &Handshaker{stateDB, state, store, log.NewNopLogger(), 0}
func NewHandshaker(stateDB dbm.DB, state sm.State,
store types.BlockStore, appState json.RawMessage) *Handshaker {
return &Handshaker{
stateDB: stateDB,
initialState: state,
store: store,
appState: appState,
logger: log.NewNopLogger(),
nBlocks: 0,
}
}
func (h *Handshaker) SetLogger(l log.Logger) {
@ -249,9 +260,12 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
// If appBlockHeight == 0 it means that we are at genesis and hence should send InitChain
if appBlockHeight == 0 {
validators := types.TM2PB.Validators(state.Validators)
// TODO: get the genesis bytes (https://github.com/tendermint/tendermint/issues/1224)
var genesisBytes []byte
if _, err := proxyApp.Consensus().InitChainSync(abci.RequestInitChain{validators, genesisBytes}); err != nil {
req := abci.RequestInitChain{
Validators: validators,
AppStateBytes: h.appState,
}
_, err := proxyApp.Consensus().InitChainSync(req)
if err != nil {
return nil, err
}
}


+ 7
- 2
consensus/replay_file.go View File

@ -287,14 +287,19 @@ func newConsensusStateForReplay(config cfg.BaseConfig, csConfig *cfg.ConsensusCo
// Get State
stateDB := dbm.NewDB("state", dbType, config.DBDir())
state, err := sm.MakeGenesisStateFromFile(config.GenesisFile())
gdoc, err := sm.MakeGenesisDocFromFile(config.GenesisFile())
if err != nil {
cmn.Exit(err.Error())
}
state, err := sm.MakeGenesisState(gdoc)
if err != nil {
cmn.Exit(err.Error())
}
// Create proxyAppConn connection (consensus, mempool, query)
clientCreator := proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())
proxyApp := proxy.NewAppConns(clientCreator, NewHandshaker(stateDB, state, blockStore))
proxyApp := proxy.NewAppConns(clientCreator,
NewHandshaker(stateDB, state, blockStore, gdoc.AppState))
err = proxyApp.Start()
if err != nil {
cmn.Exit(cmn.Fmt("Error starting proxy app conns: %v", err))


+ 1
- 1
consensus/replay_test.go View File

@ -362,7 +362,7 @@ func testHandshakeReplay(t *testing.T, nBlocks int, mode uint) {
}
// now start the app using the handshake - it should sync
handshaker := NewHandshaker(stateDB, state, store)
handshaker := NewHandshaker(stateDB, state, store, nil)
proxyApp := proxy.NewAppConns(clientCreator2, handshaker)
if err := proxyApp.Start(); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)


+ 1
- 1
consensus/state.go View File

@ -1269,7 +1269,7 @@ func (cs *ConsensusState) defaultSetProposal(proposal *types.Proposal) error {
}
// Verify signature
if !cs.Validators.GetProposer().PubKey.VerifyBytes(types.SignBytes(cs.state.ChainID, proposal), proposal.Signature) {
if !cs.Validators.GetProposer().PubKey.VerifyBytes(proposal.SignBytes(cs.state.ChainID), proposal.Signature) {
return ErrInvalidProposalSignature
}


+ 1
- 1
consensus/types/height_vote_set.go View File

@ -218,5 +218,5 @@ func (hvs *HeightVoteSet) SetPeerMaj23(round int, type_ byte, peerID p2p.ID, blo
if voteSet == nil {
return nil // something we don't know about yet
}
return voteSet.SetPeerMaj23(peerID, blockID)
return voteSet.SetPeerMaj23(types.P2PID(peerID), blockID)
}

+ 1
- 1
consensus/wal_generator.go View File

@ -52,7 +52,7 @@ func WALWithNBlocks(numBlocks int) (data []byte, err error) {
return nil, errors.Wrap(err, "failed to make genesis state")
}
blockStore := bc.NewBlockStore(blockStoreDB)
handshaker := NewHandshaker(stateDB, state, blockStore)
handshaker := NewHandshaker(stateDB, state, blockStore, genDoc.AppState)
proxyApp := proxy.NewAppConns(proxy.NewLocalClientCreator(app), handshaker)
proxyApp.SetLogger(logger.With("module", "proxy"))
if err := proxyApp.Start(); err != nil {


+ 1
- 1
lite/helpers.go View File

@ -102,7 +102,7 @@ func makeVote(header *types.Header, vals *types.ValidatorSet, key crypto.PrivKey
BlockID: types.BlockID{Hash: header.Hash()},
}
// Sign it
signBytes := types.SignBytes(header.ChainID, vote)
signBytes := vote.SignBytes(header.ChainID)
vote.Signature = key.Sign(signBytes)
return vote
}


+ 1
- 1
node/node.go View File

@ -162,7 +162,7 @@ func NewNode(config *cfg.Config,
// and sync tendermint and the app by performing a handshake
// and replaying any necessary blocks
consensusLogger := logger.With("module", "consensus")
handshaker := cs.NewHandshaker(stateDB, state, blockStore)
handshaker := cs.NewHandshaker(stateDB, state, blockStore, genDoc.AppState)
handshaker.SetLogger(consensusLogger)
proxyApp := proxy.NewAppConns(clientCreator, handshaker)
proxyApp.SetLogger(logger.With("module", "proxy"))


+ 0
- 1
rpc/lib/client/http_client.go View File

@ -187,7 +187,6 @@ func argsToJson(args map[string]interface{}) error {
continue
}
// Pass everything else to go-wire
data, err := json.Marshal(v)
if err != nil {
return err


+ 5
- 1
state/state.go View File

@ -86,7 +86,11 @@ func (s State) Equals(s2 State) bool {
// Bytes serializes the State using go-wire.
func (s State) Bytes() []byte {
return wire.BinaryBytes(s)
bz, err := wire.MarshalBinary(s)
if err != nil {
panic(err)
}
return bz
}
// IsEmpty returns true if the State is equal to the empty State.


+ 27
- 20
state/store.go View File

@ -1,7 +1,6 @@
package state
import (
"bytes"
"fmt"
abci "github.com/tendermint/abci/types"
@ -70,12 +69,11 @@ func loadState(db dbm.DB, key []byte) (state State) {
return state
}
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(&state, r, 0, n, err)
if *err != nil {
err := wire.UnmarshalBinary(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:
%v\n`, *err))
%v\n`, err))
}
// TODO: ensure that buf is completely read.
@ -113,7 +111,11 @@ func NewABCIResponses(block *types.Block) *ABCIResponses {
// Bytes serializes the ABCIResponse using go-wire
func (a *ABCIResponses) Bytes() []byte {
return wire.BinaryBytes(*a)
bz, err := wire.MarshalBinary(*a)
if err != nil {
panic(err)
}
return bz
}
func (a *ABCIResponses) ResultsHash() []byte {
@ -131,12 +133,11 @@ func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) {
}
abciResponses := new(ABCIResponses)
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(abciResponses, r, 0, n, err)
if *err != nil {
err := wire.UnmarshalBinary(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
changed: %v\n`, *err))
changed: %v\n`, err))
}
// TODO: ensure that buf is completely read.
@ -160,7 +161,11 @@ type ValidatorsInfo struct {
// Bytes serializes the ValidatorsInfo using go-wire
func (valInfo *ValidatorsInfo) Bytes() []byte {
return wire.BinaryBytes(*valInfo)
bz, err := wire.MarshalBinary(*valInfo)
if err != nil {
panic(err)
}
return bz
}
// LoadValidators loads the ValidatorSet for a given height.
@ -189,12 +194,11 @@ func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo {
}
v := new(ValidatorsInfo)
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(v, r, 0, n, err)
if *err != nil {
err := wire.UnmarshalBinary(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:
%v\n`, *err))
%v\n`, err))
}
// TODO: ensure that buf is completely read.
@ -225,7 +229,11 @@ type ConsensusParamsInfo struct {
// Bytes serializes the ConsensusParamsInfo using go-wire
func (params ConsensusParamsInfo) Bytes() []byte {
return wire.BinaryBytes(params)
bz, err := wire.MarshalBinary(params)
if err != nil {
panic(err)
}
return bz
}
// LoadConsensusParams loads the ConsensusParams for a given height.
@ -255,12 +263,11 @@ func loadConsensusParamsInfo(db dbm.DB, height int64) *ConsensusParamsInfo {
}
paramsInfo := new(ConsensusParamsInfo)
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(paramsInfo, r, 0, n, err)
if *err != nil {
err := wire.UnmarshalBinary(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:
%v\n`, *err))
%v\n`, err))
}
// TODO: ensure that buf is completely read.


+ 10
- 6
state/txindex/kv/kv.go View File

@ -67,10 +67,8 @@ func (txi *TxIndex) Get(hash []byte) (*types.TxResult, error) {
return nil, nil
}
r := bytes.NewReader(rawBytes)
var n int
var err error
txResult := wire.ReadBinary(&types.TxResult{}, r, 0, &n, &err).(*types.TxResult)
txResult := new(types.TxResult)
err := wire.UnmarshalBinary(rawBytes, &txResult)
if err != nil {
return nil, fmt.Errorf("Error reading TxResult: %v", err)
}
@ -93,7 +91,10 @@ func (txi *TxIndex) AddBatch(b *txindex.Batch) error {
}
// index tx by hash
rawBytes := wire.BinaryBytes(result)
rawBytes, err := wire.MarshalBinary(result)
if err != nil {
return err
}
storeBatch.Set(hash, rawBytes)
}
@ -115,7 +116,10 @@ func (txi *TxIndex) Index(result *types.TxResult) error {
}
// index tx by hash
rawBytes := wire.BinaryBytes(result)
rawBytes, err := wire.MarshalBinary(result)
if err != nil {
return err
}
b.Set(hash, rawBytes)
b.Write()


+ 27
- 18
types/block.go View File

@ -4,11 +4,10 @@ import (
"bytes"
"errors"
"fmt"
"io"
"strings"
"time"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/merkle"
"golang.org/x/crypto/ripemd160"
@ -96,7 +95,11 @@ func (b *Block) Hash() cmn.HexBytes {
// 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 {
return NewPartSetFromData(wire.BinaryBytes(b), partSize)
bz, err := wire.MarshalBinary(b)
if err != nil {
panic(err)
}
return NewPartSetFromData(bz, partSize)
}
// HashesTo is a convenience function that checks if a block hashes to the given argument.
@ -249,7 +252,8 @@ type Commit struct {
bitArray *cmn.BitArray
}
// FirstPrecommit returns the first non-nil precommit in the commit
// FirstPrecommit returns the first non-nil precommit in the commit.
// If all precommits are nil, it returns an empty precommit with height 0.
func (commit *Commit) FirstPrecommit() *Vote {
if len(commit.Precommits) == 0 {
return nil
@ -263,7 +267,9 @@ func (commit *Commit) FirstPrecommit() *Vote {
return precommit
}
}
return nil
return &Vote{
Type: VoteTypePrecommit,
}
}
// Height returns the height of the commit
@ -493,17 +499,11 @@ func (blockID BlockID) Equals(other BlockID) bool {
// Key returns a machine-readable string representation of the BlockID
func (blockID BlockID) Key() string {
return string(blockID.Hash) + string(wire.BinaryBytes(blockID.PartsHeader))
}
// WriteSignBytes writes the canonical bytes of the BlockID to the given writer for digital signing
func (blockID BlockID) WriteSignBytes(w io.Writer, n *int, err *error) {
if blockID.IsZero() {
wire.WriteTo([]byte("null"), w, n, err)
} else {
wire.WriteJSON(CanonicalBlockID(blockID), w, n, err)
bz, err := wire.MarshalBinary(blockID.PartsHeader)
if err != nil {
panic(err)
}
return string(blockID.Hash) + string(bz)
}
// String returns a human readable string representation of the BlockID
@ -518,15 +518,24 @@ type hasher struct {
}
func (h hasher) Hash() []byte {
hasher, n, err := ripemd160.New(), new(int), new(error)
wire.WriteBinary(h.item, hasher, n, err)
if *err != nil {
hasher := ripemd160.New()
bz, err := wire.MarshalBinary(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 {
h := hasher{item}
return h.Hash()
}
func wireHasher(item interface{}) merkle.Hasher {
return hasher{item}
}

+ 3
- 3
types/canonical_json.go View File

@ -3,11 +3,11 @@ package types
import (
"time"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
)
// canonical json is go-wire's json for structs with fields in alphabetical order
// canonical json is wire's json for structs with fields in alphabetical order
// TimeFormat is used for generating the sigs
const TimeFormat = wire.RFC3339Millis
@ -114,7 +114,7 @@ func CanonicalHeartbeat(heartbeat *Heartbeat) CanonicalJSONHeartbeat {
}
func CanonicalTime(t time.Time) string {
// note that sending time over go-wire resets it to
// note that sending time over wire resets it to
// local time, we need to force UTC here, so the
// signatures match
return t.UTC().Format(TimeFormat)


+ 3
- 3
types/evidence.go View File

@ -5,7 +5,7 @@ import (
"fmt"
"github.com/tendermint/go-crypto"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
"github.com/tendermint/tmlibs/merkle"
)
@ -148,10 +148,10 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
}
// Signatures must be valid
if !dve.PubKey.VerifyBytes(SignBytes(chainID, dve.VoteA), dve.VoteA.Signature) {
if !dve.PubKey.VerifyBytes(dve.VoteA.SignBytes(chainID), dve.VoteA.Signature) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteA: %v", ErrVoteInvalidSignature)
}
if !dve.PubKey.VerifyBytes(SignBytes(chainID, dve.VoteB), dve.VoteB.Signature) {
if !dve.PubKey.VerifyBytes(dve.VoteB.SignBytes(chainID), dve.VoteB.Signature) {
return fmt.Errorf("DuplicateVoteEvidence Error verifying VoteB: %v", ErrVoteInvalidSignature)
}


+ 2
- 2
types/evidence_test.go View File

@ -22,7 +22,7 @@ func makeVote(val *PrivValidatorFS, chainID string, valIndex int, height int64,
Type: byte(step),
BlockID: blockID,
}
sig := val.PrivKey.Sign(SignBytes(chainID, v))
sig := val.PrivKey.Sign(v.SignBytes(chainID))
v.Signature = sig
return v
@ -41,7 +41,7 @@ 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(SignBytes(chainID, badVote))
badVote.Signature = val2.PrivKey.Sign(badVote.SignBytes(chainID))
cases := []voteData{
{vote1, makeVote(val, chainID, 0, 10, 2, 1, blockID2), true}, // different block ids


+ 9
- 6
types/heartbeat.go View File

@ -2,10 +2,9 @@ package types
import (
"fmt"
"io"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
)
@ -23,13 +22,17 @@ type Heartbeat struct {
Signature crypto.Signature `json:"signature"`
}
// WriteSignBytes writes the Heartbeat for signing.
// SignBytes returns the Heartbeat bytes for signing.
// It panics if the Heartbeat is nil.
func (heartbeat *Heartbeat) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
wire.WriteJSON(CanonicalJSONOnceHeartbeat{
func (heartbeat *Heartbeat) SignBytes(chainID string) []byte {
bz, err := wire.MarshalJSON(CanonicalJSONOnceHeartbeat{
chainID,
CanonicalHeartbeat(heartbeat),
}, w, n, err)
})
if err != nil {
panic(err)
}
return bz
}
// Copy makes a copy of the Heartbeat.


+ 6
- 12
types/heartbeat_test.go View File

@ -1,7 +1,6 @@
package types
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
@ -34,23 +33,18 @@ func TestHeartbeatString(t *testing.T) {
}
func TestHeartbeatWriteSignBytes(t *testing.T) {
var n int
var err error
buf := new(bytes.Buffer)
hb := &Heartbeat{ValidatorIndex: 1, Height: 10, Round: 1}
hb.WriteSignBytes("0xdeadbeef", buf, &n, &err)
require.Equal(t, buf.String(), `{"chain_id":"0xdeadbeef","heartbeat":{"height":10,"round":1,"sequence":0,"validator_address":"","validator_index":1}}`)
bz := hb.SignBytes("0xdeadbeef")
require.Equal(t, string(bz), `{"chain_id":"0xdeadbeef","heartbeat":{"height":10,"round":1,"sequence":0,"validator_address":"","validator_index":1}}`)
buf.Reset()
plainHb := &Heartbeat{}
plainHb.WriteSignBytes("0xdeadbeef", buf, &n, &err)
require.Equal(t, buf.String(), `{"chain_id":"0xdeadbeef","heartbeat":{"height":0,"round":0,"sequence":0,"validator_address":"","validator_index":0}}`)
bz = plainHb.SignBytes("0xdeadbeef")
require.Equal(t, string(bz), `{"chain_id":"0xdeadbeef","heartbeat":{"height":0,"round":0,"sequence":0,"validator_address":"","validator_index":0}}`)
require.Panics(t, func() {
buf.Reset()
var nilHb *Heartbeat
nilHb.WriteSignBytes("0xdeadbeef", buf, &n, &err)
require.Equal(t, buf.String(), "null")
bz := nilHb.SignBytes("0xdeadbeef")
require.Equal(t, string(bz), "null")
})
}

+ 0
- 5
types/part_set.go View File

@ -9,7 +9,6 @@ import (
"golang.org/x/crypto/ripemd160"
"github.com/tendermint/go-wire"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/merkle"
)
@ -73,10 +72,6 @@ func (psh PartSetHeader) Equals(other PartSetHeader) bool {
return psh.Total == other.Total && bytes.Equal(psh.Hash, other.Hash)
}
func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int, err *error) {
wire.WriteJSON(CanonicalPartSetHeader(psh), w, n, err)
}
//-------------------------------------
type PartSet struct {


+ 5
- 4
types/priv_validator.go View File

@ -234,10 +234,11 @@ func (privVal *PrivValidatorFS) save() {
// Reset resets all fields in the PrivValidatorFS.
// NOTE: Unsafe!
func (privVal *PrivValidatorFS) Reset() {
var sig crypto.Signature
privVal.LastHeight = 0
privVal.LastRound = 0
privVal.LastStep = 0
privVal.LastSignature = crypto.Signature{}
privVal.LastSignature = sig
privVal.LastSignBytes = nil
privVal.Save()
}
@ -297,7 +298,7 @@ func (privVal *PrivValidatorFS) checkHRS(height int64, round int, step int8) (bo
// a previously signed vote (ie. we crashed after signing but before the vote hit the WAL).
func (privVal *PrivValidatorFS) signVote(chainID string, vote *Vote) error {
height, round, step := vote.Height, vote.Round, voteToStep(vote)
signBytes := SignBytes(chainID, vote)
signBytes := vote.SignBytes(chainID)
sameHRS, err := privVal.checkHRS(height, round, step)
if err != nil {
@ -336,7 +337,7 @@ func (privVal *PrivValidatorFS) signVote(chainID string, vote *Vote) error {
// a previously signed proposal ie. we crashed after signing but before the proposal hit the WAL).
func (privVal *PrivValidatorFS) signProposal(chainID string, proposal *Proposal) error {
height, round, step := proposal.Height, proposal.Round, stepPropose
signBytes := SignBytes(chainID, proposal)
signBytes := proposal.SignBytes(chainID)
sameHRS, err := privVal.checkHRS(height, round, step)
if err != nil {
@ -388,7 +389,7 @@ func (privVal *PrivValidatorFS) SignHeartbeat(chainID string, heartbeat *Heartbe
privVal.mtx.Lock()
defer privVal.mtx.Unlock()
var err error
heartbeat.Signature, err = privVal.Sign(SignBytes(chainID, heartbeat))
heartbeat.Signature, err = privVal.Sign(heartbeat.SignBytes(chainID))
return err
}


+ 4
- 4
types/priv_validator/priv_validator_test.go View File

@ -211,7 +211,7 @@ func TestDifferByTimestamp(t *testing.T) {
proposal := newProposal(height, round, block1)
err := privVal.SignProposal(chainID, proposal)
assert.NoError(t, err, "expected no error signing proposal")
signBytes := types.SignBytes(chainID, proposal)
signBytes := proposal.SignBytes(chainID)
sig := proposal.Signature
timeStamp := clipToMS(proposal.Timestamp)
@ -222,7 +222,7 @@ func TestDifferByTimestamp(t *testing.T) {
assert.NoError(t, err, "expected no error on signing same proposal")
assert.Equal(t, timeStamp, proposal.Timestamp)
assert.Equal(t, signBytes, types.SignBytes(chainID, proposal))
assert.Equal(t, signBytes, proposal.SignBytes(chainID))
assert.Equal(t, sig, proposal.Signature)
}
@ -237,7 +237,7 @@ func TestDifferByTimestamp(t *testing.T) {
err = privVal.SignVote("mychainid", vote)
assert.NoError(t, err, "expected no error signing vote")
signBytes := types.SignBytes(chainID, vote)
signBytes := vote.SignBytes(chainID)
sig := vote.Signature
timeStamp := clipToMS(vote.Timestamp)
@ -248,7 +248,7 @@ func TestDifferByTimestamp(t *testing.T) {
assert.NoError(t, err, "expected no error on signing same vote")
assert.Equal(t, timeStamp, vote.Timestamp)
assert.Equal(t, signBytes, types.SignBytes(chainID, vote))
assert.Equal(t, signBytes, vote.SignBytes(chainID))
assert.Equal(t, sig, vote.Signature)
}
}


+ 2
- 2
types/priv_validator/sign_info.go View File

@ -112,7 +112,7 @@ func (info *LastSignedInfo) Reset() {
// Else it returns an error.
func (lsi *LastSignedInfo) SignVote(signer types.Signer, chainID string, vote *types.Vote) error {
height, round, step := vote.Height, vote.Round, voteToStep(vote)
signBytes := types.SignBytes(chainID, vote)
signBytes := vote.SignBytes(chainID)
sameHRS, err := lsi.Verify(height, round, step)
if err != nil {
@ -151,7 +151,7 @@ func (lsi *LastSignedInfo) SignVote(signer types.Signer, chainID string, vote *t
// Else it returns an error.
func (lsi *LastSignedInfo) SignProposal(signer types.Signer, chainID string, proposal *types.Proposal) error {
height, round, step := proposal.Height, proposal.Round, stepPropose
signBytes := types.SignBytes(chainID, proposal)
signBytes := proposal.SignBytes(chainID)
sameHRS, err := lsi.Verify(height, round, step)
if err != nil {


+ 1
- 1
types/priv_validator/unencrypted.go View File

@ -61,6 +61,6 @@ func (upv *PrivValidatorUnencrypted) SignProposal(chainID string, proposal *type
func (upv *PrivValidatorUnencrypted) SignHeartbeat(chainID string, heartbeat *types.Heartbeat) error {
var err error
heartbeat.Signature, err = upv.PrivKey.Sign(types.SignBytes(chainID, heartbeat))
heartbeat.Signature, err = upv.PrivKey.Sign(heartbeat.SignBytes(chainID))
return err
}

+ 8
- 6
types/priv_validator_test.go View File

@ -185,18 +185,19 @@ func TestDifferByTimestamp(t *testing.T) {
proposal := newProposal(height, round, block1)
err := privVal.SignProposal(chainID, proposal)
assert.NoError(t, err, "expected no error signing proposal")
signBytes := SignBytes(chainID, proposal)
signBytes := proposal.SignBytes(chainID)
sig := proposal.Signature
timeStamp := clipToMS(proposal.Timestamp)
// manipulate the timestamp. should get changed back
proposal.Timestamp = proposal.Timestamp.Add(time.Millisecond)
proposal.Signature = crypto.Signature{}
var emptySig crypto.Signature
proposal.Signature = emptySig
err = privVal.SignProposal("mychainid", proposal)
assert.NoError(t, err, "expected no error on signing same proposal")
assert.Equal(t, timeStamp, proposal.Timestamp)
assert.Equal(t, signBytes, SignBytes(chainID, proposal))
assert.Equal(t, signBytes, proposal.SignBytes(chainID))
assert.Equal(t, sig, proposal.Signature)
}
@ -208,18 +209,19 @@ func TestDifferByTimestamp(t *testing.T) {
err := privVal.SignVote("mychainid", vote)
assert.NoError(t, err, "expected no error signing vote")
signBytes := SignBytes(chainID, vote)
signBytes := vote.SignBytes(chainID)
sig := vote.Signature
timeStamp := clipToMS(vote.Timestamp)
// manipulate the timestamp. should get changed back
vote.Timestamp = vote.Timestamp.Add(time.Millisecond)
vote.Signature = crypto.Signature{}
var emptySig crypto.Signature
vote.Signature = emptySig
err = privVal.SignVote("mychainid", vote)
assert.NoError(t, err, "expected no error on signing same vote")
assert.Equal(t, timeStamp, vote.Timestamp)
assert.Equal(t, signBytes, SignBytes(chainID, vote))
assert.Equal(t, signBytes, vote.SignBytes(chainID))
assert.Equal(t, sig, vote.Signature)
}
}


+ 9
- 6
types/proposal.go View File

@ -3,11 +3,10 @@ package types
import (
"errors"
"fmt"
"io"
"time"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/wire"
)
var (
@ -50,10 +49,14 @@ func (p *Proposal) String() string {
p.POLBlockID, p.Signature, CanonicalTime(p.Timestamp))
}
// WriteSignBytes writes the Proposal bytes for signing
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
wire.WriteJSON(CanonicalJSONOnceProposal{
// SignBytes returns the Proposal bytes for signing
func (p *Proposal) SignBytes(chainID string) []byte {
bz, err := wire.MarshalJSON(CanonicalJSONOnceProposal{
ChainID: chainID,
Proposal: CanonicalProposal(p),
}, w, n, err)
})
if err != nil {
panic(err)
}
return bz
}

+ 12
- 11
types/proposal_test.go View File

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
)
var testProposal *Proposal
@ -26,7 +26,7 @@ func init() {
}
func TestProposalSignable(t *testing.T) {
signBytes := SignBytes("test_chain_id", testProposal)
signBytes := testProposal.SignBytes("test_chain_id")
signStr := string(signBytes)
expected := `{"chain_id":"test_chain_id","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_block_id":{},"pol_round":-1,"round":23456,"timestamp":"2018-02-11T07:09:22.765Z"}}`
@ -48,24 +48,25 @@ func TestProposalVerifySignature(t *testing.T) {
pubKey := privVal.GetPubKey()
prop := NewProposal(4, 2, PartSetHeader{777, []byte("proper")}, 2, BlockID{})
signBytes := SignBytes("test_chain_id", prop)
signBytes := prop.SignBytes("test_chain_id")
// sign it
signature, err := privVal.Signer.Sign(signBytes)
require.NoError(t, err)
// verify the same proposal
valid := pubKey.VerifyBytes(SignBytes("test_chain_id", prop), signature)
valid := pubKey.VerifyBytes(prop.SignBytes("test_chain_id"), signature)
require.True(t, valid)
// serialize, deserialize and verify again....
newProp := new(Proposal)
bs := wire.BinaryBytes(prop)
err = wire.ReadBinaryBytes(bs, &newProp)
bs, err := wire.MarshalBinary(prop)
require.NoError(t, err)
err = wire.UnmarshalBinary(bs, &newProp)
require.NoError(t, err)
// verify the transmitted proposal
newSignBytes := SignBytes("test_chain_id", newProp)
newSignBytes := newProp.SignBytes("test_chain_id")
require.Equal(t, string(signBytes), string(newSignBytes))
valid = pubKey.VerifyBytes(newSignBytes, signature)
require.True(t, valid)
@ -73,14 +74,14 @@ func TestProposalVerifySignature(t *testing.T) {
func BenchmarkProposalWriteSignBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
SignBytes("test_chain_id", testProposal)
testProposal.SignBytes("test_chain_id")
}
}
func BenchmarkProposalSign(b *testing.B) {
privVal := GenPrivValidatorFS("")
for i := 0; i < b.N; i++ {
_, err := privVal.Signer.Sign(SignBytes("test_chain_id", testProposal))
_, err := privVal.Signer.Sign(testProposal.SignBytes("test_chain_id"))
if err != nil {
b.Error(err)
}
@ -88,12 +89,12 @@ func BenchmarkProposalSign(b *testing.B) {
}
func BenchmarkProposalVerifySignature(b *testing.B) {
signBytes := SignBytes("test_chain_id", testProposal)
signBytes := testProposal.SignBytes("test_chain_id")
privVal := GenPrivValidatorFS("")
signature, _ := privVal.Signer.Sign(signBytes)
pubKey := privVal.GetPubKey()
for i := 0; i < b.N; i++ {
pubKey.VerifyBytes(SignBytes("test_chain_id", testProposal), signature)
pubKey.VerifyBytes(testProposal.SignBytes("test_chain_id"), signature)
}
}

+ 8
- 4
types/results.go View File

@ -2,7 +2,7 @@ package types
import (
abci "github.com/tendermint/abci/types"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
"github.com/tendermint/tmlibs/merkle"
)
@ -18,7 +18,7 @@ type ABCIResult struct {
// Hash returns the canonical hash of the ABCIResult
func (a ABCIResult) Hash() []byte {
return wire.BinaryRipemd160(a)
return tmHash(a)
}
// ABCIResults wraps the deliver tx results to return a proof
@ -40,9 +40,13 @@ func NewResultFromResponse(response *abci.ResponseDeliverTx) ABCIResult {
}
}
// Bytes serializes the ABCIResponse using go-wire
// Bytes serializes the ABCIResponse using wire
func (a ABCIResults) Bytes() []byte {
return wire.BinaryBytes(a)
bz, err := wire.MarshalBinary(a)
if err != nil {
panic(err)
}
return bz
}
// Hash returns a merkle hash of all results


+ 8
- 16
types/signable.go View File

@ -1,24 +1,16 @@
package types
import (
"bytes"
"io"
cmn "github.com/tendermint/tmlibs/common"
)
// Signable is an interface for all signable things.
// It typically removes signatures before serializing.
// SignBytes returns the bytes to be signed
// NOTE: chainIDs are part of the SignBytes but not
// necessarily the object themselves.
// NOTE: Expected to panic if there is an error marshalling.
type Signable interface {
WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
SignBytes(chainID string) []byte
}
// SignBytes is a convenience method for getting the bytes to sign of a Signable.
func SignBytes(chainID string, o Signable) []byte {
buf, n, err := new(bytes.Buffer), new(int), new(error)
o.WriteSignBytes(chainID, buf, n, err)
if *err != nil {
cmn.PanicCrisis(err)
}
return buf.Bytes()
// HashSignBytes is a convenience method for getting the hash of the bytes of a signable
func HashSignBytes(chainID string, o Signable) []byte {
return tmHash(o.SignBytes(chainID))
}

+ 1
- 1
types/test_util.go View File

@ -29,7 +29,7 @@ func MakeCommit(blockID BlockID, height int64, round int,
}
func signAddVote(privVal *PrivValidatorFS, vote *Vote, voteSet *VoteSet) (signed bool, err error) {
vote.Signature, err = privVal.Signer.Sign(SignBytes(voteSet.ChainID(), vote))
vote.Signature, err = privVal.Signer.Sign(vote.SignBytes(voteSet.ChainID()))
if err != nil {
return false, err
}


+ 2
- 2
types/tx.go View File

@ -11,12 +11,12 @@ import (
)
// Tx is an arbitrary byte array.
// NOTE: Tx has no types at this level, so when go-wire encoded it's just length-prefixed.
// NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
// Alternatively, it may make sense to add types here and let
// []byte be type 0x1 so we can have versioned txs if need be in the future.
type Tx []byte
// Hash computes the RIPEMD160 hash of the go-wire encoded transaction.
// Hash computes the RIPEMD160 hash of the wire encoded transaction.
func (tx Tx) Hash() []byte {
return wireHasher(tx).Hash()
}


+ 7
- 5
types/tx_test.go View File

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
ctest "github.com/tendermint/tmlibs/test"
)
@ -69,8 +69,9 @@ func TestValidTxProof(t *testing.T) {
// read-write must also work
var p2 TxProof
bin := wire.BinaryBytes(proof)
err := wire.ReadBinaryBytes(bin, &p2)
bin, err := wire.MarshalBinary(proof)
assert.Nil(err)
err = wire.UnmarshalBinary(bin, &p2)
if assert.Nil(err, "%d: %d: %+v", h, i, err) {
assert.Nil(p2.Validate(root), "%d: %d", h, i)
}
@ -96,7 +97,8 @@ func testTxProofUnchangable(t *testing.T) {
// make sure it is valid to start with
assert.Nil(proof.Validate(root))
bin := wire.BinaryBytes(proof)
bin, err := wire.MarshalBinary(proof)
assert.Nil(err)
// try mutating the data and make sure nothing breaks
for j := 0; j < 500; j++ {
@ -110,7 +112,7 @@ func testTxProofUnchangable(t *testing.T) {
// this make sure the proof doesn't deserialize into something valid
func assertBadProof(t *testing.T, root []byte, bad []byte, good TxProof) {
var proof TxProof
err := wire.ReadBinaryBytes(bad, &proof)
err := wire.UnmarshalBinary(bad, &proof)
if err == nil {
err = proof.Validate(root)
if err == nil {


+ 4
- 25
types/validator.go View File

@ -3,10 +3,8 @@ package types
import (
"bytes"
"fmt"
"io"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
cmn "github.com/tendermint/tmlibs/common"
)
@ -14,9 +12,9 @@ import (
// NOTE: The Accum is not included in Validator.Hash();
// make sure to update that method if changes are made here
type Validator struct {
Address Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
VotingPower int64 `json:"voting_power"`
Address Address `json:"address"`
PubKey crypto.PubKey `json:"pub_key"`
VotingPower int64 `json:"voting_power"`
Accum int64 `json:"accum"`
}
@ -72,7 +70,7 @@ func (v *Validator) String() string {
// Hash computes the unique ID of a validator with a given voting power.
// It excludes the Accum value, which changes with every round.
func (v *Validator) Hash() []byte {
return wire.BinaryRipemd160(struct {
return tmHash(struct {
Address Address
PubKey crypto.PubKey
VotingPower int64
@ -83,25 +81,6 @@ func (v *Validator) Hash() []byte {
})
}
//-------------------------------------
var ValidatorCodec = validatorCodec{}
type validatorCodec struct{}
func (vc validatorCodec) Encode(o interface{}, w io.Writer, n *int, err *error) {
wire.WriteBinary(o.(*Validator), w, n, err)
}
func (vc validatorCodec) Decode(r io.Reader, n *int, err *error) interface{} {
return wire.ReadBinary(&Validator{}, r, 0, n, err)
}
func (vc validatorCodec) Compare(o1 interface{}, o2 interface{}) int {
cmn.PanicSanity("ValidatorCodec.Compare not implemented")
return 0
}
//--------------------------------------------------------------------------------
// For testing...


+ 2
- 2
types/validator_set.go View File

@ -253,7 +253,7 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
}
_, val := valSet.GetByIndex(idx)
// Validate signature
precommitSignBytes := SignBytes(chainID, precommit)
precommitSignBytes := precommit.SignBytes(chainID)
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
}
@ -327,7 +327,7 @@ func (valSet *ValidatorSet) VerifyCommitAny(newSet *ValidatorSet, chainID string
seen[vi] = true
// Validate signature old school
precommitSignBytes := SignBytes(chainID, precommit)
precommitSignBytes := precommit.SignBytes(chainID)
if !ov.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
return errors.Errorf("Invalid commit -- invalid signature: %v", precommit)
}


+ 114
- 52
types/validator_set_test.go View File

@ -6,33 +6,15 @@ import (
"strings"
"testing"
"testing/quick"
"time"
"github.com/stretchr/testify/assert"
crypto "github.com/tendermint/go-crypto"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
)
func randPubKey() crypto.PubKey {
var pubKey [32]byte
copy(pubKey[:], cmn.RandBytes(32))
return crypto.PubKeyEd25519(pubKey).Wrap()
}
func randValidator_() *Validator {
val := NewValidator(randPubKey(), cmn.RandInt64())
val.Accum = cmn.RandInt64()
return val
}
func randValidatorSet(numValidators int) *ValidatorSet {
validators := make([]*Validator, numValidators)
for i := 0; i < numValidators; i++ {
validators[i] = randValidator_()
}
return NewValidatorSet(validators)
}
func TestCopy(t *testing.T) {
vset := randValidatorSet(10)
vsetHash := vset.Hash()
@ -48,6 +30,26 @@ func TestCopy(t *testing.T) {
}
}
func BenchmarkValidatorSetCopy(b *testing.B) {
b.StopTimer()
vset := NewValidatorSet([]*Validator{})
for i := 0; i < 1000; i++ {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
val := NewValidator(pubKey, 0)
if !vset.Add(val) {
panic("Failed to add validator")
}
}
b.StartTimer()
for i := 0; i < b.N; i++ {
vset.Copy()
}
}
//-------------------------------------------------------------------
func TestProposerSelection1(t *testing.T) {
vset := NewValidatorSet([]*Validator{
newValidator([]byte("foo"), 1000),
@ -66,10 +68,6 @@ func TestProposerSelection1(t *testing.T) {
}
}
func newValidator(address []byte, power int64) *Validator {
return &Validator{Address: address, VotingPower: power}
}
func TestProposerSelection2(t *testing.T) {
addr0 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
addr1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
@ -193,6 +191,48 @@ func TestProposerSelection3(t *testing.T) {
}
}
func newValidator(address []byte, power int64) *Validator {
return &Validator{Address: address, VotingPower: power}
}
func randPubKey() crypto.PubKey {
var pubKey [32]byte
copy(pubKey[:], cmn.RandBytes(32))
return crypto.PubKeyEd25519(pubKey).Wrap()
}
func randValidator_() *Validator {
val := NewValidator(randPubKey(), cmn.RandInt64())
val.Accum = cmn.RandInt64()
return val
}
func randValidatorSet(numValidators int) *ValidatorSet {
validators := make([]*Validator, numValidators)
for i := 0; i < numValidators; i++ {
validators[i] = randValidator_()
}
return NewValidatorSet(validators)
}
func (valSet *ValidatorSet) toBytes() []byte {
bz, err := wire.MarshalBinary(valSet)
if err != nil {
panic(err)
}
return bz
}
func (valSet *ValidatorSet) fromBytes(b []byte) {
err := wire.UnmarshalBinary(b, &valSet)
if err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
panic(err)
}
}
//-------------------------------------------------------------------
func TestValidatorSetTotalVotingPowerOverflows(t *testing.T) {
vset := NewValidatorSet([]*Validator{
{Address: []byte("a"), VotingPower: math.MaxInt64, Accum: 0},
@ -272,38 +312,60 @@ func TestSafeSubClip(t *testing.T) {
assert.EqualValues(t, math.MaxInt64, safeSubClip(math.MaxInt64, -10))
}
func BenchmarkValidatorSetCopy(b *testing.B) {
b.StopTimer()
vset := NewValidatorSet([]*Validator{})
for i := 0; i < 1000; i++ {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
val := NewValidator(pubKey, 0)
if !vset.Add(val) {
panic("Failed to add validator")
}
//-------------------------------------------------------------------
func TestValidatorSetVerifyCommit(t *testing.T) {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
v1 := NewValidator(pubKey, 1000)
vset := NewValidatorSet([]*Validator{v1})
chainID := "mychainID"
blockID := BlockID{Hash: []byte("hello")}
height := int64(5)
vote := &Vote{
ValidatorAddress: v1.Address,
ValidatorIndex: 0,
Height: height,
Round: 0,
Timestamp: time.Now().UTC(),
Type: VoteTypePrecommit,
BlockID: blockID,
}
vote.Signature = privKey.Sign(vote.SignBytes(chainID))
commit := &Commit{
BlockID: blockID,
Precommits: []*Vote{vote},
}
b.StartTimer()
for i := 0; i < b.N; i++ {
vset.Copy()
badChainID := "notmychainID"
badBlockID := BlockID{Hash: []byte("goodbye")}
badHeight := height + 1
badCommit := &Commit{
BlockID: blockID,
Precommits: []*Vote{nil},
}
}
func (valSet *ValidatorSet) toBytes() []byte {
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(valSet, buf, n, err)
if *err != nil {
cmn.PanicCrisis(*err)
// test some error cases
// TODO: test more cases!
cases := []struct {
chainID string
blockID BlockID
height int64
commit *Commit
}{
{badChainID, blockID, height, commit},
{chainID, badBlockID, height, commit},
{chainID, blockID, badHeight, commit},
{chainID, blockID, height, badCommit},
}
return buf.Bytes()
}
func (valSet *ValidatorSet) fromBytes(b []byte) {
r, n, err := bytes.NewReader(b), new(int), new(error)
wire.ReadBinary(valSet, r, 0, n, err)
if *err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
cmn.PanicCrisis(*err)
for i, c := range cases {
err := vset.VerifyCommit(c.chainID, c.blockID, c.height, c.commit)
assert.NotNil(t, err, i)
}
// test a good one
err := vset.VerifyCommit(chainID, blockID, height, commit)
assert.Nil(t, err)
}

+ 9
- 6
types/vote.go View File

@ -4,11 +4,10 @@ import (
"bytes"
"errors"
"fmt"
"io"
"time"
"github.com/tendermint/go-crypto"
"github.com/tendermint/go-wire"
"github.com/tendermint/tendermint/wire"
cmn "github.com/tendermint/tmlibs/common"
)
@ -73,11 +72,15 @@ type Vote struct {
Signature crypto.Signature `json:"signature"`
}
func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
wire.WriteJSON(CanonicalJSONOnceVote{
func (vote *Vote) SignBytes(chainID string) []byte {
bz, err := wire.MarshalJSON(CanonicalJSONOnceVote{
chainID,
CanonicalVote(vote),
}, w, n, err)
})
if err != nil {
panic(err)
}
return bz
}
func (vote *Vote) Copy() *Vote {
@ -111,7 +114,7 @@ func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
return ErrVoteInvalidValidatorAddress
}
if !pubKey.VerifyBytes(SignBytes(chainID, vote), vote.Signature) {
if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
return ErrVoteInvalidSignature
}
return nil


+ 9
- 4
types/vote_set.go View File

@ -8,10 +8,15 @@ import (
"github.com/pkg/errors"
"github.com/tendermint/tendermint/p2p"
cmn "github.com/tendermint/tmlibs/common"
)
// UNSTABLE
// XXX: duplicate of p2p.ID to avoid dependence between packages.
// Perhaps we can have a minimal types package containing this (and other things?)
// that both `types` and `p2p` import ?
type P2PID string
/*
VoteSet helps collect signatures from validators at each height+round for a
predefined vote type.
@ -59,7 +64,7 @@ type VoteSet struct {
sum int64 // Sum of voting power for seen votes, discounting conflicts
maj23 *BlockID // First 2/3 majority seen
votesByBlock map[string]*blockVotes // string(blockHash|blockParts) -> blockVotes
peerMaj23s map[p2p.ID]BlockID // Maj23 for each peer
peerMaj23s map[P2PID]BlockID // Maj23 for each peer
}
// Constructs a new VoteSet struct used to accumulate votes for given height/round.
@ -78,7 +83,7 @@ func NewVoteSet(chainID string, height int64, round int, type_ byte, valSet *Val
sum: 0,
maj23: nil,
votesByBlock: make(map[string]*blockVotes, valSet.Size()),
peerMaj23s: make(map[p2p.ID]BlockID),
peerMaj23s: make(map[P2PID]BlockID),
}
}
@ -291,7 +296,7 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower
// this can cause memory issues.
// TODO: implement ability to remove peers too
// NOTE: VoteSet must not be nil
func (voteSet *VoteSet) SetPeerMaj23(peerID p2p.ID, blockID BlockID) error {
func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
if voteSet == nil {
cmn.PanicSanity("SetPeerMaj23() on nil VoteSet")
}


+ 8
- 7
types/vote_test.go View File

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require"
wire "github.com/tendermint/go-wire"
wire "github.com/tendermint/tendermint/wire"
)
func examplePrevote() *Vote {
@ -42,7 +42,7 @@ func exampleVote(t byte) *Vote {
func TestVoteSignable(t *testing.T) {
vote := examplePrecommit()
signBytes := SignBytes("test_chain_id", vote)
signBytes := vote.SignBytes("test_chain_id")
signStr := string(signBytes)
expected := `{"chain_id":"test_chain_id","vote":{"block_id":{"hash":"68617368","parts":{"hash":"70617274735F68617368","total":1000000}},"height":12345,"round":2,"timestamp":"2017-12-25T03:00:01.234Z","type":2}}`
@ -77,24 +77,25 @@ func TestVoteVerifySignature(t *testing.T) {
pubKey := privVal.GetPubKey()
vote := examplePrecommit()
signBytes := SignBytes("test_chain_id", vote)
signBytes := vote.SignBytes("test_chain_id")
// sign it
signature, err := privVal.Signer.Sign(signBytes)
require.NoError(t, err)
// verify the same vote
valid := pubKey.VerifyBytes(SignBytes("test_chain_id", vote), signature)
valid := pubKey.VerifyBytes(vote.SignBytes("test_chain_id"), signature)
require.True(t, valid)
// serialize, deserialize and verify again....
precommit := new(Vote)
bs := wire.BinaryBytes(vote)
err = wire.ReadBinaryBytes(bs, &precommit)
bs, err := wire.MarshalBinary(vote)
require.NoError(t, err)
err = wire.UnmarshalBinary(bs, &precommit)
require.NoError(t, err)
// verify the transmitted vote
newSignBytes := SignBytes("test_chain_id", precommit)
newSignBytes := precommit.SignBytes("test_chain_id")
require.Equal(t, string(signBytes), string(newSignBytes))
valid = pubKey.VerifyBytes(newSignBytes, signature)
require.True(t, valid)


+ 60
- 0
wire/wire.go View File

@ -0,0 +1,60 @@
package wire
import (
"github.com/tendermint/go-wire"
)
/*
// Expose access to a global wire codec
// TODO: maybe introduce some Context object
// containing logger, config, codec that can
// be threaded through everything to avoid this global
var cdc *wire.Codec
func init() {
cdc = wire.NewCodec()
crypto.RegisterWire(cdc)
}
*/
// Just a flow through to go-wire.
// To be used later for the global codec
func MarshalBinary(o interface{}) ([]byte, error) {
return wire.MarshalBinary(o)
}
func UnmarshalBinary(bz []byte, ptr interface{}) error {
return wire.UnmarshalBinary(bz, ptr)
}
func MarshalJSON(o interface{}) ([]byte, error) {
return wire.MarshalJSON(o)
}
func UnmarshalJSON(jsonBz []byte, ptr interface{}) error {
return wire.UnmarshalJSON(jsonBz, ptr)
}
type ConcreteType = wire.ConcreteType
func RegisterInterface(o interface{}, ctypes ...ConcreteType) *wire.TypeInfo {
return wire.RegisterInterface(o, ctypes...)
}
const RFC3339Millis = wire.RFC3339Millis
/*
func RegisterInterface(ptr interface{}, opts *wire.InterfaceOptions) {
cdc.RegisterInterface(ptr, opts)
}
func RegisterConcrete(o interface{}, name string, opts *wire.ConcreteOptions) {
cdc.RegisterConcrete(o, name, opts)
}
//-------------------------------
const RFC3339Millis = wire.RFC3339Millis
*/

Loading…
Cancel
Save