mirror of
https://github.com/fluencelabs/tendermint
synced 2025-07-31 04:01:55 +00:00
* crypto/merkle: Remove byter in favor of plain byte slices This PR is fully backwards compatible in terms of function output! (The Go API differs though) The only test case changes was to refactor it to be table driven. * Update godocs per review comments
126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package types
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/crypto/merkle"
|
|
"github.com/tendermint/tendermint/crypto/tmhash"
|
|
cmn "github.com/tendermint/tendermint/libs/common"
|
|
)
|
|
|
|
// Tx is an arbitrary byte array.
|
|
// NOTE: Tx has no types at this level, so when wire encoded it's just length-prefixed.
|
|
// Might we want types here ?
|
|
type Tx []byte
|
|
|
|
// Hash computes the TMHASH hash of the wire encoded transaction.
|
|
func (tx Tx) Hash() []byte {
|
|
return tmhash.Sum(tx)
|
|
}
|
|
|
|
// String returns the hex-encoded transaction as a string.
|
|
func (tx Tx) String() string {
|
|
return fmt.Sprintf("Tx{%X}", []byte(tx))
|
|
}
|
|
|
|
// Txs is a slice of Tx.
|
|
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)
|
|
}
|
|
}
|
|
|
|
// Index returns the index of this transaction in the list, or -1 if not found
|
|
func (txs Txs) Index(tx Tx) int {
|
|
for i := range txs {
|
|
if bytes.Equal(txs[i], tx) {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// IndexByHash returns the index of this transaction hash in the list, or -1 if not found
|
|
func (txs Txs) IndexByHash(hash []byte) int {
|
|
for i := range txs {
|
|
if bytes.Equal(txs[i].Hash(), hash) {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// Proof returns a simple merkle proof for this node.
|
|
// Panics if i < 0 or i >= len(txs)
|
|
// TODO: optimize this!
|
|
func (txs Txs) Proof(i int) TxProof {
|
|
l := len(txs)
|
|
bzs := make([][]byte, l)
|
|
for i := 0; i < l; i++ {
|
|
bzs[i] = txs[i]
|
|
}
|
|
root, proofs := merkle.SimpleProofsFromByteSlices(bzs)
|
|
|
|
return TxProof{
|
|
RootHash: root,
|
|
Data: txs[i],
|
|
Proof: *proofs[i],
|
|
}
|
|
}
|
|
|
|
// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree.
|
|
type TxProof struct {
|
|
RootHash cmn.HexBytes
|
|
Data Tx
|
|
Proof merkle.SimpleProof
|
|
}
|
|
|
|
// LeadHash returns the hash of the this proof refers to.
|
|
func (tp TxProof) LeafHash() []byte {
|
|
return tp.Data.Hash()
|
|
}
|
|
|
|
// Validate verifies the proof. It returns nil if the RootHash matches the dataHash argument,
|
|
// and if the proof is internally consistent. Otherwise, it returns a sensible error.
|
|
func (tp TxProof) Validate(dataHash []byte) error {
|
|
if !bytes.Equal(dataHash, tp.RootHash) {
|
|
return errors.New("Proof matches different data hash")
|
|
}
|
|
if tp.Proof.Index < 0 {
|
|
return errors.New("Proof index cannot be negative")
|
|
}
|
|
if tp.Proof.Total <= 0 {
|
|
return errors.New("Proof total must be positive")
|
|
}
|
|
valid := tp.Proof.Verify(tp.RootHash, tp.LeafHash())
|
|
if valid != nil {
|
|
return errors.New("Proof is not internally consistent")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TxResult contains results of executing the transaction.
|
|
//
|
|
// One usage is indexing transaction results.
|
|
type TxResult struct {
|
|
Height int64 `json:"height"`
|
|
Index uint32 `json:"index"`
|
|
Tx Tx `json:"tx"`
|
|
Result abci.ResponseDeliverTx `json:"result"`
|
|
}
|