- package types
-
- import (
- "bytes"
- "crypto/sha256"
- "errors"
- "fmt"
-
- "github.com/tendermint/tendermint/crypto/merkle"
- "github.com/tendermint/tendermint/crypto/tmhash"
- tmbytes "github.com/tendermint/tendermint/libs/bytes"
- tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
- )
-
- // 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
-
- // Key produces a fixed-length key for use in indexing.
- func (tx Tx) Key() TxKey { return sha256.Sum256(tx) }
-
- // 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 Merkle root hash of the transaction hashes.
- // i.e. the leaves of the tree are the hashes of the txs.
- func (txs Txs) Hash() []byte {
- // 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].Hash()
- }
- return merkle.HashFromByteSlices(txBzs)
- }
-
- // 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].Hash()
- }
- root, proofs := merkle.ProofsFromByteSlices(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 tmbytes.HexBytes `json:"root_hash"`
- Data Tx `json:"data"`
- Proof merkle.Proof `json:"proof"`
- }
-
- // Leaf returns the hash(tx), which is the leaf in the merkle tree which this proof refers to.
- func (tp TxProof) Leaf() []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.Leaf())
- if valid != nil {
- return errors.New("proof is not internally consistent")
- }
- return nil
- }
-
- func (tp TxProof) ToProto() tmproto.TxProof {
-
- pbProof := tp.Proof.ToProto()
-
- pbtp := tmproto.TxProof{
- RootHash: tp.RootHash,
- Data: tp.Data,
- Proof: pbProof,
- }
-
- return pbtp
- }
- func TxProofFromProto(pb tmproto.TxProof) (TxProof, error) {
-
- pbProof, err := merkle.ProofFromProto(pb.Proof)
- if err != nil {
- return TxProof{}, err
- }
-
- pbtp := TxProof{
- RootHash: pb.RootHash,
- Data: pb.Data,
- Proof: *pbProof,
- }
-
- return pbtp, nil
- }
-
- // ComputeProtoSizeForTxs wraps the transactions in tmproto.Data{} and calculates the size.
- // https://developers.google.com/protocol-buffers/docs/encoding
- func ComputeProtoSizeForTxs(txs []Tx) int64 {
- data := Data{Txs: txs}
- pdData := data.ToProto()
- return int64(pdData.Size())
- }
|