Skip to content

Commit 6feb0f5

Browse files
committed
rpc/wallet: add analyzerawtransaction RPC
1 parent eda3fbe commit 6feb0f5

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

src/wallet/rpcwallet.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6190,6 +6190,77 @@ void FillBlinds(CWallet* pwallet, CMutableTransaction& tx, std::vector<uint256>&
61906190
}
61916191
}
61926192

6193+
RPCHelpMan analyzerawtransaction()
6194+
{
6195+
return RPCHelpMan{"analyzerawtransaction",
6196+
"\nGenerate a mapping showing losses and gains resulting in the signing and broadcasting of the given transaction.\n" +
6197+
HELP_REQUIRING_PASSPHRASE,
6198+
{
6199+
{"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
6200+
},
6201+
RPCResult{
6202+
RPCResult::Type::OBJ_DYN, "", "",
6203+
{
6204+
{RPCResult::Type::NUM, "asset", "The wallet change for the given asset (negative means decrease)."},
6205+
}
6206+
},
6207+
RPCExamples{
6208+
HelpExampleCli("analyzerawtransaction", "\"myhex\"")
6209+
+ HelpExampleRpc("analyzerawtransaction", "\"myhex\"")
6210+
},
6211+
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
6212+
{
6213+
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
6214+
if (!wallet) return NullUniValue;
6215+
CWallet* const pwallet = wallet.get();
6216+
6217+
RPCTypeCheck(request.params, {UniValue::VSTR}, true);
6218+
6219+
LOCK(pwallet->cs_wallet);
6220+
EnsureWalletIsUnlocked(pwallet);
6221+
6222+
// Decode and unblind the transaction
6223+
CMutableTransaction mtx;
6224+
if (!DecodeHexTx(mtx, request.params[0].get_str())) {
6225+
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
6226+
}
6227+
6228+
std::vector<uint256> output_value_blinds;
6229+
std::vector<uint256> output_asset_blinds;
6230+
std::vector<CPubKey> output_pubkeys;
6231+
std::vector<CKey> asset_keys;
6232+
std::vector<CKey> token_keys;
6233+
FillBlinds(pwallet, mtx, output_value_blinds, output_asset_blinds, output_pubkeys, asset_keys, token_keys);
6234+
CTransaction tx(mtx);
6235+
6236+
// Calculate changes (+credit, -debit)
6237+
CAmountMap changes;
6238+
6239+
// Fetch debit; we are *spending* these; if the transaction is signed and broadcast, we will lose everything in these
6240+
for (size_t i = 0; i < tx.vin.size(); ++i) {
6241+
CAmountMap debit = pwallet->GetDebit(tx.vin.at(i), ISMINE_SPENDABLE);
6242+
for (const auto& entry : debit) {
6243+
changes[entry.first] -= entry.second;
6244+
}
6245+
}
6246+
6247+
// Fetch credit; we are *receiving* these; if the transaciton is signed and broadcast, we will receive everything in these
6248+
for (size_t i = 0; i < tx.vout.size(); ++i) {
6249+
const CTxOut& txout = tx.vout.at(i);
6250+
if (!pwallet->IsMine(txout)) continue;
6251+
if (!txout.nAsset.IsExplicit() || !txout.nValue.IsExplicit()) {
6252+
throw JSONRPCError(RPC_WALLET_ERROR, "Output belongs to me but I can't unblind it");
6253+
}
6254+
const auto& asset = txout.nAsset.GetAsset();
6255+
const auto& value = txout.nValue.GetAmount();
6256+
changes[asset] += value;
6257+
}
6258+
6259+
return AmountMapToUniv(changes, "");
6260+
}
6261+
};
6262+
}
6263+
61936264
static RPCHelpMan blindrawtransaction()
61946265
{
61956266
return RPCHelpMan{"blindrawtransaction",
@@ -7069,6 +7140,7 @@ static const CRPCCommand commands[] =
70697140
{ "wallet", "getpeginaddress", &getpeginaddress, {} },
70707141
{ "wallet", "claimpegin", &claimpegin, {"bitcoin_tx", "txoutproof", "claim_script"} },
70717142
{ "wallet", "createrawpegin", &createrawpegin, {"bitcoin_tx", "txoutproof", "claim_script"} },
7143+
{ "wallet", "analyzerawtransaction", &analyzerawtransaction, {"hexstring"} },
70727144
{ "wallet", "blindrawtransaction", &blindrawtransaction, {"hexstring", "ignoreblindfail", "asset_commitments", "blind_issuances", "totalblinder"} },
70737145
{ "wallet", "unblindrawtransaction", &unblindrawtransaction, {"hex"} },
70747146
{ "wallet", "sendtomainchain", &sendtomainchain, {"address", "amount", "subtractfeefromamount", "verbose"} },

0 commit comments

Comments
 (0)