From cefe40767d8453eafe45c422b221360ce631d265 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Mon, 14 Oct 2019 14:47:57 -0400 Subject: [PATCH] Allow specifying peg-in info in raw transaction RPC inputs --- src/rpc/rawtransaction.cpp | 45 +++++++++++++++++++++++++++++++++++--- src/rpc/rawtransaction.h | 2 +- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 98e642d981..ba3c4ca650 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -483,7 +484,7 @@ void CreatePegInInput(CMutableTransaction& mtx, uint32_t input_idx, Sidechain::B CreatePegInInputInner(mtx, input_idx, tx_btc, merkle_block, claim_scripts, txData, txOutProofData); } -CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector* output_pubkeys_out) +CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector* output_pubkeys_out, bool allow_peg_in) { if (inputs_in.isNull() || outputs_in.isNull()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null"); @@ -542,8 +543,43 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal } CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence); - rawTx.vin.push_back(in); + + // Get the pegin stuff if it's there + const UniValue& pegin_tx = find_value(o, "pegin_bitcoin_tx"); + const UniValue& pegin_tx_proof = find_value(o, "pegin_txout_proof"); + const UniValue& pegin_script = find_value(o, "pegin_claim_script"); + if (!pegin_tx.isNull() && !pegin_tx_proof.isNull() && !pegin_script.isNull() && allow_peg_in) { + if (!IsHex(pegin_script.get_str())) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Given claim_script is not hex."); + } + // If given manually, no need for it to be a witness script + std::vector claim_script_bytes(ParseHex(pegin_script.get_str())); + CScript claim_script(claim_script_bytes.begin(), claim_script_bytes.end()); + std::set claim_scripts; + claim_scripts.insert(std::move(claim_script)); + if (Params().GetConsensus().ParentChainHasPow()) { + Sidechain::Bitcoin::CTransactionRef tx_btc; + Sidechain::Bitcoin::CMerkleBlock merkle_block; + CreatePegInInput(rawTx, idx, tx_btc, merkle_block, claim_scripts, ParseHex(pegin_tx.get_str()), ParseHex(pegin_tx_proof.get_str())); + if (!CheckParentProofOfWork(merkle_block.header.GetHash(), merkle_block.header.nBits, Params().GetConsensus())) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof"); + } + } else { + CTransactionRef tx_btc; + CMerkleBlock merkle_block; + CreatePegInInput(rawTx, idx, tx_btc, merkle_block, claim_scripts, ParseHex(pegin_tx.get_str()), ParseHex(pegin_tx_proof.get_str())); + if (!CheckProofSignedParent(merkle_block.header, Params().GetConsensus())) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid tx out proof"); + } + } + } else if (!pegin_tx.isNull() || !pegin_tx_proof.isNull() || !pegin_script.isNull()) { + if (allow_peg_in) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Some but not all pegin_ arguments provided"); + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "pegin_ arguments provided but this command does not support peg-ins"); + } + } } if (!outputs_is_obj) { @@ -678,6 +714,9 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, {"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"}, + {"pegin_bitcoin_tx", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The raw bitcoin transaction (in hex) depositing bitcoin to the mainchain_address generated by getpeginaddress"}, + {"pegin_txout_proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A rawtxoutproof (in hex) generated by the mainchain daemon's `gettxoutproof` containing a proof of only bitcoin_tx"}, + {"pegin_claim_script", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The claim script generated by getpeginaddress."}, }, }, }, @@ -2072,7 +2111,7 @@ UniValue createpsbt(const JSONRPCRequest& request) ); std::vector output_pubkeys; - CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3], request.params[4], &output_pubkeys); + CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3], request.params[4], &output_pubkeys, false /* allow_peg_in */); // Make a blank psbt PartiallySignedTransaction psbtx(rawTx); diff --git a/src/rpc/rawtransaction.h b/src/rpc/rawtransaction.h index 42b5e8ba9b..42784aeb46 100644 --- a/src/rpc/rawtransaction.h +++ b/src/rpc/rawtransaction.h @@ -19,7 +19,7 @@ UniValue SignTransaction(interfaces::Chain& chain, CMutableTransaction& mtx, con /** Create a transaction from univalue parameters. If (and only if) output_pubkeys_out is null, the "nonce hack" of storing Confidential Assets output pubkeys in nonces will be used. */ -CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector* output_pubkeys_out = nullptr); +CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& rbf, const UniValue& assets_in, std::vector* output_pubkeys_out = nullptr, bool allow_peg_in = true); /** Create a peg-in input */ void CreatePegInInput(CMutableTransaction& mtx, uint32_t input_idx, CTransactionRef& tx_btc, CMerkleBlock& merkle_block, const std::set& claim_scripts, const std::vector& txData, const std::vector& txOutProofData); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1abee184c8..5d1398027d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4672,7 +4672,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) // It's hard to control the behavior of FundTransaction, so we will wait // until after it's done, then extract the blinding keys from the output // nonces. - CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]["replaceable"], NullUniValue /* CA: assets_in */); + CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]["replaceable"], NullUniValue /* CA: assets_in */, nullptr /* output_pubkeys_out */, false /* allow_peg_in */); FundTransaction(pwallet, rawTx, fee, change_position, request.params[3]); // Make a blank psbt