Make txs and evidencelist use merkle.SimpleHashFromBytes to create hash (#2635)
This is a performance regression, but will also spare the types directory from knowing about RFC 6962, which is a more correct abstraction. For txs this performance hit will be fixed soon with #2603. For evidence, the performance impact is negligible due to it being capped at a small number.
This commit is contained in:
parent
4ab7dcf3ac
commit
124d0db1e0
|
@ -24,6 +24,7 @@ BREAKING CHANGES:
|
||||||
* [types] \#2298 Remove `Index` and `Total` fields from `TxProof`.
|
* [types] \#2298 Remove `Index` and `Total` fields from `TxProof`.
|
||||||
* [crypto/merkle & lite] \#2298 Various changes to accomodate General Merkle trees
|
* [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] \#2595 Remove all Hasher objects in favor of byte slices
|
||||||
|
* [crypto/merkle] \#2635 merkle.SimpleHashFromTwoHashes is no longer exported
|
||||||
* [types] \#2598 `VoteTypeXxx` are now
|
* [types] \#2598 `VoteTypeXxx` are now
|
||||||
|
|
||||||
* Blockchain Protocol
|
* Blockchain Protocol
|
||||||
|
|
|
@ -134,13 +134,13 @@ func computeHashFromAunts(index int, total int, leafHash []byte, innerHashes [][
|
||||||
if leftHash == nil {
|
if leftHash == nil {
|
||||||
return 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])
|
rightHash := computeHashFromAunts(index-numLeft, total-numLeft, leafHash, innerHashes[:len(innerHashes)-1])
|
||||||
if rightHash == nil {
|
if rightHash == nil {
|
||||||
return 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:
|
default:
|
||||||
lefts, leftRoot := trailsFromByteSlices(items[:(len(items)+1)/2])
|
lefts, leftRoot := trailsFromByteSlices(items[:(len(items)+1)/2])
|
||||||
rights, rightRoot := 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}
|
root := &SimpleProofNode{rootHash, nil, nil, nil}
|
||||||
leftRoot.Parent = root
|
leftRoot.Parent = root
|
||||||
leftRoot.Right = rightRoot
|
leftRoot.Right = rightRoot
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"github.com/tendermint/tendermint/crypto/tmhash"
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SimpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right).
|
// simpleHashFromTwoHashes is the basic operation of the Merkle tree: Hash(left | right).
|
||||||
func SimpleHashFromTwoHashes(left, right []byte) []byte {
|
func simpleHashFromTwoHashes(left, right []byte) []byte {
|
||||||
var hasher = tmhash.New()
|
var hasher = tmhash.New()
|
||||||
err := encodeByteSlice(hasher, left)
|
err := encodeByteSlice(hasher, left)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -29,7 +29,7 @@ func SimpleHashFromByteSlices(items [][]byte) []byte {
|
||||||
default:
|
default:
|
||||||
left := SimpleHashFromByteSlices(items[:(len(items)+1)/2])
|
left := SimpleHashFromByteSlices(items[:(len(items)+1)/2])
|
||||||
right := SimpleHashFromByteSlices(items[(len(items)+1)/2:])
|
right := SimpleHashFromByteSlices(items[(len(items)+1)/2:])
|
||||||
return SimpleHashFromTwoHashes(left, right)
|
return simpleHashFromTwoHashes(left, right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -576,7 +576,6 @@ func (sh SignedHeader) StringIndented(indent string) string {
|
||||||
indent, sh.Header.StringIndented(indent+" "),
|
indent, sh.Header.StringIndented(indent+" "),
|
||||||
indent, sh.Commit.StringIndented(indent+" "),
|
indent, sh.Commit.StringIndented(indent+" "),
|
||||||
indent)
|
indent)
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -660,7 +659,6 @@ func (data *EvidenceData) StringIndented(indent string) string {
|
||||||
%s}#%v`,
|
%s}#%v`,
|
||||||
indent, strings.Join(evStrings, "\n"+indent+" "),
|
indent, strings.Join(evStrings, "\n"+indent+" "),
|
||||||
indent, data.hash)
|
indent, data.hash)
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
|
|
@ -55,6 +55,7 @@ func (err *ErrEvidenceOverflow) Error() string {
|
||||||
type Evidence interface {
|
type Evidence interface {
|
||||||
Height() int64 // height of the equivocation
|
Height() int64 // height of the equivocation
|
||||||
Address() []byte // address of the equivocating validator
|
Address() []byte // address of the equivocating validator
|
||||||
|
Bytes() []byte // bytes which compromise the evidence
|
||||||
Hash() []byte // hash of the evidence
|
Hash() []byte // hash of the evidence
|
||||||
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
Verify(chainID string, pubKey crypto.PubKey) error // verify the evidence
|
||||||
Equal(Evidence) bool // check equality of evidence
|
Equal(Evidence) bool // check equality of evidence
|
||||||
|
@ -88,6 +89,8 @@ type DuplicateVoteEvidence struct {
|
||||||
VoteB *Vote
|
VoteB *Vote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Evidence = &DuplicateVoteEvidence{}
|
||||||
|
|
||||||
// String returns a string representation of the evidence.
|
// String returns a string representation of the evidence.
|
||||||
func (dve *DuplicateVoteEvidence) String() string {
|
func (dve *DuplicateVoteEvidence) String() string {
|
||||||
return fmt.Sprintf("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB)
|
return fmt.Sprintf("VoteA: %v; VoteB: %v", dve.VoteA, dve.VoteB)
|
||||||
|
@ -104,6 +107,11 @@ func (dve *DuplicateVoteEvidence) Address() []byte {
|
||||||
return dve.PubKey.Address()
|
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.
|
// Hash returns the hash of the evidence.
|
||||||
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
func (dve *DuplicateVoteEvidence) Hash() []byte {
|
||||||
return tmhash.Sum(cdcEncode(dve))
|
return tmhash.Sum(cdcEncode(dve))
|
||||||
|
@ -172,6 +180,8 @@ type MockGoodEvidence struct {
|
||||||
Address_ []byte
|
Address_ []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Evidence = &MockGoodEvidence{}
|
||||||
|
|
||||||
// UNSTABLE
|
// UNSTABLE
|
||||||
func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence {
|
func NewMockGoodEvidence(height int64, idx int, address []byte) MockGoodEvidence {
|
||||||
return MockGoodEvidence{height, address}
|
return MockGoodEvidence{height, address}
|
||||||
|
@ -182,6 +192,9 @@ func (e MockGoodEvidence) Address() []byte { return e.Address_ }
|
||||||
func (e MockGoodEvidence) Hash() []byte {
|
func (e MockGoodEvidence) Hash() []byte {
|
||||||
return []byte(fmt.Sprintf("%d-%x", e.Height_, e.Address_))
|
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) Verify(chainID string, pubKey crypto.PubKey) error { return nil }
|
||||||
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
func (e MockGoodEvidence) Equal(ev Evidence) bool {
|
||||||
e2 := ev.(MockGoodEvidence)
|
e2 := ev.(MockGoodEvidence)
|
||||||
|
@ -216,18 +229,14 @@ type EvidenceList []Evidence
|
||||||
|
|
||||||
// Hash returns the simple merkle root hash of the EvidenceList.
|
// Hash returns the simple merkle root hash of the EvidenceList.
|
||||||
func (evl EvidenceList) Hash() []byte {
|
func (evl EvidenceList) Hash() []byte {
|
||||||
// Recursive impl.
|
// These allocations are required because Evidence is not of type Bytes, and
|
||||||
// Copied from crypto/merkle to avoid allocations
|
// golang slices can't be typed cast. This shouldn't be a performance problem since
|
||||||
switch len(evl) {
|
// the Evidence size is capped.
|
||||||
case 0:
|
evidenceBzs := make([][]byte, len(evl))
|
||||||
return nil
|
for i := 0; i < len(evl); i++ {
|
||||||
case 1:
|
evidenceBzs[i] = evl[i].Bytes()
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
return merkle.SimpleHashFromByteSlices(evidenceBzs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (evl EvidenceList) String() string {
|
func (evl EvidenceList) String() string {
|
||||||
|
|
17
types/tx.go
17
types/tx.go
|
@ -31,18 +31,13 @@ type Txs []Tx
|
||||||
|
|
||||||
// Hash returns the simple Merkle root hash of the transactions.
|
// Hash returns the simple Merkle root hash of the transactions.
|
||||||
func (txs Txs) Hash() []byte {
|
func (txs Txs) Hash() []byte {
|
||||||
// Recursive impl.
|
// These allocations will be removed once Txs is switched to [][]byte,
|
||||||
// Copied from tendermint/crypto/merkle to avoid allocations
|
// ref #2603. This is because golang does not allow type casting slices without unsafe
|
||||||
switch len(txs) {
|
txBzs := make([][]byte, len(txs))
|
||||||
case 0:
|
for i := 0; i < len(txs); i++ {
|
||||||
return nil
|
txBzs[i] = txs[i]
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
return merkle.SimpleHashFromByteSlices(txBzs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index returns the index of this transaction in the list, or -1 if not found
|
// Index returns the index of this transaction in the list, or -1 if not found
|
||||||
|
|
Loading…
Reference in New Issue