elements/src/rpc/util.cpp
2019-03-20 12:05:48 +00:00

308 lines
9.9 KiB
C++

// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key_io.h>
#include <keystore.h>
#include <rpc/protocol.h>
#include <rpc/util.h>
#include <tinyformat.h>
#include <utilstrencodings.h>
#include <policy/policy.h>
#include <assetsdir.h>
#include <core_io.h>
// Converts a hex string to a public key if possible
CPubKey HexToPubKey(const std::string& hex_in)
{
if (!IsHex(hex_in)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
}
CPubKey vchPubKey(ParseHex(hex_in));
if (!vchPubKey.IsFullyValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid public key: " + hex_in);
}
return vchPubKey;
}
// Retrieves a public key for an address from the given CKeyStore
CPubKey AddrToPubKey(CKeyStore* const keystore, const std::string& addr_in)
{
CTxDestination dest = DecodeDestination(addr_in);
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address: " + addr_in);
}
CKeyID key = GetKeyForDestination(*keystore, dest);
if (key.IsNull()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("%s does not refer to a key", addr_in));
}
CPubKey vchPubKey;
if (!keystore->GetPubKey(key, vchPubKey)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("no full public key for address %s", addr_in));
}
if (!vchPubKey.IsFullyValid()) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet contains an invalid public key");
}
return vchPubKey;
}
// Creates a multisig redeemscript from a given list of public keys and number required.
CScript CreateMultisigRedeemscript(const int required, const std::vector<CPubKey>& pubkeys)
{
// Gather public keys
if (required < 1) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "a multisignature address must require at least one key to redeem");
}
if ((int)pubkeys.size() < required) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("not enough keys supplied (got %u keys, but need at least %d to redeem)", pubkeys.size(), required));
}
if (pubkeys.size() > 16) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Number of keys involved in the multisignature address creation > 16\nReduce the number");
}
CScript result = GetScriptForMultisig(required, pubkeys);
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) {
throw JSONRPCError(RPC_INVALID_PARAMETER, (strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)));
}
return result;
}
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
public:
explicit DescribeAddressVisitor() {}
UniValue operator()(const CNoDestination& dest) const
{
return UniValue(UniValue::VOBJ);
}
UniValue operator()(const PKHash& keyID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", false);
obj.pushKV("iswitness", false);
return obj;
}
UniValue operator()(const ScriptHash& scriptID) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", true);
obj.pushKV("iswitness", false);
return obj;
}
UniValue operator()(const WitnessV0KeyHash& id) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", false);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
return obj;
}
UniValue operator()(const WitnessV0ScriptHash& id) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", true);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
return obj;
}
UniValue operator()(const WitnessUnknown& id) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", (int)id.version);
obj.pushKV("witness_program", HexStr(id.program, id.program + id.length));
return obj;
}
UniValue operator()(const NullData& id) const
{
UniValue obj(UniValue::VOBJ);
obj.pushKV("isscript", false);
obj.pushKV("iswitness", false);
return obj;
}
};
UniValue DescribeAddress(const CTxDestination& dest)
{
return boost::apply_visitor(DescribeAddressVisitor(), dest);
}
// ELEMENTS
class BlindingPubkeyVisitor : public boost::static_visitor<CPubKey>
{
public:
explicit BlindingPubkeyVisitor() {}
CPubKey operator()(const CNoDestination& dest) const
{
return CPubKey();
}
CPubKey operator()(const PKHash& keyID) const
{
return keyID.blinding_pubkey;
}
CPubKey operator()(const ScriptHash& scriptID) const
{
return scriptID.blinding_pubkey;
}
CPubKey operator()(const WitnessV0KeyHash& id) const
{
return id.blinding_pubkey;
}
CPubKey operator()(const WitnessV0ScriptHash& id) const
{
return id.blinding_pubkey;
}
CPubKey operator()(const WitnessUnknown& id) const
{
return id.blinding_pubkey;
}
CPubKey operator()(const NullData& id) const
{
return CPubKey();
}
};
CPubKey GetDestinationBlindingKey(const CTxDestination& dest) {
return boost::apply_visitor(BlindingPubkeyVisitor(), dest);
}
bool IsBlindDestination(const CTxDestination& dest) {
return GetDestinationBlindingKey(dest).IsFullyValid();
}
class DescribeBlindAddressVisitor : public boost::static_visitor<UniValue>
{
public:
explicit DescribeBlindAddressVisitor() {}
UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
UniValue operator()(const PKHash& pkhash) const
{
UniValue obj(UniValue::VOBJ);
const CPubKey& blind_pub = pkhash.blinding_pubkey;
if (IsBlindDestination(pkhash)) {
obj.pushKV("confidential_key", HexStr(blind_pub.begin(), blind_pub.end()));
PKHash unblinded(pkhash);
unblinded.blinding_pubkey = CPubKey();
obj.pushKV("unconfidential", EncodeDestination(unblinded));
} else {
obj.pushKV("confidential_key", "");
obj.pushKV("unconfidential", EncodeDestination(pkhash));
}
return obj;
}
UniValue operator()(const ScriptHash& scripthash) const
{
UniValue obj(UniValue::VOBJ);
const CPubKey& blind_pub = scripthash.blinding_pubkey;
if (IsBlindDestination(scripthash)) {
obj.pushKV("confidential_key", HexStr(blind_pub.begin(), blind_pub.end()));
ScriptHash unblinded(scripthash);
unblinded.blinding_pubkey = CPubKey();
obj.pushKV("unconfidential", EncodeDestination(unblinded));
} else {
obj.pushKV("confidential_key", "");
obj.pushKV("unconfidential", EncodeDestination(scripthash));
}
return obj;
}
UniValue operator()(const WitnessV0KeyHash& id) const
{
UniValue obj(UniValue::VOBJ);
const CPubKey& blind_pub = id.blinding_pubkey;
if (IsBlindDestination(id)) {
obj.pushKV("confidential_key", HexStr(blind_pub.begin(), blind_pub.end()));
WitnessV0KeyHash unblinded(id);
unblinded.blinding_pubkey = CPubKey();
obj.pushKV("unconfidential", EncodeDestination(unblinded));
} else {
obj.pushKV("confidential_key", "");
obj.pushKV("unconfidential", EncodeDestination(id));
}
return obj;
}
UniValue operator()(const WitnessV0ScriptHash& id) const
{
UniValue obj(UniValue::VOBJ);
const CPubKey& blind_pub = id.blinding_pubkey;
if (IsBlindDestination(id)) {
obj.pushKV("confidential_key", HexStr(blind_pub.begin(), blind_pub.end()));
WitnessV0ScriptHash unblinded(id);
unblinded.blinding_pubkey = CPubKey();
obj.pushKV("unconfidential", EncodeDestination(unblinded));
} else {
obj.pushKV("confidential_key", "");
obj.pushKV("unconfidential", EncodeDestination(id));
}
return obj;
}
UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
UniValue operator()(const NullData& id) const { return NullUniValue; }
};
UniValue DescribeBlindAddress(const CTxDestination& dest)
{
UniValue ret(UniValue::VOBJ);
ret.pushKVs(boost::apply_visitor(DescribeBlindAddressVisitor(), 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<CAsset, CAmount>::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;
}