Files
tendermint/types/tx.go
Dev Ojha 12fa9d1cab crypto/merkle: Remove byter in favor of plain byte slices (#2595)
* 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
2018-10-10 12:46:09 -04:00

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"`
}