// maybeAddOrphan potentially adds an orphan to the orphan pool. func (mp *txMemPool) maybeAddOrphan(tx *btcwire.MsgTx, txHash *btcwire.ShaHash) error { // Ignore orphan transactions that are too large. This helps avoid // a memory exhaustion attack based on sending a lot of really large // orphans. In the case there is a valid transaction larger than this, // it will ultimtely be rebroadcast after the parent transactions // have been mined or otherwise received. // // Note that the number of orphan transactions in the orphan pool is // also limited, so this equates to a maximum memory used of // maxOrphanTxSize * maxOrphanTransactions (which is 500MB as of the // time this comment was written). var serializedTxBuf bytes.Buffer err := tx.Serialize(&serializedTxBuf) if err != nil { return err } serializedLen := serializedTxBuf.Len() if serializedLen > maxOrphanTxSize { str := fmt.Sprintf("orphan transaction size of %d bytes is "+ "larger than max allowed size of %d bytes", serializedLen, maxOrphanTxSize) return TxRuleError(str) } // Add the orphan if the none of the above disqualified it. mp.addOrphan(tx, txHash) return nil }
// SignRawTransaction2Async returns an instance of a type that can be used to // get the result of the RPC at some future time by invoking the Receive // function on the returned instance. // // See SignRawTransaction2 for the blocking version and more details. func (c *Client) SignRawTransaction2Async(tx *btcwire.MsgTx, inputs []btcjson.RawTxInput) FutureSignRawTransactionResult { txHex := "" if tx != nil { // Serialize the transaction and convert to hex string. buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) if err := tx.Serialize(buf); err != nil { return newFutureError(err) } txHex = hex.EncodeToString(buf.Bytes()) } id := c.NextID() cmd, err := btcjson.NewSignRawTransactionCmd(id, txHex, inputs) if err != nil { return newFutureError(err) } return c.sendCmd(cmd) }
// checkTransactionStandard performs a series of checks on a transaction to // ensure it is a "standard" transaction. A standard transaction is one that // conforms to several additional limiting cases over what is considered a // "sane" transaction such as having a version in the supported range, being // finalized, conforming to more stringent size constraints, having scripts // of recognized forms, and not containing "dust" outputs (those that are // so small it costs more to process them than they are worth). func checkTransactionStandard(tx *btcwire.MsgTx, height int64) error { // The transaction must be a currently supported version. if tx.Version > btcwire.TxVersion || tx.Version < 1 { str := fmt.Sprintf("transaction version %d is not in the "+ "valid range of %d-%d", tx.Version, 1, btcwire.TxVersion) return TxRuleError(str) } // The transaction must be finalized to be standard and therefore // considered for inclusion in a block. if !btcchain.IsFinalizedTransaction(tx, height, time.Now()) { str := fmt.Sprintf("transaction is not finalized") return TxRuleError(str) } // Since extremely large transactions with a lot of inputs can cost // almost as much to process as the sender fees, limit the maximum // size of a transaction. This also helps mitigate CPU exhaustion // attacks. var serializedTxBuf bytes.Buffer err := tx.Serialize(&serializedTxBuf) if err != nil { return err } serializedLen := serializedTxBuf.Len() if serializedLen > maxStandardTxSize { str := fmt.Sprintf("transaction size of %v is larger than max "+ "allowed size of %v", serializedLen, maxStandardTxSize) return TxRuleError(str) } for i, txIn := range tx.TxIn { // Each transaction input signature script must not exceed the // maximum size allowed for a standard transaction. See // the comment on maxStandardSigScriptSize for more details. sigScriptLen := len(txIn.SignatureScript) if sigScriptLen > maxStandardSigScriptSize { str := fmt.Sprintf("transaction input %d: signature "+ "script size of %d bytes is large than max "+ "allowed size of %d bytes", i, sigScriptLen, maxStandardSigScriptSize) return TxRuleError(str) } // Each transaction input signature script must only contain // opcodes which push data onto the stack. if !btcscript.IsPushOnlyScript(txIn.SignatureScript) { str := fmt.Sprintf("transaction input %d: signature "+ "script is not push only", i) return TxRuleError(str) } } // None of the output public key scripts can be a non-standard script or // be "dust". for i, txOut := range tx.TxOut { err := checkPkScriptStandard(txOut.PkScript) if err != nil { str := fmt.Sprintf("transaction output %d: %v", i, err) return TxRuleError(str) } if isDust(txOut) { str := fmt.Sprintf("transaction output %d: payment "+ "of %d is dust", i, txOut.Value) return TxRuleError(str) } } return nil }
// toHex converts a msgTx into a hex string. func ToHex(tx *btcwire.MsgTx) string { buf := bytes.NewBuffer(make([]byte, 0, tx.SerializeSize())) tx.Serialize(buf) txHex := hex.EncodeToString(buf.Bytes()) return txHex }