mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-09 06:33:16 +00:00
Addresses one of the concerns with #7041. Provides a mechanism (via the RPC interface) to delete a single transaction, described by its hash, from the mempool. The method returns an error if the transaction cannot be found. Once the transaction is removed it remains in the cache and cannot be resubmitted until the cache is cleared or it expires from the cache.
148 lines
3.8 KiB
Go
148 lines
3.8 KiB
Go
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())
|
|
}
|