|
package mempool
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
// Mempool defines the mempool interface.
|
|
//
|
|
// Updates to the mempool need to be synchronized with committing a block so
|
|
// apps can reset their transient state on Commit.
|
|
type Mempool interface {
|
|
// CheckTx executes a new transaction against the application to determine
|
|
// its validity and whether it should be added to the mempool.
|
|
CheckTx(tx types.Tx, callback func(*abci.Response)) error
|
|
|
|
// CheckTxWithInfo performs the same operation as CheckTx, but with extra
|
|
// meta data about the tx.
|
|
// Currently this metadata is the peer who sent it, used to prevent the tx
|
|
// from being gossiped back to them.
|
|
CheckTxWithInfo(tx types.Tx, callback func(*abci.Response), txInfo TxInfo) error
|
|
|
|
// ReapMaxBytesMaxGas reaps transactions from the mempool up to maxBytes
|
|
// bytes total with the condition that the total gasWanted must be less than
|
|
// maxGas.
|
|
// If both maxes are negative, there is no cap on the size of all returned
|
|
// transactions (~ all available transactions).
|
|
ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs
|
|
|
|
// ReapMaxTxs reaps up to max transactions from the mempool.
|
|
// If max is negative, there is no cap on the size of all returned
|
|
// transactions (~ all available transactions).
|
|
ReapMaxTxs(max int) types.Txs
|
|
|
|
// OnNewTx allows one to set a callback, which will be called when a new
|
|
// transaction is added to the mempool.
|
|
// Used by Reactor to broadcast new transactions to peers.
|
|
OnNewTx(cb func(Tx))
|
|
|
|
// Lock locks the mempool. The consensus must be able to hold lock to safely update.
|
|
Lock()
|
|
|
|
// Unlock unlocks the mempool.
|
|
Unlock()
|
|
|
|
// Update informs the mempool that the given txs were committed and can be discarded.
|
|
// NOTE: this should be called *after* block is committed by consensus.
|
|
// NOTE: unsafe; Lock/Unlock must be managed by caller
|
|
Update(blockHeight int64, blockTxs types.Txs, newPreFn PreCheckFunc, newPostFn PostCheckFunc) error
|
|
|
|
// FlushAppConn flushes the mempool connection to ensure async reqResCb calls are
|
|
// done. E.g. from CheckTx.
|
|
FlushAppConn() error
|
|
|
|
// Flush removes all transactions from the mempool and cache
|
|
Flush()
|
|
|
|
// TxsAvailable returns a channel which fires once for every height,
|
|
// and only when transactions are available in the mempool.
|
|
// NOTE: the returned channel may be nil if EnableTxsAvailable was not called.
|
|
TxsAvailable() <-chan struct{}
|
|
|
|
// EnableTxsAvailable initializes the TxsAvailable channel, ensuring it will
|
|
// trigger once every height when transactions are available.
|
|
EnableTxsAvailable()
|
|
|
|
// Size returns the number of transactions in the mempool.
|
|
Size() int
|
|
|
|
// TxsBytes returns the total size of all txs in the mempool.
|
|
TxsBytes() int64
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
// Tx wraps raw transaction and adds a few methods to extract useful
|
|
// information like where transaction is coming from, at which height it was
|
|
// received, etc.
|
|
type Tx interface {
|
|
Height() int64
|
|
HasSender(uint16) bool
|
|
Raw() types.Tx
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
// PreCheckFunc is an optional filter executed before CheckTx and rejects
|
|
// transaction if false is returned. An example would be to ensure that a
|
|
// transaction doesn't exceeded the block size.
|
|
type PreCheckFunc func(types.Tx) error
|
|
|
|
// PostCheckFunc is an optional filter executed after CheckTx and rejects
|
|
// transaction if false is returned. An example would be to ensure a
|
|
// transaction doesn't require more gas than available for the block.
|
|
type PostCheckFunc func(types.Tx, *abci.ResponseCheckTx) error
|
|
|
|
// TxInfo are parameters that get passed when attempting to add a tx to the
|
|
// mempool.
|
|
type TxInfo struct {
|
|
// We don't use p2p.ID here because it's too big. The gain is to store max 2
|
|
// bytes with each tx to identify the sender rather than 20 bytes.
|
|
SenderID uint16
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
// PreCheckAminoMaxBytes checks that the size of the transaction plus the amino
|
|
// overhead is smaller or equal to the expected maxBytes.
|
|
func PreCheckAminoMaxBytes(maxBytes int64) PreCheckFunc {
|
|
return func(tx types.Tx) error {
|
|
// We have to account for the amino overhead in the tx size as well
|
|
// NOTE: fieldNum = 1 as types.Block.Data contains Txs []Tx as first field.
|
|
// If this field order ever changes this needs to updated here accordingly.
|
|
// NOTE: if some []Tx are encoded without a parenting struct, the
|
|
// fieldNum is also equal to 1.
|
|
aminoOverhead := types.ComputeAminoOverhead(tx, 1)
|
|
txSize := int64(len(tx)) + aminoOverhead
|
|
if txSize > maxBytes {
|
|
return fmt.Errorf("Tx size (including amino overhead) is too big: %d, max: %d",
|
|
txSize, maxBytes)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// PostCheckMaxGas checks that the wanted gas is smaller or equal to the passed
|
|
// maxGas. Returns nil if maxGas is -1.
|
|
func PostCheckMaxGas(maxGas int64) PostCheckFunc {
|
|
return func(tx types.Tx, res *abci.ResponseCheckTx) error {
|
|
if maxGas == -1 {
|
|
return nil
|
|
}
|
|
if res.GasWanted < 0 {
|
|
return fmt.Errorf("gas wanted %d is negative",
|
|
res.GasWanted)
|
|
}
|
|
if res.GasWanted > maxGas {
|
|
return fmt.Errorf("gas wanted %d is greater than max gas %d",
|
|
res.GasWanted, maxGas)
|
|
}
|
|
return nil
|
|
}
|
|
}
|