diff --git a/src/rest.cpp b/src/rest.cpp index 6ba15172fa082..c0b200b1a5f13 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -555,7 +555,9 @@ static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart) for (const CCoin& coin : outs) { UniValue utxo(UniValue::VOBJ); utxo.pushKV("height", (int32_t)coin.nHeight); - utxo.pushKV("value", ValueFromAmount(coin.out.nValue)); + if (coin.out.nValue.IsExplicit()) { + utxo.pushKV("value", ValueFromAmount(coin.out.nValue.GetAmount())); + } // include the script in a json output UniValue o(UniValue::VOBJ); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 04b34973e2ceb..3e5a8c9747708 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -889,9 +889,13 @@ static void ApplyStats(CCoinsStats &stats, CHashWriter& ss, const uint256& hash, for (const auto& output : outputs) { ss << VARINT(output.first + 1); ss << output.second.out.scriptPubKey; - ss << VARINT(output.second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED); + ss << output.second.out.nValue; + ss << output.second.out.nAsset; + ss << output.second.out.nNonce; stats.nTransactionOutputs++; - stats.nTotalAmount += output.second.out.nValue; + if (output.second.out.nValue.IsExplicit()) { + stats.nTotalAmount += output.second.out.nValue.GetAmount(); + } stats.nBogoSize += 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ + 8 /* amount */ + 2 /* scriptPubKey len */ + output.second.out.scriptPubKey.size() /* scriptPubKey */; } @@ -1098,7 +1102,20 @@ UniValue gettxout(const JSONRPCRequest& request) } else { ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1)); } - ret.pushKV("value", ValueFromAmount(coin.out.nValue)); + if (coin.out.nValue.IsExplicit()) { + ret.pushKV("value", ValueFromAmount(coin.out.nValue.GetAmount())); + } else { + ret.pushKV("valuecommitment", coin.out.nValue.GetHex()); + } + if (g_con_elementsmode) { + if (coin.out.nAsset.IsExplicit()) { + ret.pushKV("asset", coin.out.nAsset.GetAsset().GetHex()); + } else { + ret.pushKV("assetcommitment", coin.out.nAsset.GetHex()); + } + + ret.pushKV("commitmentnonce", coin.out.nNonce.GetHex()); + } UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(coin.out.scriptPubKey, o, true); ret.pushKV("scriptPubKey", o); @@ -1819,6 +1836,9 @@ static UniValue getblockstats(const JSONRPCRequest& request) } } + // ELEMENTS: + const CAsset asset = policyAsset; // TODO Make configurable + const CBlock block = GetBlockChecked(pindex); const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default) @@ -1857,10 +1877,25 @@ static UniValue getblockstats(const JSONRPCRequest& request) outputs += tx->vout.size(); CAmount tx_total_out = 0; - if (loop_outputs) { - for (const CTxOut& out : tx->vout) { - tx_total_out += out.nValue; - utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + // ELEMENTS: + CAmount elements_txfee = 0; + if (g_con_elementsmode) { + if (loop_outputs) { + for (const CTxOut& out : tx->vout) { + if (out.IsFee() && out.nAsset.GetAsset() == asset) { + elements_txfee += out.nValue.GetAmount(); + } + if (out.nValue.IsExplicit() && out.nAsset.IsExplicit() && out.nAsset.GetAsset() == asset) { + tx_total_out += out.nValue.GetAmount(); + } + } + } + } else { + if (loop_outputs) { + for (const CTxOut& out : tx->vout) { + tx_total_out += out.nValue.GetAmount(); + utxo_size_inc += GetSerializeSize(out, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; + } } } @@ -1900,7 +1935,7 @@ static UniValue getblockstats(const JSONRPCRequest& request) if (!g_txindex) { throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more of the selected stats requires -txindex enabled"); } - CAmount tx_total_in = 0; + CAmount tx_total_in = 0; // Only needed for bitcoin serialization for (const CTxIn& in : tx->vin) { if (in.m_is_pegin) { continue; @@ -1913,12 +1948,11 @@ static UniValue getblockstats(const JSONRPCRequest& request) } CTxOut prevoutput = tx_in->vout[in.prevout.n]; - - tx_total_in += prevoutput.nValue; + tx_total_in += g_con_elementsmode ? 0 : prevoutput.nValue.GetAmount(); utxo_size_inc -= GetSerializeSize(prevoutput, PROTOCOL_VERSION) + PER_UTXO_OVERHEAD; } - CAmount txfee = tx_total_in - tx_total_out; + CAmount txfee = g_con_elementsmode ? elements_txfee : (tx_total_in - tx_total_out); assert(MoneyRange(txfee)); if (do_medianfee) { fee_array.push_back(txfee); @@ -2114,10 +2148,11 @@ UniValue scantxoutset(const JSONRPCRequest& request) " \"vout\": n, (numeric) the vout value\n" " \"scriptPubKey\" : \"script\", (string) the script key\n" " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output\n" + " \"asset\" : \"asset\", (hex) The asset ID\n" " \"height\" : n, (numeric) Height of the unspent transaction output\n" " }\n" " ,...], \n" - " \"total_amount\" : x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n" + " \"total_unblinded_bitcoin_amount\" : x.xxx, (numeric) The total amount of all found unspent unblinded outputs in " + CURRENCY_UNIT + "\n" "]\n" ); @@ -2201,24 +2236,57 @@ UniValue scantxoutset(const JSONRPCRequest& request) result.pushKV("success", res); result.pushKV("searched_items", count); - for (const auto& it : coins) { - const COutPoint& outpoint = it.first; - const Coin& coin = it.second; - const CTxOut& txo = coin.out; - input_txos.push_back(txo); - total_in += txo.nValue; - - UniValue unspent(UniValue::VOBJ); - unspent.pushKV("txid", outpoint.hash.GetHex()); - unspent.pushKV("vout", (int32_t)outpoint.n); - unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end())); - unspent.pushKV("amount", ValueFromAmount(txo.nValue)); - unspent.pushKV("height", (int32_t)coin.nHeight); - - unspents.push_back(unspent); + if (!g_con_elementsmode) { + for (const auto& it : coins) { + const COutPoint& outpoint = it.first; + const Coin& coin = it.second; + const CTxOut& txo = coin.out; + input_txos.push_back(txo); + total_in += txo.nValue.GetAmount(); + + UniValue unspent(UniValue::VOBJ); + unspent.pushKV("txid", outpoint.hash.GetHex()); + unspent.pushKV("vout", (int32_t)outpoint.n); + unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end())); + unspent.pushKV("amount", ValueFromAmount(txo.nValue.GetAmount())); + unspent.pushKV("height", (int32_t)coin.nHeight); + + unspents.push_back(unspent); + } + result.pushKV("unspents", unspents); + result.pushKV("total_amount", ValueFromAmount(total_in)); + } else { + CAmount total_in_explicit_parent = 0; + for (const auto& it : coins) { + const COutPoint& outpoint = it.first; + const Coin& coin = it.second; + const CTxOut& txo = coin.out; + input_txos.push_back(txo); + if (txo.nValue.IsExplicit() && txo.nAsset.IsExplicit() && txo.nAsset.GetAsset() == Params().GetConsensus().pegged_asset) { + total_in_explicit_parent += txo.nValue.GetAmount(); + } + + UniValue unspent(UniValue::VOBJ); + unspent.pushKV("txid", outpoint.hash.GetHex()); + unspent.pushKV("vout", (int32_t)outpoint.n); + unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end())); + if (txo.nValue.IsExplicit()) { + unspent.pushKV("amount", ValueFromAmount(txo.nValue.GetAmount())); + } else { + unspent.pushKV("amountcommitment", HexStr(txo.nValue.vchCommitment)); + } + if (txo.nAsset.IsExplicit()) { + unspent.pushKV("asset", txo.nAsset.GetAsset().GetHex()); + } else { + unspent.pushKV("assetcommitment", HexStr(txo.nAsset.vchCommitment)); + } + unspent.pushKV("height", (int32_t)coin.nHeight); + + unspents.push_back(unspent); + } + result.pushKV("unspents", unspents); + result.pushKV("total_unblinded_bitcoin_amount", ValueFromAmount(total_in_explicit_parent)); } - result.pushKV("unspents", unspents); - result.pushKV("total_amount", ValueFromAmount(total_in)); } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command"); } @@ -2258,8 +2326,7 @@ UniValue getsidechaininfo(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.pushKV("fedpegscript", HexStr(consensus.fedpegScript.begin(), consensus.fedpegScript.end())); - //TODO(rebase) CA - //obj.pushKV("pegged_asset", consensus.pegged_asset.GetHex()); + obj.pushKV("pegged_asset", consensus.pegged_asset.GetHex()); obj.pushKV("min_peg_diff", consensus.parentChainPowLimit.GetHex()); obj.pushKV("parent_blockhash", parent_blockhash.GetHex()); obj.pushKV("parent_chain_has_pow", consensus.ParentChainHasPow()); @@ -2267,8 +2334,7 @@ UniValue getsidechaininfo(const JSONRPCRequest& request) if (!consensus.ParentChainHasPow()) { obj.pushKV("parent_chain_signblockscript_asm", ScriptToAsmStr(consensus.parent_chain_signblockscript)); obj.pushKV("parent_chain_signblockscript_hex", HexStr(consensus.parent_chain_signblockscript)); - //TODO(stevenroose) rebase CA - //obj.pushKV("parent_pegged_asset", HexStr(consensus.parent_pegged_asset)); + obj.pushKV("parent_pegged_asset", HexStr(consensus.parent_pegged_asset)); } return obj; } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index c7e35b1abced5..603b79def7c56 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -659,7 +659,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) result.pushKV("previousblockhash", pblock->hashPrevBlock.GetHex()); result.pushKV("transactions", transactions); result.pushKV("coinbaseaux", aux); - result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue); + result.pushKV("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue.GetAmount()); result.pushKV("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)); result.pushKV("target", hashTarget.GetHex()); result.pushKV("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1); diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index c9072bdaa6e06..9d51ab978c8c3 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -54,6 +54,8 @@ static UniValue validateaddress(const JSONRPCRequest& request) " \"iswitness\" : true|false, (boolean) If the address is a witness address\n" " \"witness_version\" : version (numeric, optional) The version number of the witness program\n" " \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n" + " \"confidential_key\" : \"hex\", (string) The hex value of the raw blinding public key for that address, if any. \"\" if none.\n" + " \"unconfidential\" : \"address\", (string) The address without confidentiality key.\n" "}\n" "\nExamples:\n" + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") @@ -77,6 +79,8 @@ static UniValue validateaddress(const JSONRPCRequest& request) UniValue detail = DescribeAddress(dest); ret.pushKVs(detail); + UniValue blind_detail = DescribeBlindAddress(dest); + ret.pushKVs(blind_detail); } return ret; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 214db5e740ee4..573740a5557cf 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index aca94f6b20ff2..d5219bc505c6d 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include // Converts a hex string to a public key if possible CPubKey HexToPubKey(const std::string& hex_in) @@ -271,3 +274,35 @@ UniValue DescribeBlindAddress(const CTxDestination& dest) return ret; } +// Attaches labeled balance reports to UniValue obj with asset filter +// "" displays *all* assets as VOBJ pairs, while named assets must have +// been entered via -assetdir configuration argument and are returned as VNUM. +UniValue AmountMapToUniv(const CAmountMap& balanceOrig, std::string strasset) +{ + // Make sure the policyAsset is always present in the balance map. + CAmountMap balance = balanceOrig; + balance[::policyAsset] += 0; + + // If we don't do assets or a specific asset is given, we filter out once asset. + if (!g_con_elementsmode || strasset != "") { + if (g_con_elementsmode) { + return ValueFromAmount(balance[GetAssetFromString(strasset)]); + } else { + return ValueFromAmount(balance[::policyAsset]); + } + } + + UniValue obj(UniValue::VOBJ); + for(std::map::const_iterator it = balance.begin(); it != balance.end(); ++it) { + // Unknown assets + if (it->first.IsNull()) + continue; + UniValue pair(UniValue::VOBJ); + std::string label = gAssetsDir.GetLabel(it->first); + if (label == "") { + label = it->first.GetHex(); + } + obj.pushKV(label, ValueFromAmount(it->second)); + } + return obj; +} diff --git a/src/rpc/util.h b/src/rpc/util.h index 3b8e849a74f56..b01e94e171f77 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -27,4 +27,6 @@ UniValue DescribeBlindAddress(const CTxDestination& dest); CPubKey GetDestinationBlindingKey(const CTxDestination& dest); bool IsBlindDestination(const CTxDestination& dest); +UniValue AmountMapToUniv(const CAmountMap& balanceOrig, std::string strasset); + #endif // BITCOIN_RPC_UTIL_H