Browse Source

Merge pull request #1936 from tendermint/693-ensure-types-are-covered

Ensure all funcs in types pkg are well guarded (Part 1)
pull/1975/head
Ethan Buchman 6 years ago
committed by GitHub
parent
commit
789666ef78
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 569 additions and 195 deletions
  1. +6
    -0
      CHANGELOG.md
  2. +1
    -1
      consensus/replay.go
  3. +3
    -3
      libs/pubsub/query/Makefile
  4. +2
    -0
      libs/pubsub/query/query.peg.go
  5. +4
    -5
      scripts/wire2amino.go
  6. +5
    -1
      types/block.go
  7. +130
    -1
      types/block_test.go
  8. +0
    -50
      types/event_buffer.go
  9. +0
    -21
      types/event_buffer_test.go
  10. +61
    -11
      types/event_bus_test.go
  11. +0
    -10
      types/events.go
  12. +23
    -0
      types/events_test.go
  13. +1
    -1
      types/evidence.go
  14. +28
    -1
      types/evidence_test.go
  15. +1
    -11
      types/genesis.go
  16. +45
    -0
      types/genesis_test.go
  17. +57
    -0
      types/params_test.go
  18. +25
    -30
      types/part_set_test.go
  19. +1
    -1
      types/protobuf.go
  20. +51
    -0
      types/protobuf_test.go
  21. +5
    -4
      types/results.go
  22. +12
    -0
      types/results_test.go
  23. +28
    -19
      types/tx_test.go
  24. +3
    -2
      types/validator_set.go
  25. +54
    -0
      types/validator_set_test.go
  26. +23
    -23
      types/vote_test.go

+ 6
- 0
CHANGELOG.md View File

@ -1,5 +1,11 @@
# Changelog
## TBD
IMPROVEMENTS:
- [genesis] removed deprecated `app_options` field.
- [types] Genesis.AppStateJSON -> Genesis.AppState
## 0.22.3
IMPROVEMENTS


+ 1
- 1
consensus/replay.go View File

@ -273,7 +273,7 @@ func (h *Handshaker) ReplayBlocks(state sm.State, appHash []byte, appBlockHeight
ChainId: h.genDoc.ChainID,
ConsensusParams: csParams,
Validators: validators,
AppStateBytes: h.genDoc.AppStateJSON,
AppStateBytes: h.genDoc.AppState,
}
res, err := proxyApp.Consensus().InitChainSync(req)
if err != nil {


+ 3
- 3
libs/pubsub/query/Makefile View File

@ -1,10 +1,10 @@
gen_query_parser:
@go get github.com/pointlander/peg
go get -u -v github.com/pointlander/peg
peg -inline -switch query.peg
fuzzy_test:
@go get github.com/dvyukov/go-fuzz/go-fuzz
@go get github.com/dvyukov/go-fuzz/go-fuzz-build
go get -u -v github.com/dvyukov/go-fuzz/go-fuzz
go get -u -v github.com/dvyukov/go-fuzz/go-fuzz-build
go-fuzz-build github.com/tendermint/tendermint/libs/pubsub/query/fuzz_test
go-fuzz -bin=./fuzz_test-fuzz.zip -workdir=./fuzz_test/output


+ 2
- 0
libs/pubsub/query/query.peg.go View File

@ -1,6 +1,8 @@
// nolint
package query
//go:generate peg -inline -switch query.peg
import (
"fmt"
"math"


+ 4
- 5
scripts/wire2amino.go View File

@ -29,9 +29,8 @@ type Genesis struct {
ConsensusParams *types.ConsensusParams `json:"consensus_params,omitempty"`
Validators []GenesisValidator `json:"validators"`
AppHash cmn.HexBytes `json:"app_hash"`
AppStateJSON json.RawMessage `json:"app_state,omitempty"`
AppState json.RawMessage `json:"app_state,omitempty"`
AppOptions json.RawMessage `json:"app_options,omitempty"` // DEPRECATED
}
type NodeKey struct {
@ -112,12 +111,12 @@ func convertGenesis(cdc *amino.Codec, jsonBytes []byte) ([]byte, error) {
ChainID: genesis.ChainID,
ConsensusParams: genesis.ConsensusParams,
// Validators
AppHash: genesis.AppHash,
AppStateJSON: genesis.AppStateJSON,
AppHash: genesis.AppHash,
AppState: genesis.AppState,
}
if genesis.AppOptions != nil {
genesisNew.AppStateJSON = genesis.AppOptions
genesisNew.AppState = genesis.AppOptions
}
for _, v := range genesis.Validators {


+ 5
- 1
types/block.go View File

@ -107,6 +107,7 @@ 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.
// CONTRACT: partSize is greater than zero.
func (b *Block) MakePartSet(partSize int) *PartSet {
if b == nil {
return nil
@ -208,7 +209,7 @@ type Header struct {
// Hash returns the hash of the header.
// Returns nil if ValidatorHash is missing,
// since a Header is not valid unless there is
// a ValidaotrsHash (corresponding to the validator set).
// a ValidatorsHash (corresponding to the validator set).
func (h *Header) Hash() cmn.HexBytes {
if h == nil || len(h.ValidatorsHash) == 0 {
return nil
@ -392,6 +393,9 @@ func (commit *Commit) ValidateBasic() error {
// Hash returns the hash of the commit
func (commit *Commit) Hash() cmn.HexBytes {
if commit == nil {
return nil
}
if commit.hash == nil {
bs := make([]merkle.Hasher, len(commit.Precommits))
for i, precommit := range commit.Precommits {


+ 130
- 1
types/block_test.go View File

@ -10,7 +10,25 @@ import (
cmn "github.com/tendermint/tendermint/libs/common"
)
func TestValidateBlock(t *testing.T) {
func TestBlockAddEvidence(t *testing.T) {
txs := []Tx{Tx("foo"), Tx("bar")}
lastID := makeBlockIDRandom()
h := int64(3)
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
require.NoError(t, err)
block := MakeBlock(h, txs, commit)
require.NotNil(t, block)
ev := NewMockGoodEvidence(h, 0, valSet.Validators[0].Address)
block.AddEvidence([]Evidence{ev})
}
func TestBlockValidateBasic(t *testing.T) {
require.Error(t, (*Block)(nil).ValidateBasic())
txs := []Tx{Tx("foo"), Tx("bar")}
lastID := makeBlockIDRandom()
h := int64(3)
@ -57,6 +75,59 @@ func TestValidateBlock(t *testing.T) {
block.DataHash = cmn.RandBytes(len(block.DataHash))
err = block.ValidateBasic()
require.Error(t, err)
// tamper with evidence
block = MakeBlock(h, txs, commit)
block.EvidenceHash = []byte("something else")
err = block.ValidateBasic()
require.Error(t, err)
}
func TestBlockHash(t *testing.T) {
assert.Nil(t, (*Block)(nil).Hash())
assert.Nil(t, MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil).Hash())
}
func TestBlockMakePartSet(t *testing.T) {
assert.Nil(t, (*Block)(nil).MakePartSet(2))
partSet := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil).MakePartSet(1024)
assert.NotNil(t, partSet)
assert.Equal(t, 1, partSet.Total())
}
func TestBlockHashesTo(t *testing.T) {
assert.False(t, (*Block)(nil).HashesTo(nil))
lastID := makeBlockIDRandom()
h := int64(3)
voteSet, valSet, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
require.NoError(t, err)
block := MakeBlock(h, []Tx{Tx("Hello World")}, commit)
block.ValidatorsHash = valSet.Hash()
assert.False(t, block.HashesTo([]byte{}))
assert.False(t, block.HashesTo([]byte("something else")))
assert.True(t, block.HashesTo(block.Hash()))
}
func TestBlockSize(t *testing.T) {
size := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil).Size()
if size <= 0 {
t.Fatal("Size of the block is zero or negative")
}
}
func TestBlockString(t *testing.T) {
assert.Equal(t, "nil-Block", (*Block)(nil).String())
assert.Equal(t, "nil-Block", (*Block)(nil).StringIndented(""))
assert.Equal(t, "nil-Block", (*Block)(nil).StringShort())
block := MakeBlock(int64(3), []Tx{Tx("Hello World")}, nil)
assert.NotEqual(t, "nil-Block", block.String())
assert.NotEqual(t, "nil-Block", block.StringIndented(""))
assert.NotEqual(t, "nil-Block", block.StringShort())
}
func makeBlockIDRandom() BlockID {
@ -86,3 +157,61 @@ func TestNilDataHashDoesntCrash(t *testing.T) {
assert.Equal(t, []byte((*Data)(nil).Hash()), nilBytes)
assert.Equal(t, []byte(new(Data).Hash()), nilBytes)
}
func TestCommit(t *testing.T) {
lastID := makeBlockIDRandom()
h := int64(3)
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
require.NoError(t, err)
assert.NotNil(t, commit.FirstPrecommit())
assert.Equal(t, h-1, commit.Height())
assert.Equal(t, 1, commit.Round())
assert.Equal(t, VoteTypePrecommit, commit.Type())
if commit.Size() <= 0 {
t.Fatalf("commit %v has a zero or negative size: %d", commit, commit.Size())
}
require.NotNil(t, commit.BitArray())
assert.Equal(t, cmn.NewBitArray(10).Size(), commit.BitArray().Size())
assert.Equal(t, voteSet.GetByIndex(0), commit.GetByIndex(0))
assert.True(t, commit.IsCommit())
}
func TestCommitValidateBasic(t *testing.T) {
commit := randCommit()
assert.NoError(t, commit.ValidateBasic())
// nil precommit is OK
commit = randCommit()
commit.Precommits[0] = nil
assert.NoError(t, commit.ValidateBasic())
// tamper with types
commit = randCommit()
commit.Precommits[0].Type = VoteTypePrevote
assert.Error(t, commit.ValidateBasic())
// tamper with height
commit = randCommit()
commit.Precommits[0].Height = int64(100)
assert.Error(t, commit.ValidateBasic())
// tamper with round
commit = randCommit()
commit.Precommits[0].Round = 100
assert.Error(t, commit.ValidateBasic())
}
func randCommit() *Commit {
lastID := makeBlockIDRandom()
h := int64(3)
voteSet, _, vals := randVoteSet(h-1, 1, VoteTypePrecommit, 10, 1)
commit, err := MakeCommit(lastID, h-1, 1, voteSet, vals)
if err != nil {
panic(err)
}
return commit
}

+ 0
- 50
types/event_buffer.go View File

@ -1,50 +0,0 @@
package types
// Interface assertions
var _ TxEventPublisher = (*TxEventBuffer)(nil)
// TxEventBuffer is a buffer of events, which uses a slice to temporarily store
// events.
type TxEventBuffer struct {
next TxEventPublisher
capacity int
events []EventDataTx
}
// NewTxEventBuffer accepts a TxEventPublisher and returns a new buffer with the given
// capacity.
func NewTxEventBuffer(next TxEventPublisher, capacity int) *TxEventBuffer {
return &TxEventBuffer{
next: next,
capacity: capacity,
events: make([]EventDataTx, 0, capacity),
}
}
// Len returns the number of events cached.
func (b TxEventBuffer) Len() int {
return len(b.events)
}
// PublishEventTx buffers an event to be fired upon finality.
func (b *TxEventBuffer) PublishEventTx(e EventDataTx) error {
b.events = append(b.events, e)
return nil
}
// Flush publishes events by running next.PublishWithTags on all cached events.
// Blocks. Clears cached events.
func (b *TxEventBuffer) Flush() error {
for _, e := range b.events {
err := b.next.PublishEventTx(e)
if err != nil {
return err
}
}
// Clear out the elements and set the length to 0
// but maintain the underlying slice's capacity.
// See Issue https://github.com/tendermint/tendermint/issues/1189
b.events = b.events[:0]
return nil
}

+ 0
- 21
types/event_buffer_test.go View File

@ -1,21 +0,0 @@
package types
import (
"testing"
"github.com/stretchr/testify/assert"
)
type eventBusMock struct{}
func (eventBusMock) PublishEventTx(e EventDataTx) error {
return nil
}
func TestEventBuffer(t *testing.T) {
b := NewTxEventBuffer(eventBusMock{}, 1)
b.PublishEventTx(EventDataTx{})
assert.Equal(t, 1, b.Len())
b.Flush()
assert.Equal(t, 0, b.Len())
}

+ 61
- 11
types/event_bus_test.go View File

@ -11,9 +11,9 @@ import (
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
tmquery "github.com/tendermint/tendermint/libs/pubsub/query"
cmn "github.com/tendermint/tendermint/libs/common"
)
func TestEventBusPublishEventTx(t *testing.T) {
@ -59,6 +59,64 @@ func TestEventBusPublishEventTx(t *testing.T) {
}
}
func TestEventBusPublish(t *testing.T) {
eventBus := NewEventBus()
err := eventBus.Start()
require.NoError(t, err)
defer eventBus.Stop()
eventsCh := make(chan interface{})
err = eventBus.Subscribe(context.Background(), "test", tmquery.Empty{}, eventsCh)
require.NoError(t, err)
const numEventsExpected = 14
done := make(chan struct{})
go func() {
numEvents := 0
for range eventsCh {
numEvents++
if numEvents >= numEventsExpected {
close(done)
}
}
}()
err = eventBus.Publish(EventNewBlockHeader, EventDataNewBlockHeader{})
require.NoError(t, err)
err = eventBus.PublishEventNewBlock(EventDataNewBlock{})
require.NoError(t, err)
err = eventBus.PublishEventNewBlockHeader(EventDataNewBlockHeader{})
require.NoError(t, err)
err = eventBus.PublishEventVote(EventDataVote{})
require.NoError(t, err)
err = eventBus.PublishEventProposalHeartbeat(EventDataProposalHeartbeat{})
require.NoError(t, err)
err = eventBus.PublishEventNewRoundStep(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventTimeoutPropose(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventTimeoutWait(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventNewRound(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventCompleteProposal(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventPolka(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventUnlock(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventRelock(EventDataRoundState{})
require.NoError(t, err)
err = eventBus.PublishEventLock(EventDataRoundState{})
require.NoError(t, err)
select {
case <-done:
case <-time.After(1 * time.Second):
t.Fatalf("expected to receive %d events after 1 sec.", numEventsExpected)
}
}
func BenchmarkEventBus(b *testing.B) {
benchmarks := []struct {
name string
@ -126,11 +184,7 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
}
}
var events = []string{EventBond,
EventUnbond,
EventRebond,
EventDupeout,
EventFork,
var events = []string{
EventNewBlock,
EventNewBlockHeader,
EventNewRound,
@ -148,11 +202,7 @@ func randEvent() string {
return events[rand.Intn(len(events))]
}
var queries = []tmpubsub.Query{EventQueryBond,
EventQueryUnbond,
EventQueryRebond,
EventQueryDupeout,
EventQueryFork,
var queries = []tmpubsub.Query{
EventQueryNewBlock,
EventQueryNewBlockHeader,
EventQueryNewRound,


+ 0
- 10
types/events.go View File

@ -10,22 +10,17 @@ import (
// Reserved event types
const (
EventBond = "Bond"
EventCompleteProposal = "CompleteProposal"
EventDupeout = "Dupeout"
EventFork = "Fork"
EventLock = "Lock"
EventNewBlock = "NewBlock"
EventNewBlockHeader = "NewBlockHeader"
EventNewRound = "NewRound"
EventNewRoundStep = "NewRoundStep"
EventPolka = "Polka"
EventRebond = "Rebond"
EventRelock = "Relock"
EventTimeoutPropose = "TimeoutPropose"
EventTimeoutWait = "TimeoutWait"
EventTx = "Tx"
EventUnbond = "Unbond"
EventUnlock = "Unlock"
EventVote = "Vote"
EventProposalHeartbeat = "ProposalHeartbeat"
@ -113,11 +108,6 @@ const (
)
var (
EventQueryBond = QueryForEvent(EventBond)
EventQueryUnbond = QueryForEvent(EventUnbond)
EventQueryRebond = QueryForEvent(EventRebond)
EventQueryDupeout = QueryForEvent(EventDupeout)
EventQueryFork = QueryForEvent(EventFork)
EventQueryNewBlock = QueryForEvent(EventNewBlock)
EventQueryNewBlockHeader = QueryForEvent(EventNewBlockHeader)
EventQueryNewRound = QueryForEvent(EventNewRound)


+ 23
- 0
types/events_test.go View File

@ -0,0 +1,23 @@
package types
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestQueryTxFor(t *testing.T) {
tx := Tx("foo")
assert.Equal(t,
fmt.Sprintf("tm.event='Tx' AND tx.hash='%X'", tx.Hash()),
EventQueryTxFor(tx).String(),
)
}
func TestQueryForEvent(t *testing.T) {
assert.Equal(t,
"tm.event='NewBlock'",
QueryForEvent(EventNewBlock).String(),
)
}

+ 1
- 1
types/evidence.go View File

@ -4,7 +4,7 @@ import (
"bytes"
"fmt"
"github.com/tendermint/go-amino"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/merkle"


+ 28
- 1
types/evidence_test.go View File

@ -36,7 +36,7 @@ func TestEvidence(t *testing.T) {
blockID3 := makeBlockID("blockhash", 10000, "partshash")
blockID4 := makeBlockID("blockhash", 10000, "partshash2")
chainID := "mychain"
const chainID = "mychain"
vote1 := makeVote(val, chainID, 0, 10, 2, 1, blockID)
badVote := makeVote(val, chainID, 0, 10, 2, 1, blockID)
@ -72,3 +72,30 @@ func TestEvidence(t *testing.T) {
}
}
}
func TestDuplicatedVoteEvidence(t *testing.T) {
ev := randomDuplicatedVoteEvidence()
assert.True(t, ev.Equal(ev))
assert.False(t, ev.Equal(&DuplicateVoteEvidence{}))
}
func TestEvidenceList(t *testing.T) {
ev := randomDuplicatedVoteEvidence()
evl := EvidenceList([]Evidence{ev})
assert.NotNil(t, evl.Hash())
assert.True(t, evl.Has(ev))
assert.False(t, evl.Has(&DuplicateVoteEvidence{}))
}
func randomDuplicatedVoteEvidence() *DuplicateVoteEvidence {
val := NewMockPV()
blockID := makeBlockID("blockhash", 1000, "partshash")
blockID2 := makeBlockID("blockhash2", 1000, "partshash")
const chainID = "mychain"
return &DuplicateVoteEvidence{
VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID),
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
}
}

+ 1
- 11
types/genesis.go View File

@ -26,17 +26,7 @@ type GenesisDoc struct {
ConsensusParams *ConsensusParams `json:"consensus_params,omitempty"`
Validators []GenesisValidator `json:"validators"`
AppHash cmn.HexBytes `json:"app_hash"`
AppStateJSON json.RawMessage `json:"app_state,omitempty"`
AppOptions json.RawMessage `json:"app_options,omitempty"` // DEPRECATED
}
// AppState returns raw application state.
// TODO: replace with AppState field during next breaking release (0.18)
func (genDoc *GenesisDoc) AppState() json.RawMessage {
if len(genDoc.AppOptions) > 0 {
return genDoc.AppOptions
}
return genDoc.AppStateJSON
AppState json.RawMessage `json:"app_state,omitempty"`
}
// SaveAs is a utility method for saving GenensisDoc as a JSON file.


+ 45
- 0
types/genesis_test.go View File

@ -1,9 +1,13 @@
package types
import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
)
@ -59,3 +63,44 @@ func TestGenesisGood(t *testing.T) {
genDoc, err = GenesisDocFromJSON(genDocBytes)
assert.Error(t, err, "expected error for genDoc json with block size of 0")
}
func TestGenesisSaveAs(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "genesis")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
genDoc := randomGenesisDoc()
// save
genDoc.SaveAs(tmpfile.Name())
stat, err := tmpfile.Stat()
require.NoError(t, err)
if err != nil && stat.Size() <= 0 {
t.Fatalf("SaveAs failed to write any bytes to %v", tmpfile.Name())
}
err = tmpfile.Close()
require.NoError(t, err)
// load
genDoc2, err := GenesisDocFromFile(tmpfile.Name())
require.NoError(t, err)
// fails to unknown reason
// assert.EqualValues(t, genDoc2, genDoc)
assert.Equal(t, genDoc2.Validators, genDoc.Validators)
}
func TestGenesisValidatorHash(t *testing.T) {
genDoc := randomGenesisDoc()
assert.NotEmpty(t, genDoc.ValidatorHash())
}
func randomGenesisDoc() *GenesisDoc {
return &GenesisDoc{
GenesisTime: time.Now().UTC(),
ChainID: "abc",
Validators: []GenesisValidator{{crypto.GenPrivKeyEd25519().PubKey(), 10, "myval"}},
ConsensusParams: DefaultConsensusParams(),
}
}

+ 57
- 0
types/params_test.go View File

@ -6,6 +6,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
abci "github.com/tendermint/tendermint/abci/types"
)
func newConsensusParams(blockSize, partSize int) ConsensusParams {
@ -86,3 +87,59 @@ func TestConsensusParamsHash(t *testing.T) {
assert.NotEqual(t, hashes[i], hashes[i+1])
}
}
func TestConsensusParamsUpdate(t *testing.T) {
testCases := []struct {
params ConsensusParams
updates *abci.ConsensusParams
updatedParams ConsensusParams
}{
// empty updates
{
makeParams(1, 2, 3, 4, 5, 6),
&abci.ConsensusParams{},
makeParams(1, 2, 3, 4, 5, 6),
},
// negative BlockPartSizeBytes
{
makeParams(1, 2, 3, 4, 5, 6),
&abci.ConsensusParams{
BlockSize: &abci.BlockSize{
MaxBytes: -100,
MaxTxs: -200,
MaxGas: -300,
},
TxSize: &abci.TxSize{
MaxBytes: -400,
MaxGas: -500,
},
BlockGossip: &abci.BlockGossip{
BlockPartSizeBytes: -600,
},
},
makeParams(1, 2, 3, 4, 5, 6),
},
// fine updates
{
makeParams(1, 2, 3, 4, 5, 6),
&abci.ConsensusParams{
BlockSize: &abci.BlockSize{
MaxBytes: 100,
MaxTxs: 200,
MaxGas: 300,
},
TxSize: &abci.TxSize{
MaxBytes: 400,
MaxGas: 500,
},
BlockGossip: &abci.BlockGossip{
BlockPartSizeBytes: 600,
},
},
makeParams(100, 200, 300, 400, 500, 600),
},
}
for _, tc := range testCases {
assert.Equal(t, tc.updatedParams, tc.params.Update(tc.updates))
}
}

+ 25
- 30
types/part_set_test.go View File

@ -1,10 +1,12 @@
package types
import (
"bytes"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tendermint/libs/common"
)
@ -13,24 +15,21 @@ const (
)
func TestBasicPartSet(t *testing.T) {
// Construct random data of size partSize * 100
data := cmn.RandBytes(testPartSize * 100)
partSet := NewPartSetFromData(data, testPartSize)
if len(partSet.Hash()) == 0 {
t.Error("Expected to get hash")
}
if partSet.Total() != 100 {
t.Errorf("Expected to get 100 parts, but got %v", partSet.Total())
}
if !partSet.IsComplete() {
t.Errorf("PartSet should be complete")
}
assert.NotEmpty(t, partSet.Hash())
assert.Equal(t, 100, partSet.Total())
assert.Equal(t, 100, partSet.BitArray().Size())
assert.True(t, partSet.HashesTo(partSet.Hash()))
assert.True(t, partSet.IsComplete())
assert.Equal(t, 100, partSet.Count())
// Test adding parts to a new partSet.
partSet2 := NewPartSetFromHeader(partSet.Header())
assert.True(t, partSet2.HasHeader(partSet.Header()))
for i := 0; i < partSet.Total(); i++ {
part := partSet.GetPart(i)
//t.Logf("\n%v", part)
@ -39,31 +38,28 @@ func TestBasicPartSet(t *testing.T) {
t.Errorf("Failed to add part %v, error: %v", i, err)
}
}
if !bytes.Equal(partSet.Hash(), partSet2.Hash()) {
t.Error("Expected to get same hash")
}
if partSet2.Total() != 100 {
t.Errorf("Expected to get 100 parts, but got %v", partSet2.Total())
}
if !partSet2.IsComplete() {
t.Errorf("Reconstructed PartSet should be complete")
}
// adding part with invalid index
added, err := partSet2.AddPart(&Part{Index: 10000})
assert.False(t, added)
assert.Error(t, err)
// adding existing part
added, err = partSet2.AddPart(partSet2.GetPart(0))
assert.False(t, added)
assert.Nil(t, err)
assert.Equal(t, partSet.Hash(), partSet2.Hash())
assert.Equal(t, 100, partSet2.Total())
assert.True(t, partSet2.IsComplete())
// Reconstruct data, assert that they are equal.
data2Reader := partSet2.GetReader()
data2, err := ioutil.ReadAll(data2Reader)
if err != nil {
t.Errorf("Error reading data2Reader: %v", err)
}
if !bytes.Equal(data, data2) {
t.Errorf("Got wrong data.")
}
require.NoError(t, err)
assert.Equal(t, data, data2)
}
func TestWrongProof(t *testing.T) {
// Construct random data of size partSize * 100
data := cmn.RandBytes(testPartSize * 100)
partSet := NewPartSetFromData(data, testPartSize)
@ -86,5 +82,4 @@ func TestWrongProof(t *testing.T) {
if added || err == nil {
t.Errorf("Expected to fail adding a part with bad bytes.")
}
}

+ 1
- 1
types/protobuf.go View File

@ -78,7 +78,7 @@ func (tm2pb) PubKey(pubKey crypto.PubKey) abci.PubKey {
// XXX: panics on nil or unknown pubkey type
func (tm2pb) Validators(vals *ValidatorSet) []abci.Validator {
validators := make([]abci.Validator, len(vals.Validators))
validators := make([]abci.Validator, vals.Size())
for i, val := range vals.Validators {
validators[i] = TM2PB.Validator(val)
}


+ 51
- 0
types/protobuf_test.go View File

@ -2,6 +2,7 @@ package types
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
abci "github.com/tendermint/tendermint/abci/types"
@ -43,6 +44,9 @@ func TestABCIValidators(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, tmValExpected, tmVals[0])
abciVals := TM2PB.Validators(NewValidatorSet(tmVals))
assert.Equal(t, []abci.Validator{abciVal}, abciVals)
// val with address
tmVal.Address = pkEd.Address()
@ -67,3 +71,50 @@ func TestABCIConsensusParams(t *testing.T) {
assert.Equal(t, *cp, cp2)
}
func TestABCIHeader(t *testing.T) {
header := &Header{
Height: int64(3),
Time: time.Now(),
NumTxs: int64(10),
}
abciHeader := TM2PB.Header(header)
assert.Equal(t, int64(3), abciHeader.Height)
}
func TestABCIEvidence(t *testing.T) {
val := NewMockPV()
blockID := makeBlockID("blockhash", 1000, "partshash")
blockID2 := makeBlockID("blockhash2", 1000, "partshash")
const chainID = "mychain"
ev := &DuplicateVoteEvidence{
PubKey: val.GetPubKey(),
VoteA: makeVote(val, chainID, 0, 10, 2, 1, blockID),
VoteB: makeVote(val, chainID, 0, 10, 2, 1, blockID2),
}
abciEv := TM2PB.Evidence(
ev,
NewValidatorSet([]*Validator{NewValidator(val.GetPubKey(), 10)}),
time.Now(),
)
assert.Equal(t, "duplicate/vote", abciEv.Type)
}
type pubKeyEddie struct{}
func (pubKeyEddie) Address() Address { return []byte{} }
func (pubKeyEddie) Bytes() []byte { return []byte{} }
func (pubKeyEddie) VerifyBytes(msg []byte, sig crypto.Signature) bool { return false }
func (pubKeyEddie) Equals(crypto.PubKey) bool { return false }
func TestABCIValidatorFromPubKeyAndPower(t *testing.T) {
pubkey := crypto.GenPrivKeyEd25519().PubKey()
abciVal := TM2PB.ValidatorFromPubKeyAndPower(pubkey, 10)
assert.Equal(t, int64(10), abciVal.Power)
assert.Panics(t, func() { TM2PB.ValidatorFromPubKeyAndPower(nil, 10) })
assert.Panics(t, func() { TM2PB.ValidatorFromPubKeyAndPower(pubKeyEddie{}, 10) })
}

+ 5
- 4
types/results.go View File

@ -24,15 +24,16 @@ func (a ABCIResult) Hash() []byte {
// ABCIResults wraps the deliver tx results to return a proof
type ABCIResults []ABCIResult
// NewResults creates ABCIResults from ResponseDeliverTx
func NewResults(del []*abci.ResponseDeliverTx) ABCIResults {
res := make(ABCIResults, len(del))
for i, d := range del {
// NewResults creates ABCIResults from the list of ResponseDeliverTx.
func NewResults(responses []*abci.ResponseDeliverTx) ABCIResults {
res := make(ABCIResults, len(responses))
for i, d := range responses {
res[i] = NewResultFromResponse(d)
}
return res
}
// NewResultFromResponse creates ABCIResult from ResponseDeliverTx.
func NewResultFromResponse(response *abci.ResponseDeliverTx) ABCIResult {
return ABCIResult{
Code: response.Code,


+ 12
- 0
types/results_test.go View File

@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)
func TestABCIResults(t *testing.T) {
@ -41,3 +42,14 @@ func TestABCIResults(t *testing.T) {
assert.True(t, valid, "%d", i)
}
}
func TestABCIBytes(t *testing.T) {
results := NewResults([]*abci.ResponseDeliverTx{
{Code: 0, Data: []byte{}},
{Code: 0, Data: []byte("one")},
{Code: 14, Data: nil},
{Code: 14, Data: []byte("foo")},
{Code: 14, Data: []byte("bar")},
})
assert.NotNil(t, results.Bytes())
}

+ 28
- 19
types/tx_test.go View File

@ -24,21 +24,32 @@ func randInt(low, high int) int {
}
func TestTxIndex(t *testing.T) {
assert := assert.New(t)
for i := 0; i < 20; i++ {
txs := makeTxs(15, 60)
for j := 0; j < len(txs); j++ {
tx := txs[j]
idx := txs.Index(tx)
assert.Equal(j, idx)
assert.Equal(t, j, idx)
}
assert.Equal(-1, txs.Index(nil))
assert.Equal(-1, txs.Index(Tx("foodnwkf")))
assert.Equal(t, -1, txs.Index(nil))
assert.Equal(t, -1, txs.Index(Tx("foodnwkf")))
}
}
func TestTxIndexByHash(t *testing.T) {
for i := 0; i < 20; i++ {
txs := makeTxs(15, 60)
for j := 0; j < len(txs); j++ {
tx := txs[j]
idx := txs.IndexByHash(tx.Hash())
assert.Equal(t, j, idx)
}
assert.Equal(t, -1, txs.IndexByHash(nil))
assert.Equal(t, -1, txs.IndexByHash(Tx("foodnwkf").Hash()))
}
}
func TestValidTxProof(t *testing.T) {
assert := assert.New(t)
cases := []struct {
txs Txs
}{
@ -58,21 +69,21 @@ func TestValidTxProof(t *testing.T) {
leaf := txs[i]
leafHash := leaf.Hash()
proof := txs.Proof(i)
assert.Equal(i, proof.Index, "%d: %d", h, i)
assert.Equal(len(txs), proof.Total, "%d: %d", h, i)
assert.EqualValues(root, proof.RootHash, "%d: %d", h, i)
assert.EqualValues(leaf, proof.Data, "%d: %d", h, i)
assert.EqualValues(leafHash, proof.LeafHash(), "%d: %d", h, i)
assert.Nil(proof.Validate(root), "%d: %d", h, i)
assert.NotNil(proof.Validate([]byte("foobar")), "%d: %d", h, i)
assert.Equal(t, i, proof.Index, "%d: %d", h, i)
assert.Equal(t, len(txs), proof.Total, "%d: %d", h, i)
assert.EqualValues(t, root, proof.RootHash, "%d: %d", h, i)
assert.EqualValues(t, leaf, proof.Data, "%d: %d", h, i)
assert.EqualValues(t, leafHash, proof.LeafHash(), "%d: %d", h, i)
assert.Nil(t, proof.Validate(root), "%d: %d", h, i)
assert.NotNil(t, proof.Validate([]byte("foobar")), "%d: %d", h, i)
// read-write must also work
var p2 TxProof
bin, err := cdc.MarshalBinary(proof)
assert.Nil(err)
assert.Nil(t, err)
err = cdc.UnmarshalBinary(bin, &p2)
if assert.Nil(err, "%d: %d: %+v", h, i, err) {
assert.Nil(p2.Validate(root), "%d: %d", h, i)
if assert.Nil(t, err, "%d: %d: %+v", h, i, err) {
assert.Nil(t, p2.Validate(root), "%d: %d", h, i)
}
}
}
@ -86,8 +97,6 @@ func TestTxProofUnchangable(t *testing.T) {
}
func testTxProofUnchangable(t *testing.T) {
assert := assert.New(t)
// make some proof
txs := makeTxs(randInt(2, 100), randInt(16, 128))
root := txs.Hash()
@ -95,9 +104,9 @@ func testTxProofUnchangable(t *testing.T) {
proof := txs.Proof(i)
// make sure it is valid to start with
assert.Nil(proof.Validate(root))
assert.Nil(t, proof.Validate(root))
bin, err := cdc.MarshalBinary(proof)
assert.Nil(err)
assert.Nil(t, err)
// try mutating the data and make sure nothing breaks
for j := 0; j < 500; j++ {


+ 3
- 2
types/validator_set.go View File

@ -39,14 +39,15 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet {
Validators: validators,
}
if vals != nil {
if len(vals) > 0 {
vs.IncrementAccum(1)
}
return vs
}
// incrementAccum and update the proposer
// IncrementAccum increments accum of each validator and updates the
// proposer. Panics if validator set is empty.
func (valSet *ValidatorSet) IncrementAccum(times int) {
// Add VotingPower * times to each validator and order into heap.
validatorsHeap := cmn.NewHeap()


+ 54
- 0
types/validator_set_test.go View File

@ -14,6 +14,60 @@ import (
cmn "github.com/tendermint/tendermint/libs/common"
)
func TestValidatorSetBasic(t *testing.T) {
for _, vset := range []*ValidatorSet{NewValidatorSet([]*Validator{}), NewValidatorSet(nil)} {
assert.Panics(t, func() { vset.IncrementAccum(1) })
assert.EqualValues(t, vset, vset.Copy())
assert.False(t, vset.HasAddress([]byte("some val")))
idx, val := vset.GetByAddress([]byte("some val"))
assert.Equal(t, -1, idx)
assert.Nil(t, val)
addr, val := vset.GetByIndex(-100)
assert.Nil(t, addr)
assert.Nil(t, val)
addr, val = vset.GetByIndex(0)
assert.Nil(t, addr)
assert.Nil(t, val)
addr, val = vset.GetByIndex(100)
assert.Nil(t, addr)
assert.Nil(t, val)
assert.Zero(t, vset.Size())
assert.Equal(t, int64(0), vset.TotalVotingPower())
assert.Nil(t, vset.GetProposer())
assert.Nil(t, vset.Hash())
// add
val = randValidator_()
assert.True(t, vset.Add(val))
assert.True(t, vset.HasAddress(val.Address))
idx, val2 := vset.GetByAddress(val.Address)
assert.Equal(t, 0, idx)
assert.Equal(t, val, val2)
addr, val2 = vset.GetByIndex(0)
assert.Equal(t, []byte(val.Address), addr)
assert.Equal(t, val, val2)
assert.Equal(t, 1, vset.Size())
assert.Equal(t, val.VotingPower, vset.TotalVotingPower())
assert.Equal(t, val, vset.GetProposer())
assert.NotNil(t, vset.Hash())
assert.NotPanics(t, func() { vset.IncrementAccum(1) })
// update
assert.False(t, vset.Update(randValidator_()))
val.VotingPower = 100
assert.True(t, vset.Update(val))
// remove
val2, removed := vset.Remove(randValidator_().Address)
assert.Nil(t, val2)
assert.False(t, removed)
val2, removed = vset.Remove(val.Address)
assert.Equal(t, val.Address, val2.Address)
assert.True(t, removed)
}
}
func TestCopy(t *testing.T) {
vset := randValidatorSet(10)
vsetHash := vset.Hash()


+ 23
- 23
types/vote_test.go View File

@ -4,7 +4,9 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
)
func examplePrevote() *Vote {
@ -50,29 +52,9 @@ func TestVoteSignable(t *testing.T) {
}
}
func TestVoteString(t *testing.T) {
tc := []struct {
name string
in string
out string
}{
{"Precommit", examplePrecommit().String(), `Vote{56789:616464720000 12345/02/2(Precommit) 686173680000 <nil> @ 2017-12-25T03:00:01.234Z}`},
{"Prevote", examplePrevote().String(), `Vote{56789:616464720000 12345/02/1(Prevote) 686173680000 <nil> @ 2017-12-25T03:00:01.234Z}`},
}
for _, tt := range tc {
tt := tt
t.Run(tt.name, func(st *testing.T) {
if tt.in != tt.out {
t.Errorf("Got unexpected string for Proposal. Expected:\n%v\nGot:\n%v", tt.in, tt.out)
}
})
}
}
func TestVoteVerifySignature(t *testing.T) {
privVal := NewMockPV()
pubKey := privVal.GetPubKey()
pubkey := privVal.GetPubKey()
vote := examplePrecommit()
signBytes := vote.SignBytes("test_chain_id")
@ -82,7 +64,7 @@ func TestVoteVerifySignature(t *testing.T) {
require.NoError(t, err)
// verify the same vote
valid := pubKey.VerifyBytes(vote.SignBytes("test_chain_id"), vote.Signature)
valid := pubkey.VerifyBytes(vote.SignBytes("test_chain_id"), vote.Signature)
require.True(t, valid)
// serialize, deserialize and verify again....
@ -95,7 +77,7 @@ func TestVoteVerifySignature(t *testing.T) {
// verify the transmitted vote
newSignBytes := precommit.SignBytes("test_chain_id")
require.Equal(t, string(signBytes), string(newSignBytes))
valid = pubKey.VerifyBytes(newSignBytes, precommit.Signature)
valid = pubkey.VerifyBytes(newSignBytes, precommit.Signature)
require.True(t, valid)
}
@ -119,3 +101,21 @@ func TestIsVoteTypeValid(t *testing.T) {
})
}
}
func TestVoteVerify(t *testing.T) {
privVal := NewMockPV()
pubkey := privVal.GetPubKey()
vote := examplePrevote()
vote.ValidatorAddress = pubkey.Address()
err := vote.Verify("test_chain_id", crypto.GenPrivKeyEd25519().PubKey())
if assert.Error(t, err) {
assert.Equal(t, ErrVoteInvalidValidatorAddress, err)
}
err = vote.Verify("test_chain_id", pubkey)
if assert.Error(t, err) {
assert.Equal(t, ErrVoteInvalidSignature, err)
}
}

Loading…
Cancel
Save