Add walletblindpsbt rpc

This commit is contained in:
Andrew Chow 2020-10-08 16:04:14 -04:00
parent e7dd046b03
commit 3f6c8bfda1
3 changed files with 99 additions and 5 deletions

View file

@ -6,6 +6,7 @@
#include <amount.h>
#include <asset.h>
#include <assetsdir.h>
#include <blindpsbt.h>
#include <block_proof.h>
#include <consensus/validation.h>
#include <core_io.h>
@ -4865,6 +4866,55 @@ static RPCHelpMan walletprocesspsbt()
};
}
static RPCHelpMan walletblindpsbt()
{
return RPCHelpMan{"walletblindpsbt",
"\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
"that we can sign for.\n\n" +
HELP_REQUIRING_PASSPHRASE,
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "psbt", "The resulting raw transaction (base64-encoded string)"},
}
},
RPCExamples{
HelpExampleCli("walletblindpsbt", "\"psbt\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
if (!g_con_elementsmode)
throw std::runtime_error("PSBT operations are disabled when not in elementsmode.\n");
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
// Unserialize the transaction
PartiallySignedTransaction psbtx;
std::string error;
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
if (pwallet->WalletBlindPSBT(psbtx) != BlindingStatus::OK) {
throw JSONRPCError(RPC_WALLET_ERROR, "Something went wrong");
}
UniValue result(UniValue::VOBJ);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
result.pushKV("psbt", EncodeBase64(ssTx.str()));
return result;
},
};
}
static RPCHelpMan walletcreatefundedpsbt()
{
return RPCHelpMan{"walletcreatefundedpsbt",
@ -7106,6 +7156,7 @@ static const CRPCCommand commands[] =
{ "wallet", "issueasset", &issueasset, {"assetamount", "tokenamount", "blind"}},
{ "wallet", "reissueasset", &reissueasset, {"asset", "assetamount"}},
{ "wallet", "destroyamount", &destroyamount, {"asset", "amount", "comment", "verbose"} },
{ "wallet", "walletblindpsbt", &walletblindpsbt, {"psbt"} },
{ "hidden", "generatepegoutproof", &generatepegoutproof, {"sumkey", "btcpubkey", "onlinepubkey"} },
{ "hidden", "getpegoutkeys", &getpegoutkeys, {"btcprivkey", "offlinepubkey"} },
};

View file

@ -1258,16 +1258,21 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
chain().waitForNotificationsIfTipChanged(last_block_hash);
}
isminetype CWallet::IsMine(const CTxIn &txin) const
isminetype CWallet::IsMine(const CTxIn& txin) const
{
AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
return IsMine(txin.prevout);
}
isminetype CWallet::IsMine(const COutPoint &outpoint) const
{
AssertLockHeld(cs_wallet);
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(outpoint.hash);
if (mi != mapWallet.end())
{
const CWalletTx& prev = (*mi).second;
if (txin.prevout.n < prev.tx->vout.size())
return IsMine(prev.tx->vout[txin.prevout.n]);
if (outpoint.n < prev.tx->vout.size())
return IsMine(prev.tx->vout[outpoint.n]);
}
return ISMINE_NO;
}
@ -2792,6 +2797,41 @@ TransactionError CWallet::FillPSBTData(PartiallySignedTransaction& psbtx, bool b
return TransactionError::OK;
}
BlindingStatus CWallet::WalletBlindPSBT(PartiallySignedTransaction& psbtx) const
{
// Gather our input data
LOCK(cs_wallet);
std::map<uint32_t, std::tuple<CAmount, CAsset, uint256, uint256>> our_input_data;
std::map<uint32_t, std::pair<CKey, CKey>> our_issuances_to_blind;
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
PSBTInput& input = psbtx.inputs[i];
if (input.m_peg_in_value && !input.m_peg_in_claim_script.empty()) {
if (!IsMine(CTxOut(Params().GetConsensus().pegged_asset, *input.m_peg_in_value, input.m_peg_in_claim_script))) continue;
our_input_data[i] = std::make_tuple(*input.m_peg_in_value, Params().GetConsensus().pegged_asset, uint256(), uint256());
} else {
if (!IsMine(COutPoint(input.prev_txid, *input.prev_out))) continue;
const CWalletTx* wtx = GetWalletTx(input.prev_txid);
if (!wtx) continue;
CPubKey blinding_pubkey;
CAmount amount;
uint256 value_blinder;
CAsset asset;
uint256 asset_blinder;
wtx->GetNonIssuanceBlindingData(*input.prev_out, &blinding_pubkey, &amount, &value_blinder, &asset, &asset_blinder);
our_input_data[i] = std::make_tuple(amount, asset, asset_blinder, value_blinder);
}
// Blind issuances on our inputs
if (input.m_issuance_value || input.m_issuance_inflation_keys_amount) {
CScript blinding_script(CScript() << OP_RETURN << std::vector<unsigned char>(input.prev_txid.begin(), input.prev_txid.end()) << *input.prev_out);
our_issuances_to_blind[i] = std::make_pair(GetBlindingKey(&blinding_script), GetBlindingKey(&blinding_script));
}
}
// Blind the PSBT
return BlindPSBT(psbtx, our_input_data, our_issuances_to_blind);
}
TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool imbalance_ok, bool bip32derivs, size_t* n_signed) const
{
/*

View file

@ -8,6 +8,7 @@
#include <amount.h>
#include <asset.h>
#include <blindpsbt.h>
#include <interfaces/chain.h>
#include <interfaces/handler.h>
#include <outputtype.h>
@ -1090,6 +1091,7 @@ public:
// ELEMENTS
TransactionError FillPSBTData(PartiallySignedTransaction& psbtx, bool bip32derivs = false) const;
TransactionError SignPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type = 1, bool sign = true, bool imbalance_ok = false, bool bip32derivs = false, size_t* n_signed = nullptr) const;
BlindingStatus WalletBlindPSBT(PartiallySignedTransaction& psbtx) const;
// end ELEMENTS
/**
@ -1172,6 +1174,7 @@ public:
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const COutPoint& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/**
* Returns amount of debit if the input matches the
* filter, otherwise returns 0