[rpc] walletcreatefundedpsbt: use wallet default RBF

This commit is contained in:
Sjors Provoost 2019-08-14 13:32:10 +02:00
parent bbc2970082
commit ee950ec465
No known key found for this signature in database
GPG key ID: 57FF9BDBCC301009
4 changed files with 33 additions and 16 deletions

View file

@ -352,7 +352,7 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
return res; return res;
} }
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf) CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
{ {
if (inputs_in.isNull() || outputs_in.isNull()) if (inputs_in.isNull() || outputs_in.isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
@ -370,8 +370,6 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
rawTx.nLockTime = nLockTime; rawTx.nLockTime = nLockTime;
} }
bool rbfOptIn = rbf.isTrue();
for (unsigned int idx = 0; idx < inputs.size(); idx++) { for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx]; const UniValue& input = inputs[idx];
const UniValue& o = input.get_obj(); const UniValue& o = input.get_obj();
@ -386,7 +384,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
uint32_t nSequence; uint32_t nSequence;
if (rbfOptIn) { if (rbf) {
nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */ nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
} else if (rawTx.nLockTime) { } else if (rawTx.nLockTime) {
nSequence = CTxIn::SEQUENCE_FINAL - 1; nSequence = CTxIn::SEQUENCE_FINAL - 1;
@ -458,7 +456,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
} }
} }
if (!rbf.isNull() && rawTx.vin.size() > 0 && rbfOptIn != SignalsOptInRBF(CTransaction(rawTx))) { if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
} }
@ -528,7 +526,11 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
}, true }, true
); );
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]); bool rbf = false;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
return EncodeHexTx(CTransaction(rawTx)); return EncodeHexTx(CTransaction(rawTx));
} }
@ -1632,7 +1634,11 @@ UniValue createpsbt(const JSONRPCRequest& request)
}, true }, true
); );
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]); bool rbf = false;
if (!request.params[3].isNull()) {
rbf = request.params[3].isTrue();
}
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
// Make a blank psbt // Make a blank psbt
PartiallySignedTransaction psbtx; PartiallySignedTransaction psbtx;

View file

@ -17,6 +17,6 @@ class Chain;
UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType); UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, const UniValue& prevTxs, CBasicKeyStore *keystore, bool tempKeystore, const UniValue& hashType);
/** Create a transaction from univalue parameters */ /** Create a transaction from univalue parameters */
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf); CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf);
#endif // BITCOIN_RPC_RAWTRANSACTION_H #endif // BITCOIN_RPC_RAWTRANSACTION_H

View file

@ -4114,7 +4114,13 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
CAmount fee; CAmount fee;
int change_position; int change_position;
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]["replaceable"]); bool rbf = pwallet->m_signal_rbf;
const UniValue &replaceable_arg = request.params[3]["replaceable"];
if (!replaceable_arg.isNull()) {
RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
rbf = replaceable_arg.isTrue();
}
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]); FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]);
// Make a blank psbt // Make a blank psbt

View file

@ -20,6 +20,11 @@ class PSBTTest(BitcoinTestFramework):
def set_test_params(self): def set_test_params(self):
self.setup_clean_chain = False self.setup_clean_chain = False
self.num_nodes = 3 self.num_nodes = 3
self.extra_args = [
["-walletrbf=1"],
[],
[]
]
def skip_test_if_missing_module(self): def skip_test_if_missing_module(self):
self.skip_if_no_wallet() self.skip_if_no_wallet()
@ -191,18 +196,18 @@ class PSBTTest(BitcoinTestFramework):
# replaceable arg # replaceable arg
block_height = self.nodes[0].getblockcount() block_height = self.nodes[0].getblockcount()
unspent = self.nodes[0].listunspent()[0] unspent = self.nodes[0].listunspent()[0]
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True}, False) psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":False}, False)
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"]) decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]): for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE) assert(tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE)
assert "bip32_derivs" not in psbt_in assert "bip32_derivs" not in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height+2) assert_equal(decoded_psbt["tx"]["locktime"], block_height+2)
# Same construction with only locktime set # Same construction with only locktime set and RBF explicitly enabled
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height, {}, True) psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height, {"replaceable": True}, True)
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"]) decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]): for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
assert "bip32_derivs" in psbt_in assert "bip32_derivs" in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height) assert_equal(decoded_psbt["tx"]["locktime"], block_height)
@ -210,7 +215,7 @@ class PSBTTest(BitcoinTestFramework):
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}]) psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}])
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"]) decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
for tx_in in decoded_psbt["tx"]["vin"]: for tx_in in decoded_psbt["tx"]["vin"]:
assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
assert_equal(decoded_psbt["tx"]["locktime"], 0) assert_equal(decoded_psbt["tx"]["locktime"], 0)
# Make sure change address wallet does not have P2SH innerscript access to results in success # Make sure change address wallet does not have P2SH innerscript access to results in success