mempool: Return type TxDesc instead of type btcutil.Tx
This will provide callers more information on the accepted transaction.
This commit is contained in:
parent
1a69eb0617
commit
2615fa0849
4 changed files with 61 additions and 57 deletions
|
@ -1185,7 +1185,7 @@ func (b *blockManager) handleNotifyMsg(notification *blockchain.Notification) {
|
|||
// Reinsert all of the transactions (except the coinbase) into
|
||||
// the transaction pool.
|
||||
for _, tx := range block.Transactions()[1:] {
|
||||
_, err := b.server.txMemPool.MaybeAcceptTransaction(tx,
|
||||
_, _, err := b.server.txMemPool.MaybeAcceptTransaction(tx,
|
||||
false, false)
|
||||
if err != nil {
|
||||
// Remove the transaction and all transactions
|
||||
|
|
|
@ -481,10 +481,10 @@ func (mp *TxPool) RemoveDoubleSpends(tx *btcutil.Tx) {
|
|||
// helper for maybeAcceptTransaction.
|
||||
//
|
||||
// This function MUST be called with the mempool lock held (for writes).
|
||||
func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32, fee int64) {
|
||||
func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32, fee int64) *TxDesc {
|
||||
// Add the transaction to the pool and mark the referenced outpoints
|
||||
// as spent by the pool.
|
||||
mp.pool[*tx.Hash()] = &TxDesc{
|
||||
txD := &TxDesc{
|
||||
TxDesc: mining.TxDesc{
|
||||
Tx: tx,
|
||||
Added: time.Now(),
|
||||
|
@ -493,6 +493,8 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil
|
|||
},
|
||||
StartingPriority: mining.CalcPriority(tx.MsgTx(), utxoView, height),
|
||||
}
|
||||
mp.pool[*tx.Hash()] = txD
|
||||
|
||||
for _, txIn := range tx.MsgTx().TxIn {
|
||||
mp.outpoints[txIn.PreviousOutPoint] = tx
|
||||
}
|
||||
|
@ -503,6 +505,8 @@ func (mp *TxPool) addTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil
|
|||
if mp.cfg.AddrIndex != nil {
|
||||
mp.cfg.AddrIndex.AddUnconfirmedTx(tx, utxoView)
|
||||
}
|
||||
|
||||
return txD
|
||||
}
|
||||
|
||||
// checkPoolDoubleSpend checks whether or not the passed transaction is
|
||||
|
@ -572,7 +576,7 @@ func (mp *TxPool) FetchTransaction(txHash *chainhash.Hash) (*btcutil.Tx, error)
|
|||
// more details.
|
||||
//
|
||||
// This function MUST be called with the mempool lock held (for writes).
|
||||
func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejectDupOrphans bool) ([]*chainhash.Hash, error) {
|
||||
func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejectDupOrphans bool) ([]*chainhash.Hash, *TxDesc, error) {
|
||||
txHash := tx.Hash()
|
||||
|
||||
// Don't accept the transaction if it already exists in the pool. This
|
||||
|
@ -583,7 +587,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
mp.isOrphanInPool(txHash)) {
|
||||
|
||||
str := fmt.Sprintf("already have transaction %v", txHash)
|
||||
return nil, txRuleError(wire.RejectDuplicate, str)
|
||||
return nil, nil, txRuleError(wire.RejectDuplicate, str)
|
||||
}
|
||||
|
||||
// Perform preliminary sanity checks on the transaction. This makes
|
||||
|
@ -592,16 +596,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
err := blockchain.CheckTransactionSanity(tx)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// A standalone transaction must not be a coinbase transaction.
|
||||
if blockchain.IsCoinBase(tx) {
|
||||
str := fmt.Sprintf("transaction %v is an individual coinbase",
|
||||
txHash)
|
||||
return nil, txRuleError(wire.RejectInvalid, str)
|
||||
return nil, nil, txRuleError(wire.RejectInvalid, str)
|
||||
}
|
||||
|
||||
// Don't accept transactions with a lock time after the maximum int32
|
||||
|
@ -611,7 +615,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
if tx.MsgTx().LockTime > math.MaxInt32 {
|
||||
str := fmt.Sprintf("transaction %v has a lock time after "+
|
||||
"2038 which is not accepted yet", txHash)
|
||||
return nil, txRuleError(wire.RejectNonstandard, str)
|
||||
return nil, nil, txRuleError(wire.RejectNonstandard, str)
|
||||
}
|
||||
|
||||
// Get the current height of the main chain. A standalone transaction
|
||||
|
@ -638,7 +642,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
}
|
||||
str := fmt.Sprintf("transaction %v is not standard: %v",
|
||||
txHash, err)
|
||||
return nil, txRuleError(rejectCode, str)
|
||||
return nil, nil, txRuleError(rejectCode, str)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -652,7 +656,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
// which examines the actual spend data and prevents double spends.
|
||||
err = mp.checkPoolDoubleSpend(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Fetch all of the unspent transaction outputs referenced by the inputs
|
||||
|
@ -662,16 +666,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
utxoView, err := mp.fetchInputUtxos(tx)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Don't allow the transaction if it exists in the main chain and is not
|
||||
// not already fully spent.
|
||||
txEntry := utxoView.LookupEntry(txHash)
|
||||
if txEntry != nil && !txEntry.IsFullySpent() {
|
||||
return nil, txRuleError(wire.RejectDuplicate,
|
||||
return nil, nil, txRuleError(wire.RejectDuplicate,
|
||||
"transaction already exists")
|
||||
}
|
||||
delete(utxoView.Entries(), *txHash)
|
||||
|
@ -692,7 +696,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
}
|
||||
}
|
||||
if len(missingParents) > 0 {
|
||||
return missingParents, nil
|
||||
return missingParents, nil, nil
|
||||
}
|
||||
|
||||
// Don't allow the transaction into the mempool unless its sequence
|
||||
|
@ -701,13 +705,13 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
sequenceLock, err := mp.cfg.CalcSequenceLock(tx, utxoView)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if !blockchain.SequenceLockActive(sequenceLock, nextBlockHeight,
|
||||
medianTimePast) {
|
||||
return nil, txRuleError(wire.RejectNonstandard,
|
||||
return nil, nil, txRuleError(wire.RejectNonstandard,
|
||||
"transaction's sequence locks on inputs not met")
|
||||
}
|
||||
|
||||
|
@ -719,9 +723,9 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
utxoView, mp.cfg.ChainParams)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Don't allow transactions with non-standard inputs if the network
|
||||
|
@ -738,7 +742,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
}
|
||||
str := fmt.Sprintf("transaction %v has a non-standard "+
|
||||
"input: %v", txHash, err)
|
||||
return nil, txRuleError(rejectCode, str)
|
||||
return nil, nil, txRuleError(rejectCode, str)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,15 +758,15 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
numSigOps, err := blockchain.CountP2SHSigOps(tx, false, utxoView)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
numSigOps += blockchain.CountSigOps(tx)
|
||||
if numSigOps > mp.cfg.Policy.MaxSigOpsPerTx {
|
||||
str := fmt.Sprintf("transaction %v has too many sigops: %d > %d",
|
||||
txHash, numSigOps, mp.cfg.Policy.MaxSigOpsPerTx)
|
||||
return nil, txRuleError(wire.RejectNonstandard, str)
|
||||
return nil, nil, txRuleError(wire.RejectNonstandard, str)
|
||||
}
|
||||
|
||||
// Don't allow transactions with fees too low to get into a mined block.
|
||||
|
@ -783,7 +787,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
str := fmt.Sprintf("transaction %v has %d fees which is under "+
|
||||
"the required amount of %d", txHash, txFee,
|
||||
minFee)
|
||||
return nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
return nil, nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
}
|
||||
|
||||
// Require that free transactions have sufficient priority to be mined
|
||||
|
@ -797,7 +801,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
str := fmt.Sprintf("transaction %v has insufficient "+
|
||||
"priority (%g <= %g)", txHash,
|
||||
currentPriority, mining.MinHighPriority)
|
||||
return nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
return nil, nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -815,7 +819,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
if mp.pennyTotal >= mp.cfg.Policy.FreeTxRelayLimit*10*1000 {
|
||||
str := fmt.Sprintf("transaction %v has been rejected "+
|
||||
"by the rate limiter due to low fees", txHash)
|
||||
return nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
return nil, nil, txRuleError(wire.RejectInsufficientFee, str)
|
||||
}
|
||||
oldTotal := mp.pennyTotal
|
||||
|
||||
|
@ -831,18 +835,18 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
txscript.StandardVerifyFlags, mp.cfg.SigCache)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
return nil, nil, chainRuleError(cerr)
|
||||
}
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Add to transaction pool.
|
||||
mp.addTransaction(utxoView, tx, bestHeight, txFee)
|
||||
txD := mp.addTransaction(utxoView, tx, bestHeight, txFee)
|
||||
|
||||
log.Debugf("Accepted transaction %v (pool size: %v)", txHash,
|
||||
len(mp.pool))
|
||||
|
||||
return nil, nil
|
||||
return nil, txD, nil
|
||||
}
|
||||
|
||||
// MaybeAcceptTransaction is the main workhorse for handling insertion of new
|
||||
|
@ -856,21 +860,21 @@ func (mp *TxPool) maybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit, rejec
|
|||
// be added to the orphan pool.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (mp *TxPool) MaybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*chainhash.Hash, error) {
|
||||
func (mp *TxPool) MaybeAcceptTransaction(tx *btcutil.Tx, isNew, rateLimit bool) ([]*chainhash.Hash, *TxDesc, error) {
|
||||
// Protect concurrent access.
|
||||
mp.mtx.Lock()
|
||||
hashes, err := mp.maybeAcceptTransaction(tx, isNew, rateLimit, true)
|
||||
hashes, txD, err := mp.maybeAcceptTransaction(tx, isNew, rateLimit, true)
|
||||
mp.mtx.Unlock()
|
||||
|
||||
return hashes, err
|
||||
return hashes, txD, err
|
||||
}
|
||||
|
||||
// processOrphans is the internal function which implements the public
|
||||
// ProcessOrphans. See the comment for ProcessOrphans for more details.
|
||||
//
|
||||
// This function MUST be called with the mempool lock held (for writes).
|
||||
func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
||||
var acceptedTxns []*btcutil.Tx
|
||||
func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*TxDesc {
|
||||
var acceptedTxns []*TxDesc
|
||||
|
||||
// Start with processing at least the passed transaction.
|
||||
processList := list.New()
|
||||
|
@ -901,7 +905,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
|||
|
||||
// Potentially accept an orphan into the tx pool.
|
||||
for _, tx := range orphans {
|
||||
missing, err := mp.maybeAcceptTransaction(
|
||||
missing, txD, err := mp.maybeAcceptTransaction(
|
||||
tx, true, true, false)
|
||||
if err != nil {
|
||||
// The orphan is now invalid, so there
|
||||
|
@ -925,7 +929,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
|||
// the orphan pool, and add it to the list of
|
||||
// transactions to process so any orphans that
|
||||
// depend on it are handled too.
|
||||
acceptedTxns = append(acceptedTxns, tx)
|
||||
acceptedTxns = append(acceptedTxns, txD)
|
||||
mp.removeOrphan(tx, false)
|
||||
processList.PushBack(tx)
|
||||
|
||||
|
@ -941,8 +945,8 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
|||
// by the accepted transactions since those are now definitive double
|
||||
// spends.
|
||||
mp.removeOrphanDoubleSpends(acceptedTx)
|
||||
for _, tx := range acceptedTxns {
|
||||
mp.removeOrphanDoubleSpends(tx)
|
||||
for _, txD := range acceptedTxns {
|
||||
mp.removeOrphanDoubleSpends(txD.Tx)
|
||||
}
|
||||
|
||||
return acceptedTxns
|
||||
|
@ -958,7 +962,7 @@ func (mp *TxPool) processOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
|||
// no transactions were moved from the orphan pool to the mempool.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
||||
func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*TxDesc {
|
||||
mp.mtx.Lock()
|
||||
acceptedTxns := mp.processOrphans(acceptedTx)
|
||||
mp.mtx.Unlock()
|
||||
|
@ -977,7 +981,7 @@ func (mp *TxPool) ProcessOrphans(acceptedTx *btcutil.Tx) []*btcutil.Tx {
|
|||
// the passed one being accepted.
|
||||
//
|
||||
// This function is safe for concurrent access.
|
||||
func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool) ([]*btcutil.Tx, error) {
|
||||
func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool) ([]*TxDesc, error) {
|
||||
log.Tracef("Processing transaction %v", tx.Hash())
|
||||
|
||||
// Protect concurrent access.
|
||||
|
@ -985,7 +989,7 @@ func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool
|
|||
defer mp.mtx.Unlock()
|
||||
|
||||
// Potentially accept the transaction to the memory pool.
|
||||
missingParents, err := mp.maybeAcceptTransaction(tx, true, rateLimit,
|
||||
missingParents, txD, err := mp.maybeAcceptTransaction(tx, true, rateLimit,
|
||||
true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -997,11 +1001,11 @@ func (mp *TxPool) ProcessTransaction(tx *btcutil.Tx, allowOrphan, rateLimit bool
|
|||
// are now available) and repeat for those accepted
|
||||
// transactions until there are no more.
|
||||
newTxs := mp.processOrphans(tx)
|
||||
acceptedTxs := make([]*btcutil.Tx, len(newTxs)+1)
|
||||
acceptedTxs := make([]*TxDesc, len(newTxs)+1)
|
||||
|
||||
// Add the parent transaction first so remote nodes
|
||||
// do not add orphans.
|
||||
acceptedTxs[0] = tx
|
||||
acceptedTxs[0] = txD
|
||||
copy(acceptedTxs[1:], newTxs)
|
||||
|
||||
return acceptedTxs, nil
|
||||
|
|
|
@ -442,10 +442,10 @@ func TestSimpleOrphanChain(t *testing.T) {
|
|||
"length does not match expected -- got %d, want %d",
|
||||
len(acceptedTxns), len(chainedTxns))
|
||||
}
|
||||
for _, tx := range acceptedTxns {
|
||||
for _, txD := range acceptedTxns {
|
||||
// Ensure the transaction is no longer in the orphan pool, is
|
||||
// now in the transaction pool, and is reported as available.
|
||||
testPoolMembership(tc, tx, false, true)
|
||||
testPoolMembership(tc, txD.Tx, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -784,10 +784,10 @@ func TestMultiInputOrphanDoubleSpend(t *testing.T) {
|
|||
"length does not match expected -- got %d, want %d",
|
||||
len(acceptedTxns), maxOrphans)
|
||||
}
|
||||
for _, tx := range acceptedTxns {
|
||||
for _, txD := range acceptedTxns {
|
||||
// Ensure the transaction is no longer in the orphan pool, is
|
||||
// in the transaction pool, and is reported as available.
|
||||
testPoolMembership(tc, tx, false, true)
|
||||
testPoolMembership(tc, txD.Tx, false, true)
|
||||
}
|
||||
|
||||
// Ensure the double spending orphan is no longer in the orphan pool and
|
||||
|
|
16
server.go
16
server.go
|
@ -972,18 +972,18 @@ func (s *server) RemoveRebroadcastInventory(iv *wire.InvVect) {
|
|||
// both websocket and getblocktemplate long poll clients of the passed
|
||||
// transactions. This function should be called whenever new transactions
|
||||
// are added to the mempool.
|
||||
func (s *server) AnnounceNewTransactions(newTxs []*btcutil.Tx) {
|
||||
func (s *server) AnnounceNewTransactions(newTxs []*mempool.TxDesc) {
|
||||
// Generate and relay inventory vectors for all newly accepted
|
||||
// transactions into the memory pool due to the original being
|
||||
// accepted.
|
||||
for _, tx := range newTxs {
|
||||
for _, txD := range newTxs {
|
||||
// Generate the inventory vector and relay it.
|
||||
iv := wire.NewInvVect(wire.InvTypeTx, tx.Hash())
|
||||
s.RelayInventory(iv, tx)
|
||||
iv := wire.NewInvVect(wire.InvTypeTx, txD.Tx.Hash())
|
||||
s.RelayInventory(iv, txD)
|
||||
|
||||
if s.rpcServer != nil {
|
||||
// Notify websocket clients about mempool transactions.
|
||||
s.rpcServer.ntfnMgr.NotifyMempoolTx(tx, true)
|
||||
s.rpcServer.ntfnMgr.NotifyMempoolTx(txD.Tx, true)
|
||||
|
||||
// Potentially notify any getblocktemplate long poll clients
|
||||
// about stale block templates due to the new transaction.
|
||||
|
@ -1319,14 +1319,14 @@ func (s *server) handleRelayInvMsg(state *peerState, msg relayMsg) {
|
|||
// Don't relay the transaction if there is a bloom
|
||||
// filter loaded and the transaction doesn't match it.
|
||||
if sp.filter.IsLoaded() {
|
||||
tx, ok := msg.data.(*btcutil.Tx)
|
||||
txD, ok := msg.data.(*mempool.TxDesc)
|
||||
if !ok {
|
||||
peerLog.Warnf("Underlying data for tx" +
|
||||
" inv relay is not a transaction")
|
||||
" inv relay is not a *mempool.TxDesc")
|
||||
return
|
||||
}
|
||||
|
||||
if !sp.filter.MatchTxAndUpdate(tx) {
|
||||
if !sp.filter.MatchTxAndUpdate(txD.Tx) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue