mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-27 08:22:34 +00:00
Convert to use new btcutil.Tx and btcchain APIs.
This commit updates btcd to work with the new btcchain APIs which now accept btcutil.Tx instead of raw btcwire.MsgTx. It also modifies the transaction memory pool to store btcutil.Tx. This is part of the ongoing transaction hash optimization effort noted in conformal/btcd#25.
This commit is contained in:
parent
7d8bb5ab4c
commit
08fc3050a3
@ -55,7 +55,7 @@ type donePeerMsg struct {
|
|||||||
// txMsg packages a bitcoin tx message and the peer it came from together
|
// txMsg packages a bitcoin tx message and the peer it came from together
|
||||||
// so the block handler has access to that information.
|
// so the block handler has access to that information.
|
||||||
type txMsg struct {
|
type txMsg struct {
|
||||||
tx *btcwire.MsgTx
|
tx *btcutil.Tx
|
||||||
peer *peer
|
peer *peer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,12 +269,12 @@ func (b *blockManager) logBlockHeight(numTx, height int64, latestHash *btcwire.S
|
|||||||
// handleTxMsg handles transaction messages from all peers.
|
// handleTxMsg handles transaction messages from all peers.
|
||||||
func (b *blockManager) handleTxMsg(tmsg *txMsg) {
|
func (b *blockManager) handleTxMsg(tmsg *txMsg) {
|
||||||
// Keep track of which peer the tx was sent from.
|
// Keep track of which peer the tx was sent from.
|
||||||
txHash, _ := tmsg.tx.TxSha()
|
txHash := tmsg.tx.Sha()
|
||||||
|
|
||||||
// If we didn't ask for this block then the peer is misbehaving.
|
// If we didn't ask for this block then the peer is misbehaving.
|
||||||
if _, ok := tmsg.peer.requestedTxns[txHash]; !ok {
|
if _, ok := tmsg.peer.requestedTxns[*txHash]; !ok {
|
||||||
log.Warnf("BMGR: Got unrequested transaction %v from %s -- "+
|
log.Warnf("BMGR: Got unrequested transaction %v from %s -- "+
|
||||||
"disconnecting", &txHash, tmsg.peer.addr)
|
"disconnecting", txHash, tmsg.peer.addr)
|
||||||
tmsg.peer.Disconnect()
|
tmsg.peer.Disconnect()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -287,8 +287,8 @@ func (b *blockManager) handleTxMsg(tmsg *txMsg) {
|
|||||||
// already knows about it and as such we shouldn't have any more
|
// already knows about it and as such we shouldn't have any more
|
||||||
// instances of trying to fetch it, or we failed to insert and thus
|
// instances of trying to fetch it, or we failed to insert and thus
|
||||||
// we'll retry next time we get an inv.
|
// we'll retry next time we get an inv.
|
||||||
delete(tmsg.peer.requestedTxns, txHash)
|
delete(tmsg.peer.requestedTxns, *txHash)
|
||||||
delete(b.requestedTxns, txHash)
|
delete(b.requestedTxns, *txHash)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// When the error is a rule error, it means the transaction was
|
// When the error is a rule error, it means the transaction was
|
||||||
@ -646,7 +646,7 @@ func (b *blockManager) handleNotifyMsg(notification *btcchain.Notification) {
|
|||||||
|
|
||||||
// Remove all of the transactions (except the coinbase) in the
|
// Remove all of the transactions (except the coinbase) in the
|
||||||
// connected block from the transaction pool.
|
// connected block from the transaction pool.
|
||||||
for _, tx := range block.MsgBlock().Transactions[1:] {
|
for _, tx := range block.Transactions()[1:] {
|
||||||
b.server.txMemPool.removeTransaction(tx)
|
b.server.txMemPool.removeTransaction(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +666,7 @@ func (b *blockManager) handleNotifyMsg(notification *btcchain.Notification) {
|
|||||||
|
|
||||||
// Reinsert all of the transactions (except the coinbase) into
|
// Reinsert all of the transactions (except the coinbase) into
|
||||||
// the transaction pool.
|
// the transaction pool.
|
||||||
for _, tx := range block.MsgBlock().Transactions[1:] {
|
for _, tx := range block.Transactions()[1:] {
|
||||||
err := b.server.txMemPool.ProcessTransaction(tx)
|
err := b.server.txMemPool.ProcessTransaction(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Remove the transaction and all transactions
|
// Remove the transaction and all transactions
|
||||||
@ -695,7 +695,7 @@ func (b *blockManager) NewPeer(p *peer) {
|
|||||||
|
|
||||||
// QueueTx adds the passed transaction message and peer to the block handling
|
// QueueTx adds the passed transaction message and peer to the block handling
|
||||||
// queue.
|
// queue.
|
||||||
func (b *blockManager) QueueTx(tx *btcwire.MsgTx, p *peer) {
|
func (b *blockManager) QueueTx(tx *btcutil.Tx, p *peer) {
|
||||||
// Don't accept more transactions if we're shutting down.
|
// Don't accept more transactions if we're shutting down.
|
||||||
if atomic.LoadInt32(&b.shutdown) != 0 {
|
if atomic.LoadInt32(&b.shutdown) != 0 {
|
||||||
p.txProcessed <- false
|
p.txProcessed <- false
|
||||||
|
131
mempool.go
131
mempool.go
@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/conformal/btcchain"
|
"github.com/conformal/btcchain"
|
||||||
"github.com/conformal/btcdb"
|
"github.com/conformal/btcdb"
|
||||||
"github.com/conformal/btcscript"
|
"github.com/conformal/btcscript"
|
||||||
|
"github.com/conformal/btcutil"
|
||||||
"github.com/conformal/btcwire"
|
"github.com/conformal/btcwire"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -77,10 +78,10 @@ const (
|
|||||||
type txMemPool struct {
|
type txMemPool struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
server *server
|
server *server
|
||||||
pool map[btcwire.ShaHash]*btcwire.MsgTx
|
pool map[btcwire.ShaHash]*btcutil.Tx
|
||||||
orphans map[btcwire.ShaHash]*btcwire.MsgTx
|
orphans map[btcwire.ShaHash]*btcutil.Tx
|
||||||
orphansByPrev map[btcwire.ShaHash]*list.List
|
orphansByPrev map[btcwire.ShaHash]*list.List
|
||||||
outpoints map[btcwire.OutPoint]*btcwire.MsgTx
|
outpoints map[btcwire.OutPoint]*btcutil.Tx
|
||||||
}
|
}
|
||||||
|
|
||||||
// isDust returns whether or not the passed transaction output amount is
|
// isDust returns whether or not the passed transaction output amount is
|
||||||
@ -191,11 +192,13 @@ func checkPkScriptStandard(pkScript []byte) error {
|
|||||||
// finalized, conforming to more stringent size constraints, having scripts
|
// finalized, conforming to more stringent size constraints, having scripts
|
||||||
// of recognized forms, and not containing "dust" outputs (those that are
|
// of recognized forms, and not containing "dust" outputs (those that are
|
||||||
// so small it costs more to process them than they are worth).
|
// so small it costs more to process them than they are worth).
|
||||||
func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error {
|
func checkTransactionStandard(tx *btcutil.Tx, height int64) error {
|
||||||
|
msgTx := tx.MsgTx()
|
||||||
|
|
||||||
// The transaction must be a currently supported version.
|
// The transaction must be a currently supported version.
|
||||||
if tx.Version > btcwire.TxVersion || tx.Version < 1 {
|
if msgTx.Version > btcwire.TxVersion || msgTx.Version < 1 {
|
||||||
str := fmt.Sprintf("transaction version %d is not in the "+
|
str := fmt.Sprintf("transaction version %d is not in the "+
|
||||||
"valid range of %d-%d", tx.Version, 1,
|
"valid range of %d-%d", msgTx.Version, 1,
|
||||||
btcwire.TxVersion)
|
btcwire.TxVersion)
|
||||||
return TxRuleError(str)
|
return TxRuleError(str)
|
||||||
}
|
}
|
||||||
@ -212,7 +215,7 @@ func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error {
|
|||||||
// size of a transaction. This also helps mitigate CPU exhaustion
|
// size of a transaction. This also helps mitigate CPU exhaustion
|
||||||
// attacks.
|
// attacks.
|
||||||
var serializedTxBuf bytes.Buffer
|
var serializedTxBuf bytes.Buffer
|
||||||
err := tx.Serialize(&serializedTxBuf)
|
err := msgTx.Serialize(&serializedTxBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -223,7 +226,7 @@ func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error {
|
|||||||
return TxRuleError(str)
|
return TxRuleError(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, txIn := range tx.TxIn {
|
for i, txIn := range msgTx.TxIn {
|
||||||
// Each transaction input signature script must not exceed the
|
// Each transaction input signature script must not exceed the
|
||||||
// maximum size allowed for a standard transaction. See
|
// maximum size allowed for a standard transaction. See
|
||||||
// the comment on maxStandardSigScriptSize for more details.
|
// the comment on maxStandardSigScriptSize for more details.
|
||||||
@ -247,7 +250,7 @@ func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error {
|
|||||||
|
|
||||||
// None of the output public key scripts can be a non-standard script or
|
// None of the output public key scripts can be a non-standard script or
|
||||||
// be "dust".
|
// be "dust".
|
||||||
for i, txOut := range tx.TxOut {
|
for i, txOut := range msgTx.TxOut {
|
||||||
err := checkPkScriptStandard(txOut.PkScript)
|
err := checkPkScriptStandard(txOut.PkScript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
str := fmt.Sprintf("transaction output %d: %v", i, err)
|
str := fmt.Sprintf("transaction output %d: %v", i, err)
|
||||||
@ -270,7 +273,7 @@ func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error {
|
|||||||
// pushes. This help prevent resource exhaustion attacks by "creative" use of
|
// pushes. This help prevent resource exhaustion attacks by "creative" use of
|
||||||
// scripts that are super expensive to process like OP_DUP OP_CHECKSIG OP_DROP
|
// scripts that are super expensive to process like OP_DUP OP_CHECKSIG OP_DROP
|
||||||
// repeated a large number of times followed by a final OP_TRUE.
|
// repeated a large number of times followed by a final OP_TRUE.
|
||||||
func checkInputsStandard(tx *btcwire.MsgTx) error {
|
func checkInputsStandard(tx *btcutil.Tx) error {
|
||||||
// TODO(davec): Implement
|
// TODO(davec): Implement
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -287,11 +290,11 @@ func (mp *txMemPool) removeOrphan(txHash *btcwire.ShaHash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove the reference from the previous orphan index.
|
// Remove the reference from the previous orphan index.
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
originTxHash := txIn.PreviousOutpoint.Hash
|
originTxHash := txIn.PreviousOutpoint.Hash
|
||||||
if orphans, exists := mp.orphansByPrev[originTxHash]; exists {
|
if orphans, exists := mp.orphansByPrev[originTxHash]; exists {
|
||||||
for e := orphans.Front(); e != nil; e = e.Next() {
|
for e := orphans.Front(); e != nil; e = e.Next() {
|
||||||
if e.Value.(*btcwire.MsgTx) == tx {
|
if e.Value.(*btcutil.Tx) == tx {
|
||||||
orphans.Remove(e)
|
orphans.Remove(e)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -349,13 +352,13 @@ func (mp *txMemPool) limitNumOrphans() error {
|
|||||||
// addOrphan adds an orphan transaction to the orphan pool.
|
// addOrphan adds an orphan transaction to the orphan pool.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for writes).
|
// This function MUST be called with the mempool lock held (for writes).
|
||||||
func (mp *txMemPool) addOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash) {
|
func (mp *txMemPool) addOrphan(tx *btcutil.Tx) {
|
||||||
// Limit the number orphan transactions to prevent memory exhaustion. A
|
// Limit the number orphan transactions to prevent memory exhaustion. A
|
||||||
// random orphan is evicted to make room if needed.
|
// random orphan is evicted to make room if needed.
|
||||||
mp.limitNumOrphans()
|
mp.limitNumOrphans()
|
||||||
|
|
||||||
mp.orphans[*txHash] = tx
|
mp.orphans[*tx.Sha()] = tx
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
originTxHash := txIn.PreviousOutpoint.Hash
|
originTxHash := txIn.PreviousOutpoint.Hash
|
||||||
if mp.orphansByPrev[originTxHash] == nil {
|
if mp.orphansByPrev[originTxHash] == nil {
|
||||||
mp.orphansByPrev[originTxHash] = list.New()
|
mp.orphansByPrev[originTxHash] = list.New()
|
||||||
@ -363,14 +366,14 @@ func (mp *txMemPool) addOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash) {
|
|||||||
mp.orphansByPrev[originTxHash].PushBack(tx)
|
mp.orphansByPrev[originTxHash].PushBack(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("TXMP: Stored orphan transaction %v (total: %d)", txHash,
|
log.Debugf("TXMP: Stored orphan transaction %v (total: %d)", tx.Sha(),
|
||||||
len(mp.orphans))
|
len(mp.orphans))
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybeAddOrphan potentially adds an orphan to the orphan pool.
|
// maybeAddOrphan potentially adds an orphan to the orphan pool.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for writes).
|
// This function MUST be called with the mempool lock held (for writes).
|
||||||
func (mp *txMemPool) maybeAddOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash) error {
|
func (mp *txMemPool) maybeAddOrphan(tx *btcutil.Tx) error {
|
||||||
// Ignore orphan transactions that are too large. This helps avoid
|
// Ignore orphan transactions that are too large. This helps avoid
|
||||||
// a memory exhaustion attack based on sending a lot of really large
|
// a memory exhaustion attack based on sending a lot of really large
|
||||||
// orphans. In the case there is a valid transaction larger than this,
|
// orphans. In the case there is a valid transaction larger than this,
|
||||||
@ -382,7 +385,7 @@ func (mp *txMemPool) maybeAddOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash)
|
|||||||
// maxOrphanTxSize * maxOrphanTransactions (which is 500MB as of the
|
// maxOrphanTxSize * maxOrphanTransactions (which is 500MB as of the
|
||||||
// time this comment was written).
|
// time this comment was written).
|
||||||
var serializedTxBuf bytes.Buffer
|
var serializedTxBuf bytes.Buffer
|
||||||
err := tx.Serialize(&serializedTxBuf)
|
err := tx.MsgTx().Serialize(&serializedTxBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -395,7 +398,7 @@ func (mp *txMemPool) maybeAddOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the orphan if the none of the above disqualified it.
|
// Add the orphan if the none of the above disqualified it.
|
||||||
mp.addOrphan(tx, txHash)
|
mp.addOrphan(tx)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -471,11 +474,11 @@ func (mp *txMemPool) HaveTransaction(hash *btcwire.ShaHash) bool {
|
|||||||
// removeTransaction removes the passed transaction from the memory pool.
|
// removeTransaction removes the passed transaction from the memory pool.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for writes).
|
// This function MUST be called with the mempool lock held (for writes).
|
||||||
func (mp *txMemPool) removeTransaction(tx *btcwire.MsgTx) {
|
func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) {
|
||||||
// Remove any transactions which rely on this one.
|
// Remove any transactions which rely on this one.
|
||||||
txHash, _ := tx.TxSha()
|
txHash := tx.Sha()
|
||||||
for i := uint32(0); i < uint32(len(tx.TxOut)); i++ {
|
for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ {
|
||||||
outpoint := btcwire.NewOutPoint(&txHash, i)
|
outpoint := btcwire.NewOutPoint(txHash, i)
|
||||||
if txRedeemer, exists := mp.outpoints[*outpoint]; exists {
|
if txRedeemer, exists := mp.outpoints[*outpoint]; exists {
|
||||||
mp.removeTransaction(txRedeemer)
|
mp.removeTransaction(txRedeemer)
|
||||||
}
|
}
|
||||||
@ -483,11 +486,11 @@ func (mp *txMemPool) removeTransaction(tx *btcwire.MsgTx) {
|
|||||||
|
|
||||||
// Remove the transaction and mark the referenced outpoints as unspent
|
// Remove the transaction and mark the referenced outpoints as unspent
|
||||||
// by the pool.
|
// by the pool.
|
||||||
if tx, exists := mp.pool[txHash]; exists {
|
if tx, exists := mp.pool[*txHash]; exists {
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
delete(mp.outpoints, txIn.PreviousOutpoint)
|
delete(mp.outpoints, txIn.PreviousOutpoint)
|
||||||
}
|
}
|
||||||
delete(mp.pool, txHash)
|
delete(mp.pool, *txHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -496,11 +499,11 @@ func (mp *txMemPool) removeTransaction(tx *btcwire.MsgTx) {
|
|||||||
// helper for maybeAcceptTransaction.
|
// helper for maybeAcceptTransaction.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for writes).
|
// This function MUST be called with the mempool lock held (for writes).
|
||||||
func (mp *txMemPool) addTransaction(tx *btcwire.MsgTx, txHash *btcwire.ShaHash) {
|
func (mp *txMemPool) addTransaction(tx *btcutil.Tx) {
|
||||||
// Add the transaction to the pool and mark the referenced outpoints
|
// Add the transaction to the pool and mark the referenced outpoints
|
||||||
// as spent by the pool.
|
// as spent by the pool.
|
||||||
mp.pool[*txHash] = tx
|
mp.pool[*tx.Sha()] = tx
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
mp.outpoints[txIn.PreviousOutpoint] = tx
|
mp.outpoints[txIn.PreviousOutpoint] = tx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,12 +514,11 @@ func (mp *txMemPool) addTransaction(tx *btcwire.MsgTx, txHash *btcwire.ShaHash)
|
|||||||
// main chain.
|
// main chain.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for reads).
|
// This function MUST be called with the mempool lock held (for reads).
|
||||||
func (mp *txMemPool) checkPoolDoubleSpend(tx *btcwire.MsgTx) error {
|
func (mp *txMemPool) checkPoolDoubleSpend(tx *btcutil.Tx) error {
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range tx.MsgTx().TxIn {
|
||||||
if txR, exists := mp.outpoints[txIn.PreviousOutpoint]; exists {
|
if txR, exists := mp.outpoints[txIn.PreviousOutpoint]; exists {
|
||||||
hash, _ := txR.TxSha()
|
|
||||||
str := fmt.Sprintf("transaction %v in the pool "+
|
str := fmt.Sprintf("transaction %v in the pool "+
|
||||||
"already spends the same coins", hash)
|
"already spends the same coins", txR.Sha())
|
||||||
return TxRuleError(str)
|
return TxRuleError(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,7 +531,7 @@ func (mp *txMemPool) checkPoolDoubleSpend(tx *btcwire.MsgTx) error {
|
|||||||
// fetch any missing inputs from the transaction pool.
|
// fetch any missing inputs from the transaction pool.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for reads).
|
// This function MUST be called with the mempool lock held (for reads).
|
||||||
func (mp *txMemPool) fetchInputTransactions(tx *btcwire.MsgTx) (btcchain.TxStore, error) {
|
func (mp *txMemPool) fetchInputTransactions(tx *btcutil.Tx) (btcchain.TxStore, error) {
|
||||||
txStore, err := mp.server.blockManager.blockChain.FetchTransactionStore(tx)
|
txStore, err := mp.server.blockManager.blockChain.FetchTransactionStore(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -541,7 +543,7 @@ func (mp *txMemPool) fetchInputTransactions(tx *btcwire.MsgTx) (btcchain.TxStore
|
|||||||
if poolTx, exists := mp.pool[*txD.Hash]; exists {
|
if poolTx, exists := mp.pool[*txD.Hash]; exists {
|
||||||
txD.Tx = poolTx
|
txD.Tx = poolTx
|
||||||
txD.BlockHeight = mempoolHeight
|
txD.BlockHeight = mempoolHeight
|
||||||
txD.Spent = make([]bool, len(poolTx.TxOut))
|
txD.Spent = make([]bool, len(poolTx.MsgTx().TxOut))
|
||||||
txD.Err = nil
|
txD.Err = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -555,7 +557,7 @@ func (mp *txMemPool) fetchInputTransactions(tx *btcwire.MsgTx) (btcchain.TxStore
|
|||||||
// orphans.
|
// orphans.
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (mp *txMemPool) FetchTransaction(txHash *btcwire.ShaHash) (*btcwire.MsgTx, error) {
|
func (mp *txMemPool) FetchTransaction(txHash *btcwire.ShaHash) (*btcutil.Tx, error) {
|
||||||
// Protect concurrent access.
|
// Protect concurrent access.
|
||||||
mp.RLock()
|
mp.RLock()
|
||||||
defer mp.RUnlock()
|
defer mp.RUnlock()
|
||||||
@ -573,17 +575,14 @@ func (mp *txMemPool) FetchTransaction(txHash *btcwire.ShaHash) (*btcwire.MsgTx,
|
|||||||
// rules, orphan transaction handling, and insertion into the memory pool.
|
// rules, orphan transaction handling, and insertion into the memory pool.
|
||||||
//
|
//
|
||||||
// This function MUST be called with the mempool lock held (for writes).
|
// This function MUST be called with the mempool lock held (for writes).
|
||||||
func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) error {
|
func (mp *txMemPool) maybeAcceptTransaction(tx *btcutil.Tx, isOrphan *bool) error {
|
||||||
*isOrphan = false
|
*isOrphan = false
|
||||||
txHash, err := tx.TxSha()
|
txHash := tx.Sha()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't accept the transaction if it already exists in the pool. This
|
// Don't accept the transaction if it already exists in the pool. This
|
||||||
// applies to orphan transactions as well. This check is intended to
|
// applies to orphan transactions as well. This check is intended to
|
||||||
// be a quick check to weed out duplicates.
|
// be a quick check to weed out duplicates.
|
||||||
if mp.haveTransaction(&txHash) {
|
if mp.haveTransaction(txHash) {
|
||||||
str := fmt.Sprintf("already have transaction %v", txHash)
|
str := fmt.Sprintf("already have transaction %v", txHash)
|
||||||
return TxRuleError(str)
|
return TxRuleError(str)
|
||||||
}
|
}
|
||||||
@ -591,7 +590,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
// Perform preliminary sanity checks on the transaction. This makes
|
// Perform preliminary sanity checks on the transaction. This makes
|
||||||
// use of btcchain which contains the invariant rules for what
|
// use of btcchain which contains the invariant rules for what
|
||||||
// transactions are allowed into blocks.
|
// transactions are allowed into blocks.
|
||||||
err = btcchain.CheckTransactionSanity(tx)
|
err := btcchain.CheckTransactionSanity(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(btcchain.RuleError); ok {
|
if _, ok := err.(btcchain.RuleError); ok {
|
||||||
return TxRuleError(err.Error())
|
return TxRuleError(err.Error())
|
||||||
@ -610,7 +609,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
// value for now. This is an artifact of older bitcoind clients which
|
// value for now. This is an artifact of older bitcoind clients which
|
||||||
// treated this field as an int32 and would treat anything larger
|
// treated this field as an int32 and would treat anything larger
|
||||||
// incorrectly (as negative).
|
// incorrectly (as negative).
|
||||||
if tx.LockTime > math.MaxInt32 {
|
if tx.MsgTx().LockTime > math.MaxInt32 {
|
||||||
str := fmt.Sprintf("transaction %v is has a lock time after "+
|
str := fmt.Sprintf("transaction %v is has a lock time after "+
|
||||||
"2038 which is not accepted yet", txHash)
|
"2038 which is not accepted yet", txHash)
|
||||||
return TxRuleError(str)
|
return TxRuleError(str)
|
||||||
@ -658,7 +657,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
|
|
||||||
// Don't allow the transaction if it exists in the main chain and is not
|
// Don't allow the transaction if it exists in the main chain and is not
|
||||||
// not already fully spent.
|
// not already fully spent.
|
||||||
if txD, exists := txStore[txHash]; exists && txD.Err == nil {
|
if txD, exists := txStore[*txHash]; exists && txD.Err == nil {
|
||||||
for _, isOutputSpent := range txD.Spent {
|
for _, isOutputSpent := range txD.Spent {
|
||||||
if !isOutputSpent {
|
if !isOutputSpent {
|
||||||
str := fmt.Sprintf("transaction already exists")
|
str := fmt.Sprintf("transaction already exists")
|
||||||
@ -666,7 +665,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete(txStore, txHash)
|
delete(txStore, *txHash)
|
||||||
|
|
||||||
// Transaction is an orphan if any of the inputs don't exist.
|
// Transaction is an orphan if any of the inputs don't exist.
|
||||||
for _, txD := range txStore {
|
for _, txD := range txStore {
|
||||||
@ -707,7 +706,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
// Verify crypto signatures for each input and reject the transaction if
|
// Verify crypto signatures for each input and reject the transaction if
|
||||||
// any don't verify.
|
// any don't verify.
|
||||||
flags := btcscript.ScriptBip16 | btcscript.ScriptCanonicalSignatures
|
flags := btcscript.ScriptBip16 | btcscript.ScriptCanonicalSignatures
|
||||||
err = btcchain.ValidateTransactionScripts(tx, &txHash, txStore, flags)
|
err = btcchain.ValidateTransactionScripts(tx, txStore, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -715,7 +714,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
// TODO(davec): Rate-limit free transactions
|
// TODO(davec): Rate-limit free transactions
|
||||||
|
|
||||||
// Add to transaction pool.
|
// Add to transaction pool.
|
||||||
mp.addTransaction(tx, &txHash)
|
mp.addTransaction(tx)
|
||||||
|
|
||||||
log.Debugf("TXMP: Accepted transaction %v (pool size: %v)", txHash,
|
log.Debugf("TXMP: Accepted transaction %v (pool size: %v)", txHash,
|
||||||
len(mp.pool))
|
len(mp.pool))
|
||||||
@ -723,7 +722,7 @@ func (mp *txMemPool) maybeAcceptTransaction(tx *btcwire.MsgTx, isOrphan *bool) e
|
|||||||
// TODO(davec): Notifications
|
// TODO(davec): Notifications
|
||||||
|
|
||||||
// Generate the inventory vector and relay it.
|
// Generate the inventory vector and relay it.
|
||||||
iv := btcwire.NewInvVect(btcwire.InvTypeTx, &txHash)
|
iv := btcwire.NewInvVect(btcwire.InvTypeTx, txHash)
|
||||||
mp.server.RelayInventory(iv)
|
mp.server.RelayInventory(iv)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -757,31 +756,28 @@ func (mp *txMemPool) processOrphans(hash *btcwire.ShaHash) error {
|
|||||||
var enext *list.Element
|
var enext *list.Element
|
||||||
for e := orphans.Front(); e != nil; e = enext {
|
for e := orphans.Front(); e != nil; e = enext {
|
||||||
enext = e.Next()
|
enext = e.Next()
|
||||||
tx := e.Value.(*btcwire.MsgTx)
|
tx := e.Value.(*btcutil.Tx)
|
||||||
|
|
||||||
// Remove the orphan from the orphan pool.
|
// Remove the orphan from the orphan pool.
|
||||||
orphanHash, err := tx.TxSha()
|
orphanHash := tx.Sha()
|
||||||
if err != nil {
|
mp.removeOrphan(orphanHash)
|
||||||
return err
|
|
||||||
}
|
|
||||||
mp.removeOrphan(&orphanHash)
|
|
||||||
|
|
||||||
// Potentially accept the transaction into the
|
// Potentially accept the transaction into the
|
||||||
// transaction pool.
|
// transaction pool.
|
||||||
var isOrphan bool
|
var isOrphan bool
|
||||||
err = mp.maybeAcceptTransaction(tx, &isOrphan)
|
err := mp.maybeAcceptTransaction(tx, &isOrphan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isOrphan {
|
if isOrphan {
|
||||||
mp.removeOrphan(&orphanHash)
|
mp.removeOrphan(orphanHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this transaction to the list of transactions to
|
// Add this transaction to the list of transactions to
|
||||||
// process so any orphans that depend on this one are
|
// process so any orphans that depend on this one are
|
||||||
// handled too.
|
// handled too.
|
||||||
processHashes.PushBack(&orphanHash)
|
processHashes.PushBack(orphanHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,20 +790,17 @@ func (mp *txMemPool) processOrphans(hash *btcwire.ShaHash) error {
|
|||||||
// rules, orphan transaction handling, and insertion into the memory pool.
|
// rules, orphan transaction handling, and insertion into the memory pool.
|
||||||
//
|
//
|
||||||
// This function is safe for concurrent access.
|
// This function is safe for concurrent access.
|
||||||
func (mp *txMemPool) ProcessTransaction(tx *btcwire.MsgTx) error {
|
func (mp *txMemPool) ProcessTransaction(tx *btcutil.Tx) error {
|
||||||
// Protect concurrent access.
|
// Protect concurrent access.
|
||||||
mp.Lock()
|
mp.Lock()
|
||||||
defer mp.Unlock()
|
defer mp.Unlock()
|
||||||
|
|
||||||
txHash, err := tx.TxSha()
|
txHash := tx.Sha()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Tracef("TXMP: Processing transaction %v", txHash)
|
log.Tracef("TXMP: Processing transaction %v", txHash)
|
||||||
|
|
||||||
// Potentially accept the transaction to the memory pool.
|
// Potentially accept the transaction to the memory pool.
|
||||||
var isOrphan bool
|
var isOrphan bool
|
||||||
err = mp.maybeAcceptTransaction(tx, &isOrphan)
|
err := mp.maybeAcceptTransaction(tx, &isOrphan)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -816,14 +809,14 @@ func (mp *txMemPool) ProcessTransaction(tx *btcwire.MsgTx) error {
|
|||||||
// Accept any orphan transactions that depend on this
|
// Accept any orphan transactions that depend on this
|
||||||
// transaction (they are no longer orphans) and repeat for those
|
// transaction (they are no longer orphans) and repeat for those
|
||||||
// accepted transactions until there are no more.
|
// accepted transactions until there are no more.
|
||||||
err = mp.processOrphans(&txHash)
|
err := mp.processOrphans(txHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// When the transaction is an orphan (has inputs missing),
|
// When the transaction is an orphan (has inputs missing),
|
||||||
// potentially add it to the orphan pool.
|
// potentially add it to the orphan pool.
|
||||||
err := mp.maybeAddOrphan(tx, &txHash)
|
err := mp.maybeAddOrphan(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -856,9 +849,9 @@ func (mp *txMemPool) TxShas() []*btcwire.ShaHash {
|
|||||||
func newTxMemPool(server *server) *txMemPool {
|
func newTxMemPool(server *server) *txMemPool {
|
||||||
return &txMemPool{
|
return &txMemPool{
|
||||||
server: server,
|
server: server,
|
||||||
pool: make(map[btcwire.ShaHash]*btcwire.MsgTx),
|
pool: make(map[btcwire.ShaHash]*btcutil.Tx),
|
||||||
orphans: make(map[btcwire.ShaHash]*btcwire.MsgTx),
|
orphans: make(map[btcwire.ShaHash]*btcutil.Tx),
|
||||||
orphansByPrev: make(map[btcwire.ShaHash]*list.List),
|
orphansByPrev: make(map[btcwire.ShaHash]*list.List),
|
||||||
outpoints: make(map[btcwire.OutPoint]*btcwire.MsgTx),
|
outpoints: make(map[btcwire.OutPoint]*btcutil.Tx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
peer.go
19
peer.go
@ -325,7 +325,7 @@ func (p *peer) pushTxMsg(sha *btcwire.ShaHash, doneChan chan bool) error {
|
|||||||
"pool: %v", sha, err)
|
"pool: %v", sha, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.QueueMessage(tx, doneChan)
|
p.QueueMessage(tx.MsgTx(), doneChan)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -453,12 +453,10 @@ func (p *peer) handleMemPoolMsg(msg *btcwire.MsgMemPool) {
|
|||||||
// transactions don't rely on the previous one in a linear fashion like blocks.
|
// transactions don't rely on the previous one in a linear fashion like blocks.
|
||||||
func (p *peer) handleTxMsg(msg *btcwire.MsgTx) {
|
func (p *peer) handleTxMsg(msg *btcwire.MsgTx) {
|
||||||
// Add the transaction to the known inventory for the peer.
|
// Add the transaction to the known inventory for the peer.
|
||||||
hash, err := msg.TxSha()
|
// Convert the raw MsgTx to a btcutil.Tx which provides some convenience
|
||||||
if err != nil {
|
// methods and things such as hash caching.
|
||||||
log.Errorf("Unable to get transaction hash: %v", err)
|
tx := btcutil.NewTx(msg)
|
||||||
return
|
iv := btcwire.NewInvVect(btcwire.InvTypeTx, tx.Sha())
|
||||||
}
|
|
||||||
iv := btcwire.NewInvVect(btcwire.InvTypeTx, &hash)
|
|
||||||
p.addKnownInventory(iv)
|
p.addKnownInventory(iv)
|
||||||
|
|
||||||
// Queue the transaction up to be handled by the block manager and
|
// Queue the transaction up to be handled by the block manager and
|
||||||
@ -466,16 +464,15 @@ func (p *peer) handleTxMsg(msg *btcwire.MsgTx) {
|
|||||||
// processed and known good or bad. This helps prevent a malicious peer
|
// processed and known good or bad. This helps prevent a malicious peer
|
||||||
// from queueing up a bunch of bad transactions before disconnecting (or
|
// from queueing up a bunch of bad transactions before disconnecting (or
|
||||||
// being disconnected) and wasting memory.
|
// being disconnected) and wasting memory.
|
||||||
p.server.blockManager.QueueTx(msg, p)
|
p.server.blockManager.QueueTx(tx, p)
|
||||||
<-p.txProcessed
|
<-p.txProcessed
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleBlockMsg is invoked when a peer receives a block bitcoin message. It
|
// handleBlockMsg is invoked when a peer receives a block bitcoin message. It
|
||||||
// blocks until the bitcoin block has been fully processed.
|
// blocks until the bitcoin block has been fully processed.
|
||||||
func (p *peer) handleBlockMsg(msg *btcwire.MsgBlock, buf []byte) {
|
func (p *peer) handleBlockMsg(msg *btcwire.MsgBlock, buf []byte) {
|
||||||
// Convert the raw MsgBlock to a btcutil.Block which
|
// Convert the raw MsgBlock to a btcutil.Block which provides some
|
||||||
// provides some convience methods and things such as
|
// convenience methods and things such as hash caching.
|
||||||
// hash caching.
|
|
||||||
block := btcutil.NewBlockFromBlockAndBytes(msg, buf)
|
block := btcutil.NewBlockFromBlockAndBytes(msg, buf)
|
||||||
|
|
||||||
// Add the block to the known inventory for the peer.
|
// Add the block to the known inventory for the peer.
|
||||||
|
@ -725,7 +725,8 @@ func jsonRead(body []byte, s *rpcServer, walletNotification chan []byte) (reply
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = s.server.txMemPool.ProcessTransaction(msgtx)
|
tx := btcutil.NewTx(msgtx)
|
||||||
|
err = s.server.txMemPool.ProcessTransaction(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("RPCS: Failed to process transaction: %v", err)
|
log.Errorf("RPCS: Failed to process transaction: %v", err)
|
||||||
err = btcjson.Error{
|
err = btcjson.Error{
|
||||||
@ -736,15 +737,13 @@ func jsonRead(body []byte, s *rpcServer, walletNotification chan []byte) (reply
|
|||||||
}
|
}
|
||||||
|
|
||||||
var result interface{}
|
var result interface{}
|
||||||
txsha, err := msgtx.TxSha()
|
txsha := tx.Sha()
|
||||||
if err == nil {
|
|
||||||
result = txsha.String()
|
result = txsha.String()
|
||||||
}
|
|
||||||
|
|
||||||
// If called from websocket code, add a mined tx hashes
|
// If called from websocket code, add a mined tx hashes
|
||||||
// request.
|
// request.
|
||||||
if walletNotification != nil {
|
if walletNotification != nil {
|
||||||
s.ws.requests.AddMinedTxRequest(walletNotification, &txsha)
|
s.ws.requests.AddMinedTxRequest(walletNotification, txsha)
|
||||||
}
|
}
|
||||||
|
|
||||||
reply = btcjson.Reply{
|
reply = btcjson.Reply{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user