Merge branch 'develop' into jae/aminoify

This commit is contained in:
Ethan Buchman
2018-04-07 16:16:53 +03:00
95 changed files with 2317 additions and 770 deletions
+9 -5
View File
@@ -156,9 +156,8 @@ func (b *Block) StringIndented(indent string) string {
func (b *Block) StringShort() string {
if b == nil {
return "nil-Block"
} else {
return fmt.Sprintf("Block#%v", b.Hash())
}
return fmt.Sprintf("Block#%v", b.Hash())
}
//-----------------------------------------------------------------------------
@@ -192,9 +191,11 @@ type Header struct {
}
// Hash returns the hash of the header.
// Returns nil if ValidatorHash is missing.
// Returns nil if ValidatorHash is missing,
// since a Header is not valid unless there is
// a ValidaotrsHash (corresponding to the validator set).
func (h *Header) Hash() cmn.HexBytes {
if len(h.ValidatorsHash) == 0 {
if h == nil || len(h.ValidatorsHash) == 0 {
return nil
}
return merkle.SimpleHashFromMap(map[string]merkle.Hasher{
@@ -230,7 +231,7 @@ func (h *Header) StringIndented(indent string) string {
%s Data: %v
%s Validators: %v
%s App: %v
%s Conensus: %v
%s Consensus: %v
%s Results: %v
%s Evidence: %v
%s}#%v`,
@@ -428,6 +429,9 @@ type Data struct {
// Hash returns the hash of the data
func (data *Data) Hash() cmn.HexBytes {
if data == nil {
return (Txs{}).Hash()
}
if data.hash == nil {
data.hash = data.Txs.Hash() // NOTE: leaves of merkle tree are TxIDs
}
+15 -1
View File
@@ -3,7 +3,9 @@ package types
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
cmn "github.com/tendermint/tmlibs/common"
)
@@ -26,7 +28,7 @@ func TestValidateBlock(t *testing.T) {
// tamper with NumTxs
block = MakeBlock(h, txs, commit)
block.NumTxs += 1
block.NumTxs++
err = block.ValidateBasic()
require.Error(t, err)
@@ -72,3 +74,15 @@ func makeBlockID(hash string, partSetSize int, partSetHash string) BlockID {
}
}
var nilBytes []byte
func TestNilHeaderHashDoesntCrash(t *testing.T) {
assert.Equal(t, []byte((*Header)(nil).Hash()), nilBytes)
assert.Equal(t, []byte((new(Header)).Hash()), nilBytes)
}
func TestNilDataHashDoesntCrash(t *testing.T) {
assert.Equal(t, []byte((*Data)(nil).Hash()), nilBytes)
assert.Equal(t, []byte(new(Data).Hash()), nilBytes)
}
+1 -1
View File
@@ -101,7 +101,7 @@ func (b *EventBus) PublishEventTx(event EventDataTx) error {
b.Logger.Info("Got tag with an empty key (skipping)", "tag", tag, "tx", event.Tx)
continue
}
tags[string(tag.Key)] = tag.Value
tags[string(tag.Key)] = string(tag.Value)
}
// add predefined tags
+49
View File
@@ -7,9 +7,58 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
tmpubsub "github.com/tendermint/tmlibs/pubsub"
tmquery "github.com/tendermint/tmlibs/pubsub/query"
)
func TestEventBusPublishEventTx(t *testing.T) {
eventBus := NewEventBus()
err := eventBus.Start()
require.NoError(t, err)
defer eventBus.Stop()
tx := Tx("foo")
result := abci.ResponseDeliverTx{Data: []byte("bar"), Tags: []cmn.KVPair{}, Fee: cmn.KI64Pair{Key: []uint8{}, Value: 0}}
txEventsCh := make(chan interface{})
// PublishEventTx adds all these 3 tags, so the query below should work
query := fmt.Sprintf("tm.event='Tx' AND tx.height=1 AND tx.hash='%X'", tx.Hash())
err = eventBus.Subscribe(context.Background(), "test", tmquery.MustParse(query), txEventsCh)
require.NoError(t, err)
done := make(chan struct{})
go func() {
for e := range txEventsCh {
edt := e.(TMEventData).Unwrap().(EventDataTx)
assert.Equal(t, int64(1), edt.Height)
assert.Equal(t, uint32(0), edt.Index)
assert.Equal(t, tx, edt.Tx)
assert.Equal(t, result, edt.Result)
close(done)
}
}()
err = eventBus.PublishEventTx(EventDataTx{TxResult{
Height: 1,
Index: 0,
Tx: tx,
Result: result,
}})
assert.NoError(t, err)
select {
case <-done:
case <-time.After(1 * time.Second):
t.Fatal("did not receive a transaction after 1 sec.")
}
}
func BenchmarkEventBus(b *testing.B) {
benchmarks := []struct {
name string
+1 -1
View File
@@ -99,7 +99,7 @@ func (dve *DuplicateVoteEvidence) Verify(chainID string) error {
// BlockIDs must be different
if dve.VoteA.BlockID.Equals(dve.VoteB.BlockID) {
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote!", dve.VoteA.BlockID)
return fmt.Errorf("DuplicateVoteEvidence Error: BlockIDs are the same (%v) - not a real duplicate vote", dve.VoteA.BlockID)
}
// Signatures must be valid
+11 -1
View File
@@ -26,7 +26,17 @@ type GenesisDoc struct {
ConsensusParams *ConsensusParams `json:"consensus_params,omitempty"`
Validators []GenesisValidator `json:"validators"`
AppHash cmn.HexBytes `json:"app_hash"`
AppState json.RawMessage `json:"app_state,omitempty"`
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
}
// SaveAs is a utility method for saving GenensisDoc as a JSON file.
+13 -17
View File
@@ -30,12 +30,11 @@ type Part struct {
func (part *Part) Hash() []byte {
if part.hash != nil {
return part.hash
} else {
hasher := ripemd160.New()
hasher.Write(part.Bytes) // nolint: errcheck, gas
part.hash = hasher.Sum(nil)
return part.hash
}
hasher := ripemd160.New()
hasher.Write(part.Bytes) // nolint: errcheck, gas
part.hash = hasher.Sum(nil)
return part.hash
}
func (part *Part) String() string {
@@ -129,20 +128,18 @@ func NewPartSetFromHeader(header PartSetHeader) *PartSet {
func (ps *PartSet) Header() PartSetHeader {
if ps == nil {
return PartSetHeader{}
} else {
return PartSetHeader{
Total: ps.total,
Hash: ps.hash,
}
}
return PartSetHeader{
Total: ps.total,
Hash: ps.hash,
}
}
func (ps *PartSet) HasHeader(header PartSetHeader) bool {
if ps == nil {
return false
} else {
return ps.Header().Equals(header)
}
return ps.Header().Equals(header)
}
func (ps *PartSet) BitArray() *cmn.BitArray {
@@ -251,7 +248,7 @@ func (psr *PartSetReader) Read(p []byte) (n int, err error) {
return n1 + n2, err
}
psr.i += 1
psr.i++
if psr.i >= len(psr.parts) {
return 0, io.EOF
}
@@ -262,9 +259,8 @@ func (psr *PartSetReader) Read(p []byte) (n int, err error) {
func (ps *PartSet) StringShort() string {
if ps == nil {
return "nil-PartSet"
} else {
ps.mtx.Lock()
defer ps.mtx.Unlock()
return fmt.Sprintf("(%v of %v)", ps.Count(), ps.Total())
}
ps.mtx.Lock()
defer ps.mtx.Unlock()
return fmt.Sprintf("(%v of %v)", ps.Count(), ps.Total())
}
+238
View File
@@ -0,0 +1,238 @@
package types
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"time"
crypto "github.com/tendermint/go-crypto"
"github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
)
// TODO: type ?
const (
stepNone int8 = 0 // Used to distinguish the initial state
stepPropose int8 = 1
stepPrevote int8 = 2
stepPrecommit int8 = 3
)
func voteToStep(vote *types.Vote) int8 {
switch vote.Type {
case types.VoteTypePrevote:
return stepPrevote
case types.VoteTypePrecommit:
return stepPrecommit
default:
panic("Unknown vote type")
}
}
//-------------------------------------
// LastSignedInfo contains information about the latest
// data signed by a validator to help prevent double signing.
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 cmn.HexBytes `json:"signbytes,omitempty"` // so we dont lose signatures
}
func NewLastSignedInfo() *LastSignedInfo {
return &LastSignedInfo{
Step: stepNone,
}
}
func (lsi *LastSignedInfo) String() string {
return fmt.Sprintf("LH:%v, LR:%v, LS:%v", lsi.Height, lsi.Round, lsi.Step)
}
// Verify returns an error if there is a height/round/step regression
// or if the HRS matches but there are no LastSignBytes.
// It returns true if HRS matches exactly and the LastSignature exists.
// It panics if the HRS matches, the LastSignBytes are not empty, but the LastSignature is empty.
func (lsi LastSignedInfo) Verify(height int64, round int, step int8) (bool, error) {
if lsi.Height > height {
return false, errors.New("Height regression")
}
if lsi.Height == height {
if lsi.Round > round {
return false, errors.New("Round regression")
}
if lsi.Round == round {
if lsi.Step > step {
return false, errors.New("Step regression")
} else if lsi.Step == step {
if lsi.SignBytes != nil {
if lsi.Signature.Empty() {
panic("info: LastSignature is nil but LastSignBytes is not!")
}
return true, nil
}
return false, errors.New("No LastSignature found")
}
}
}
return false, nil
}
// Set height/round/step and signature on the info
func (lsi *LastSignedInfo) Set(height int64, round int, step int8,
signBytes []byte, sig crypto.Signature) {
lsi.Height = height
lsi.Round = round
lsi.Step = step
lsi.Signature = sig
lsi.SignBytes = signBytes
}
// Reset resets all the values.
// XXX: Unsafe.
func (lsi *LastSignedInfo) Reset() {
lsi.Height = 0
lsi.Round = 0
lsi.Step = 0
lsi.Signature = crypto.Signature{}
lsi.SignBytes = nil
}
// SignVote checks the height/round/step (HRS) are greater than the latest state of the LastSignedInfo.
// If so, it signs the vote, updates the LastSignedInfo, and sets the signature on the vote.
// If the HRS are equal and the only thing changed is the timestamp, it sets the vote.Timestamp to the previous
// value and the Signature to the LastSignedInfo.Signature.
// 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 := vote.SignBytes(chainID)
sameHRS, err := lsi.Verify(height, round, step)
if err != nil {
return err
}
// We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS.
// If signbytes are the same, use the last signature.
// If they only differ by timestamp, use last timestamp and signature
// Otherwise, return error
if sameHRS {
if bytes.Equal(signBytes, lsi.SignBytes) {
vote.Signature = lsi.Signature
} else if timestamp, ok := checkVotesOnlyDifferByTimestamp(lsi.SignBytes, signBytes); ok {
vote.Timestamp = timestamp
vote.Signature = lsi.Signature
} else {
err = fmt.Errorf("Conflicting data")
}
return err
}
sig, err := signer.Sign(signBytes)
if err != nil {
return err
}
lsi.Set(height, round, step, signBytes, sig)
vote.Signature = sig
return nil
}
// SignProposal checks if the height/round/step (HRS) are greater than the latest state of the LastSignedInfo.
// If so, it signs the proposal, updates the LastSignedInfo, and sets the signature on the proposal.
// If the HRS are equal and the only thing changed is the timestamp, it sets the timestamp to the previous
// value and the Signature to the LastSignedInfo.Signature.
// 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 := proposal.SignBytes(chainID)
sameHRS, err := lsi.Verify(height, round, step)
if err != nil {
return err
}
// We might crash before writing to the wal,
// causing us to try to re-sign for the same HRS.
// If signbytes are the same, use the last signature.
// If they only differ by timestamp, use last timestamp and signature
// Otherwise, return error
if sameHRS {
if bytes.Equal(signBytes, lsi.SignBytes) {
proposal.Signature = lsi.Signature
} else if timestamp, ok := checkProposalsOnlyDifferByTimestamp(lsi.SignBytes, signBytes); ok {
proposal.Timestamp = timestamp
proposal.Signature = lsi.Signature
} else {
err = fmt.Errorf("Conflicting data")
}
return err
}
sig, err := signer.Sign(signBytes)
if err != nil {
return err
}
lsi.Set(height, round, step, signBytes, sig)
proposal.Signature = sig
return nil
}
//-------------------------------------
// returns the timestamp from the lastSignBytes.
// returns true if the only difference in the votes is their timestamp.
func checkVotesOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
var lastVote, newVote types.CanonicalJSONOnceVote
if err := json.Unmarshal(lastSignBytes, &lastVote); err != nil {
panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into vote: %v", err))
}
if err := json.Unmarshal(newSignBytes, &newVote); err != nil {
panic(fmt.Sprintf("signBytes cannot be unmarshalled into vote: %v", err))
}
lastTime, err := time.Parse(types.TimeFormat, lastVote.Vote.Timestamp)
if err != nil {
panic(err)
}
// set the times to the same value and check equality
now := types.CanonicalTime(time.Now())
lastVote.Vote.Timestamp = now
newVote.Vote.Timestamp = now
lastVoteBytes, _ := json.Marshal(lastVote)
newVoteBytes, _ := json.Marshal(newVote)
return lastTime, bytes.Equal(newVoteBytes, lastVoteBytes)
}
// returns the timestamp from the lastSignBytes.
// returns true if the only difference in the proposals is their timestamp
func checkProposalsOnlyDifferByTimestamp(lastSignBytes, newSignBytes []byte) (time.Time, bool) {
var lastProposal, newProposal types.CanonicalJSONOnceProposal
if err := json.Unmarshal(lastSignBytes, &lastProposal); err != nil {
panic(fmt.Sprintf("LastSignBytes cannot be unmarshalled into proposal: %v", err))
}
if err := json.Unmarshal(newSignBytes, &newProposal); err != nil {
panic(fmt.Sprintf("signBytes cannot be unmarshalled into proposal: %v", err))
}
lastTime, err := time.Parse(types.TimeFormat, lastProposal.Proposal.Timestamp)
if err != nil {
panic(err)
}
// set the times to the same value and check equality
now := types.CanonicalTime(time.Now())
lastProposal.Proposal.Timestamp = now
newProposal.Proposal.Timestamp = now
lastProposalBytes, _ := json.Marshal(lastProposal)
newProposalBytes, _ := json.Marshal(newProposal)
return lastTime, bytes.Equal(newProposalBytes, lastProposalBytes)
}
+3 -2
View File
@@ -45,9 +45,10 @@ func (v *Validator) CompareAccum(other *Validator) *Validator {
} else if v.Accum < other.Accum {
return other
} else {
if bytes.Compare(v.Address, other.Address) < 0 {
result := bytes.Compare(v.Address, other.Address)
if result < 0 {
return v
} else if bytes.Compare(v.Address, other.Address) > 0 {
} else if result > 0 {
return other
} else {
cmn.PanicSanity("Cannot compare identical validators")
+45 -35
View File
@@ -82,27 +82,30 @@ func (valSet *ValidatorSet) Copy() *ValidatorSet {
}
}
// HasAddress returns true if address given is in the validator set, false -
// otherwise.
func (valSet *ValidatorSet) HasAddress(address []byte) bool {
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
return idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address)
return idx < len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address)
}
// GetByAddress returns an index of the validator with address and validator
// itself if found. Otherwise, -1 and nil are returned.
func (valSet *ValidatorSet) GetByAddress(address []byte) (index int, val *Validator) {
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
if idx != len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address) {
if idx < len(valSet.Validators) && bytes.Equal(valSet.Validators[idx].Address, address) {
return idx, valSet.Validators[idx].Copy()
} else {
return 0, nil
}
return -1, nil
}
// GetByIndex returns the validator by index.
// It returns nil values if index < 0 or
// index >= len(ValidatorSet.Validators)
// GetByIndex returns the validator's address and validator itself by index.
// It returns nil values if index is less than 0 or greater or equal to
// len(ValidatorSet.Validators).
func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
if index < 0 || index >= len(valSet.Validators) {
return nil, nil
@@ -111,10 +114,12 @@ func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validato
return val.Address, val.Copy()
}
// Size returns the length of the validator set.
func (valSet *ValidatorSet) Size() int {
return len(valSet.Validators)
}
// TotalVotingPower returns the sum of the voting powers of all validators.
func (valSet *ValidatorSet) TotalVotingPower() int64 {
if valSet.totalVotingPower == 0 {
for _, val := range valSet.Validators {
@@ -125,6 +130,8 @@ func (valSet *ValidatorSet) TotalVotingPower() int64 {
return valSet.totalVotingPower
}
// GetProposer returns the current proposer. If the validator set is empty, nil
// is returned.
func (valSet *ValidatorSet) GetProposer() (proposer *Validator) {
if len(valSet.Validators) == 0 {
return nil
@@ -145,6 +152,8 @@ func (valSet *ValidatorSet) findProposer() *Validator {
return proposer
}
// Hash returns the Merkle root hash build using validators (as leaves) in the
// set.
func (valSet *ValidatorSet) Hash() []byte {
if len(valSet.Validators) == 0 {
return nil
@@ -156,12 +165,14 @@ func (valSet *ValidatorSet) Hash() []byte {
return merkle.SimpleHashFromHashers(hashers)
}
// Add adds val to the validator set and returns true. It returns false if val
// is already in the set.
func (valSet *ValidatorSet) Add(val *Validator) (added bool) {
val = val.Copy()
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(val.Address, valSet.Validators[i].Address) <= 0
})
if idx == len(valSet.Validators) {
if idx >= len(valSet.Validators) {
valSet.Validators = append(valSet.Validators, val)
// Invalidate cache
valSet.Proposer = nil
@@ -182,39 +193,42 @@ func (valSet *ValidatorSet) Add(val *Validator) (added bool) {
}
}
// Update updates val and returns true. It returns false if val is not present
// in the set.
func (valSet *ValidatorSet) Update(val *Validator) (updated bool) {
index, sameVal := valSet.GetByAddress(val.Address)
if sameVal == nil {
return false
} else {
valSet.Validators[index] = val.Copy()
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return true
}
valSet.Validators[index] = val.Copy()
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return true
}
// Remove deletes the validator with address. It returns the validator removed
// and true. If returns nil and false if validator is not present in the set.
func (valSet *ValidatorSet) Remove(address []byte) (val *Validator, removed bool) {
idx := sort.Search(len(valSet.Validators), func(i int) bool {
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
})
if idx == len(valSet.Validators) || !bytes.Equal(valSet.Validators[idx].Address, address) {
if idx >= len(valSet.Validators) || !bytes.Equal(valSet.Validators[idx].Address, address) {
return nil, false
} else {
removedVal := valSet.Validators[idx]
newValidators := valSet.Validators[:idx]
if idx+1 < len(valSet.Validators) {
newValidators = append(newValidators, valSet.Validators[idx+1:]...)
}
valSet.Validators = newValidators
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return removedVal, true
}
removedVal := valSet.Validators[idx]
newValidators := valSet.Validators[:idx]
if idx+1 < len(valSet.Validators) {
newValidators = append(newValidators, valSet.Validators[idx+1:]...)
}
valSet.Validators = newValidators
// Invalidate cache
valSet.Proposer = nil
valSet.totalVotingPower = 0
return removedVal, true
}
// Iterate will run the given function over the set.
func (valSet *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) {
for i, val := range valSet.Validators {
stop := fn(i, val.Copy())
@@ -265,10 +279,9 @@ func (valSet *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
return nil
} else {
return fmt.Errorf("Invalid commit -- insufficient voting power: got %v, needed %v",
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
}
return fmt.Errorf("Invalid commit -- insufficient voting power: got %v, needed %v",
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
}
// VerifyCommitAny will check to see if the set would
@@ -471,9 +484,8 @@ func safeMulClip(a, b int64) int64 {
if overflow {
if (a < 0 || b < 0) && !(a < 0 && b < 0) {
return math.MinInt64
} else {
return math.MaxInt64
}
return math.MaxInt64
}
return c
}
@@ -483,9 +495,8 @@ func safeAddClip(a, b int64) int64 {
if overflow {
if b < 0 {
return math.MinInt64
} else {
return math.MaxInt64
}
return math.MaxInt64
}
return c
}
@@ -495,9 +506,8 @@ func safeSubClip(a, b int64) int64 {
if overflow {
if b > 0 {
return math.MinInt64
} else {
return math.MaxInt64
}
return math.MaxInt64
}
return c
}
+1 -1
View File
@@ -126,7 +126,7 @@ func TestProposerSelection2(t *testing.T) {
for i := 0; i < 120*N; i++ {
prop := vals.GetProposer()
ii := prop.Address[19]
propCount[ii] += 1
propCount[ii]++
vals.IncrementAccum(1)
}
+19 -30
View File
@@ -94,33 +94,29 @@ func (voteSet *VoteSet) ChainID() string {
func (voteSet *VoteSet) Height() int64 {
if voteSet == nil {
return 0
} else {
return voteSet.height
}
return voteSet.height
}
func (voteSet *VoteSet) Round() int {
if voteSet == nil {
return -1
} else {
return voteSet.round
}
return voteSet.round
}
func (voteSet *VoteSet) Type() byte {
if voteSet == nil {
return 0x00
} else {
return voteSet.type_
}
return voteSet.type_
}
func (voteSet *VoteSet) Size() int {
if voteSet == nil {
return 0
} else {
return voteSet.valSet.Size()
}
return voteSet.valSet.Size()
}
// Returns added=true if vote is valid and new.
@@ -185,9 +181,8 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
if existing, ok := voteSet.getVote(valIndex, blockKey); ok {
if existing.Signature.Equals(vote.Signature) {
return false, nil // duplicate
} else {
return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", existing, vote)
}
return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", existing, vote)
}
// Check signature.
@@ -199,13 +194,11 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) {
added, conflicting := voteSet.addVerifiedVote(vote, blockKey, val.VotingPower)
if conflicting != nil {
return added, NewConflictingVoteError(val, conflicting, vote)
} else {
if !added {
cmn.PanicSanity("Expected to add non-conflicting vote")
}
return added, nil
}
if !added {
cmn.PanicSanity("Expected to add non-conflicting vote")
}
return added, nil
}
// Returns (vote, true) if vote exists for valIndex and blockKey
@@ -257,13 +250,12 @@ func (voteSet *VoteSet) addVerifiedVote(vote *Vote, blockKey string, votingPower
// ... and there's a conflicting vote.
// We're not even tracking this blockKey, so just forget it.
return false, conflicting
} else {
// ... and there's no conflicting vote.
// Start tracking this blockKey
votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
voteSet.votesByBlock[blockKey] = votesByBlock
// We'll add the vote in a bit.
}
// ... and there's no conflicting vote.
// Start tracking this blockKey
votesByBlock = newBlockVotes(false, voteSet.valSet.Size())
voteSet.votesByBlock[blockKey] = votesByBlock
// We'll add the vote in a bit.
}
// Before adding to votesByBlock, see if we'll exceed quorum
@@ -309,10 +301,9 @@ func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
if existing, ok := voteSet.peerMaj23s[peerID]; ok {
if existing.Equals(blockID) {
return nil // Nothing to do
} else {
return fmt.Errorf("SetPeerMaj23: Received conflicting blockID from peer %v. Got %v, expected %v",
peerID, blockID, existing)
}
return fmt.Errorf("SetPeerMaj23: Received conflicting blockID from peer %v. Got %v, expected %v",
peerID, blockID, existing)
}
voteSet.peerMaj23s[peerID] = blockID
@@ -321,10 +312,9 @@ func (voteSet *VoteSet) SetPeerMaj23(peerID P2PID, blockID BlockID) error {
if ok {
if votesByBlock.peerMaj23 {
return nil // Nothing to do
} else {
votesByBlock.peerMaj23 = true
// No need to copy votes, already there.
}
votesByBlock.peerMaj23 = true
// No need to copy votes, already there.
} else {
votesByBlock = newBlockVotes(true, voteSet.valSet.Size())
voteSet.votesByBlock[blockKey] = votesByBlock
@@ -422,9 +412,8 @@ func (voteSet *VoteSet) TwoThirdsMajority() (blockID BlockID, ok bool) {
defer voteSet.mtx.Unlock()
if voteSet.maj23 != nil {
return *voteSet.maj23, true
} else {
return BlockID{}, false
}
return BlockID{}, false
}
func (voteSet *VoteSet) String() string {