diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index f82ddbc2..05369ea6 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -24,6 +24,7 @@ BREAKING CHANGES: * [types] \#2298 Remove `Index` and `Total` fields from `TxProof`. * [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees * [crypto/merkle] \#2595 Remove all Hasher objects in favor of byte slices + * [crypto/merkle] \#2635 merkle.SimpleHashFromTwoHashes is no longer exported * [types] \#2598 `VoteTypeXxx` are now * Blockchain Protocol diff --git a/crypto/merkle/simple_proof.go b/crypto/merkle/simple_proof.go index d2cbb126..fd6d07b8 100644 --- a/crypto/merkle/simple_proof.go +++ b/crypto/merkle/simple_proof.go @@ -134,13 +134,13 @@ func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][ if leftHash == nil { return nil } - return SimpleHashFromTwoHashes(leftHash, innerHashes[len(innerHashes)-1]) + return simpleHashFromTwoHashes(leftHash, innerHashes[len(innerHashes)-1]) } rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1]) if rightHash == nil { return nil } - return SimpleHashFromTwoHashes(innerHashes[len(innerHashes)-1], rightHash) + return simpleHashFromTwoHashes(innerHashes[len(innerHashes)-1], rightHash) } } @@ -187,7 +187,7 @@ func trailsFromByteSlices(items [][]byte) (trails []*SimpleProofNode, root *Simp default: lefts, leftRoot := trailsFromByteSlices(items[:(len(items)+1)/2]) rights, rightRoot := trailsFromByteSlices(items[(len(items)+1)/2:]) - rootHash := SimpleHashFromTwoHashes(leftRoot.Hash, rightRoot.Hash) + rootHash := simpleHashFromTwoHashes(leftRoot.Hash, rightRoot.Hash) root := &SimpleProofNode{rootHash, nil, nil, nil} leftRoot.Parent = root leftRoot.Right = rightRoot diff --git a/crypto/merkle/simple_tree.go b/crypto/merkle/simple_tree.go index 45e0c5c5..7aacb088 100644 --- a/crypto/merkle/simple_tree.go +++ b/crypto/merkle/simple_tree.go @@ -4,8 +4,8 @@ import ( "github.com/tendermint/tendermint/crypto/tmhash" ) -// SimpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right). -func SimpleHashFromTwoHashes(left, right []byte) []byte { +// simpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right). +func simpleHashFromTwoHashes(left, right []byte) []byte { var hasher = tmhash.New() err := encodeByteSlice(hasher, left) if err != nil { @@ -29,7 +29,7 @@ func SimpleHashFromByteSlices(items [][]byte) []byte { default: left := SimpleHashFromByteSlices(items[:(len(items)+1)/2]) right := SimpleHashFromByteSlices(items[(len(items)+1)/2:]) - return SimpleHashFromTwoHashes(left, right) + return simpleHashFromTwoHashes(left, right) } } diff --git a/types/block.go b/types/block.go index f41f4c1f..45a5b8c3 100644 --- a/types/block.go +++ b/types/block.go @@ -576,7 +576,6 @@ func (sh SignedHeader) StringIndented(indent string) string { indent, sh.Header.StringIndented(indent+" "), indent, sh.Commit.StringIndented(indent+" "), indent) - return "" } //----------------------------------------------------------------------------- @@ -660,7 +659,6 @@ func (data *EvidenceData) StringIndented(indent string) string { %s}#%v`, indent, strings.Join(evStrings, "\n"+indent+" "), indent, data.hash) - return "" } //-------------------------------------------------------------------------------- diff --git a/types/evidence.go b/types/evidence.go index 00c46c59..57523ab1 100644 --- a/types/evidence.go +++ b/types/evidence.go @@ -55,6 +55,7 @@ func (err *ErrEvidenceOverflow) Error() string { type Evidence interface { Height() int64 // height of the equivocation Address() []byte // address of the equivocating validator + Bytes() []byte // bytes which compromise the evidence Hash() []byte // hash of the evidence Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence Equal(Evidence) bool // check equality of evidence @@ -88,6 +89,8 @@ type DuplicateVoteEvidence struct { VoteB *Vote } +var _ Evidence = &DuplicateVoteEvidence{} + // String returns a string representation of the evidence. func (dve *DuplicateVoteEvidence) String() string { return fmt.Sprintf("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB) @@ -104,6 +107,11 @@ func (dve *DuplicateVoteEvidence) Address() []byte { return dve.PubKey.Address() } +// Hash returns the hash of the evidence. +func (dve *DuplicateVoteEvidence) Bytes() []byte { + return cdcEncode(dve) +} + // Hash returns the hash of the evidence. func (dve *DuplicateVoteEvidence) Hash() []byte { return tmhash.Sum(cdcEncode(dve)) @@ -172,6 +180,8 @@ type MockGoodEvidence struct { Address_ []byte } +var _ Evidence = &MockGoodEvidence{} + // UNSTABLE func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence { return MockGoodEvidence{height, address} @@ -182,6 +192,9 @@ func (e MockGoodEvidence) Address() []byte { return e.Address_ } func (e MockGoodEvidence) Hash() []byte { return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_)) } +func (e MockGoodEvidence) Bytes() []byte { + return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_)) +} func (e MockGoodEvidence) Verify(chainID string, pubKey crypto.PubKey) error { return nil } func (e MockGoodEvidence) Equal(ev Evidence) bool { e2 := ev.(MockGoodEvidence) @@ -216,18 +229,14 @@ type EvidenceList []Evidence // Hash returns the simple merkle root hash of the EvidenceList. func (evl EvidenceList) Hash() []byte { - // Recursive impl. - // Copied from crypto/merkle to avoid allocations - switch len(evl) { - case 0: - return nil - case 1: - return evl[0].Hash() - default: - left := EvidenceList(evl[:(len(evl)+1)/2]).Hash() - right := EvidenceList(evl[(len(evl)+1)/2:]).Hash() - return merkle.SimpleHashFromTwoHashes(left, right) + // These allocations are required because Evidence is not of type Bytes, and + // golang slices can't be typed cast. This shouldn't be a performance problem since + // the Evidence size is capped. + evidenceBzs := make([][]byte, len(evl)) + for i := 0; i < len(evl); i++ { + evidenceBzs[i] = evl[i].Bytes() } + return merkle.SimpleHashFromByteSlices(evidenceBzs) } func (evl EvidenceList) String() string { diff --git a/types/tx.go b/types/tx.go index ec42f3f1..10c097e3 100644 --- a/types/tx.go +++ b/types/tx.go @@ -31,18 +31,13 @@ type Txs []Tx // Hash returns the simple Merkle root hash of the transactions. func (txs Txs) Hash() []byte { - // Recursive impl. - // Copied from tendermint/crypto/merkle to avoid allocations - switch len(txs) { - case 0: - return nil - case 1: - return txs[0].Hash() - default: - left := Txs(txs[:(len(txs)+1)/2]).Hash() - right := Txs(txs[(len(txs)+1)/2:]).Hash() - return merkle.SimpleHashFromTwoHashes(left, right) + // These allocations will be removed once Txs is switched to [][]byte, + // ref #2603. This is because golang does not allow type casting slices without unsafe + txBzs := make([][]byte, len(txs)) + for i := 0; i < len(txs); i++ { + txBzs[i] = txs[i] } + return merkle.SimpleHashFromByteSlices(txBzs) } // Index returns the index of this transaction in the list, or -1 if not found