Skip to content

Commit

Permalink
btcd: add new RPC method testmempoolaccept
Browse files Browse the repository at this point in the history
  • Loading branch information
yyforyongyu committed Nov 5, 2023
1 parent bc5dce2 commit b4aca59
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 0 deletions.
78 changes: 78 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"verifychain": handleVerifyChain,
"verifymessage": handleVerifyMessage,
"version": handleVersion,
"testmempoolaccept": handleTestMempoolAccept,
}

// list of commands that we recognize, but for which btcd has no support because
Expand Down Expand Up @@ -3783,6 +3784,83 @@ func handleVersion(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (in
return result, nil
}

// handleTestMempoolAccept implements the testmempoolaccept command.
func handleTestMempoolAccept(s *rpcServer, cmd interface{},
closeChan <-chan struct{}) (interface{}, error) {

c := cmd.(*btcjson.TestMempoolAcceptCmd)

// Create txns to hold the decoded tx.
txns := make([]*btcutil.Tx, 0, len(c.RawTxns))

// Iterate the raw hex slice and decode them.
for _, rawTx := range c.RawTxns {
rawBytes, err := hex.DecodeString(rawTx)
if err != nil {
return nil, rpcDecodeHexError(rawTx)
}

tx, err := btcutil.NewTxFromBytes(rawBytes)
if err != nil {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCDeserialization,
Message: "TX decode failed: " + err.Error(),
}
}

txns = append(txns, tx)
}

results := make([]*btcjson.TestMempoolAcceptResult, 0, len(txns))
for _, tx := range txns {
// Create a test result item.
item := &btcjson.TestMempoolAcceptResult{
Txid: tx.Hash().String(),
Wtxid: tx.WitnessHash().String(),
}

// Check the mempool acceptance.
result, err := s.cfg.TxMemPool.CheckMempoolAcceptance(tx)

// If an error is returned, this tx is not allow, hence we
// record the reason.
if err != nil {
item.Allowed = false

// TODO(yy): differentiate the errors and put package
// error in `PackageError` field.
item.RejectReason = err.Error()

// Move to the next transaction.
continue
}

// If this transaction is an orphan, it's not allowed.
if result.MissingParents != nil {
item.Allowed = false

// NOTE: "missing-inputs" is what bitcoind returns
// here, so we mimic the same error message.
item.RejectReason = "missing-inputs"

// Move to the next transaction.
continue
}

// Otherwise this tx is allowed, we now patch the fields in
// `TestMempoolAcceptItem` as much as possible.
item.Allowed = true
item.Vsize = int32(result.TxSize)
item.Fees = &btcjson.TestMempoolAcceptFees{
Base: result.TxFee.ToBTC(),
}

results = append(results, item)
}

return results, nil
}

// rpcServer provides a concurrent safe RPC server to a chain server.
type rpcServer struct {
started int32
Expand Down
18 changes: 18 additions & 0 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,23 @@ var helpDescsEnUS = map[string]string{
"versionresult-patch": "The patch component of the JSON-RPC API version",
"versionresult-prerelease": "Prerelease info about the current build",
"versionresult-buildmetadata": "Metadata about the current build",

// TestMempoolAcceptCmd help.
"testmempoolaccept--synopsis": "Returns result of mempool acceptance tests indicating if raw transaction(s) would be accepted by mempool.",
"testmempoolaccept-rawtxns": "Serialized transactions to test.",
"testmempoolaccept-maxfeerate": "Maximum acceptable fee rate in BTC/kB",

// TestMempoolAcceptCmd result help.
"testmempoolacceptresult-txid": "The transaction hash in hex.",
"testmempoolacceptresult-wtxid": "The transaction witness hash in hex.",
"testmempoolacceptresult-package-error": "Package validation error, if any (only possible if rawtxs had more than 1 transaction).",
"testmempoolacceptresult-allowed": "Whether the transaction would be accepted to the mempool.",
"testmempoolacceptresult-vsize": "Virtual transaction size as defined in BIP 141.(only present when 'allowed' is true)",
"testmempoolacceptresult-reject-reason": "Rejection string (only present when 'allowed' is false).",
"testmempoolacceptresult-fees": "Transaction fees (only present if 'allowed' is true).",
"testmempoolacceptfees-base": "Transaction fees (only present if 'allowed' is true).",
"testmempoolacceptfees-effective-feerate": "The effective feerate in BTC per KvB.",
"testmempoolacceptfees-effective-includes": "Transactions whose fees and vsizes are included in effective-feerate. Each item is a transaction wtxid in hex.",
}

// rpcResultTypes specifies the result types that each RPC command can return.
Expand Down Expand Up @@ -762,6 +779,7 @@ var rpcResultTypes = map[string][]interface{}{
"verifychain": {(*bool)(nil)},
"verifymessage": {(*bool)(nil)},
"version": {(*map[string]btcjson.VersionResult)(nil)},
"testmempoolaccept": {(*[]btcjson.TestMempoolAcceptResult)(nil)},

// Websocket commands.
"loadtxfilter": nil,
Expand Down

0 comments on commit b4aca59

Please sign in to comment.