Add CashAddr Address Format
Ported from Bitcoin Unlimited, Bitcoin ABC
This commit is contained in:
@@ -4,12 +4,12 @@
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "amount.h"
|
||||
#include "base58.h"
|
||||
#include "chain.h"
|
||||
#include "chainparams.h"
|
||||
#include "checkpoints.h"
|
||||
#include "coins.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "dstencode.h"
|
||||
#include "main.h"
|
||||
#include "policy/policy.h"
|
||||
#include "primitives/transaction.h"
|
||||
@@ -139,9 +139,9 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||
|
||||
if (GetSpentIndex(spentKey, spentInfo)) {
|
||||
if (spentInfo.addressType == 1) {
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
|
||||
delta.push_back(Pair("address", EncodeDestination(CKeyID(spentInfo.addressHash))));
|
||||
} else if (spentInfo.addressType == 2) {
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
|
||||
delta.push_back(Pair("address", EncodeDestination(CScriptID(spentInfo.addressHash))));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -169,11 +169,11 @@ UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex)
|
||||
|
||||
if (out.scriptPubKey.IsPayToScriptHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString()));
|
||||
delta.push_back(Pair("address", EncodeDestination(CScriptID(uint160(hashBytes)))));
|
||||
|
||||
} else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
|
||||
vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
|
||||
delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString()));
|
||||
delta.push_back(Pair("address", EncodeDestination(CKeyID(uint160(hashBytes)))));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "consensus/consensus.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "core_io.h"
|
||||
#include "dstencode.h"
|
||||
#include "init.h"
|
||||
#include "main.h"
|
||||
#include "miner.h"
|
||||
@@ -226,6 +227,16 @@ UniValue setgenerate(const UniValue& params, bool fHelp)
|
||||
|
||||
mapArgs["-gen"] = (fGenerate ? "1" : "0");
|
||||
mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
|
||||
|
||||
CTxDestination destination = DecodeDestination(params[1].get_str());
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
|
||||
"Error: Invalid address");
|
||||
}
|
||||
|
||||
boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
|
||||
coinbaseScript->reserveScript = GetScriptForDestination(destination);
|
||||
|
||||
GenerateBitcoins(fGenerate, nGenProcLimit, Params());
|
||||
|
||||
return NullUniValue;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "base58.h"
|
||||
#include "clientversion.h"
|
||||
#include "dstencode.h"
|
||||
#include "init.h"
|
||||
#include "main.h"
|
||||
#include "net.h"
|
||||
@@ -144,8 +145,9 @@ public:
|
||||
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
|
||||
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
|
||||
UniValue a(UniValue::VARR);
|
||||
BOOST_FOREACH(const CTxDestination& addr, addresses)
|
||||
a.push_back(CBitcoinAddress(addr).ToString());
|
||||
for (const CTxDestination &addr : addresses) {
|
||||
a.push_back(EncodeDestination(addr));
|
||||
}
|
||||
obj.push_back(Pair("addresses", a));
|
||||
if (whichType == TX_MULTISIG)
|
||||
obj.push_back(Pair("sigsrequired", nRequired));
|
||||
@@ -188,15 +190,13 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
|
||||
LOCK(cs_main);
|
||||
#endif
|
||||
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
bool isValid = address.IsValid();
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
bool isValid = IsValidDestination(dest);
|
||||
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
ret.push_back(Pair("isvalid", isValid));
|
||||
if (isValid)
|
||||
{
|
||||
CTxDestination dest = address.Get();
|
||||
string currentAddress = address.ToString();
|
||||
if (isValid) {
|
||||
std::string currentAddress = EncodeDestination(dest);
|
||||
ret.push_back(Pair("address", currentAddress));
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(dest);
|
||||
@@ -210,11 +210,21 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
|
||||
ret.pushKVs(detail);
|
||||
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
|
||||
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
|
||||
CKeyID keyID;
|
||||
if (pwalletMain && address.GetKeyID(keyID) && pwalletMain->mapKeyMetadata.count(keyID) && !pwalletMain->mapKeyMetadata[keyID].hdKeypath.empty())
|
||||
{
|
||||
ret.push_back(Pair("hdkeypath", pwalletMain->mapKeyMetadata[keyID].hdKeypath));
|
||||
ret.push_back(Pair("hdmasterkeyid", pwalletMain->mapKeyMetadata[keyID].hdMasterKeyID.GetHex()));
|
||||
if (pwalletMain) {
|
||||
const auto &meta = pwalletMain->mapKeyMetadata;
|
||||
const CKeyID *keyID = boost::get<CKeyID>(&dest);
|
||||
auto it = keyID ? meta.find(*keyID) : meta.end();
|
||||
if (it == meta.end()) {
|
||||
it = meta.find(CScriptID(scriptPubKey));
|
||||
}
|
||||
if (it != meta.end()) {
|
||||
ret.push_back(Pair("timestamp", it->second.nCreateTime));
|
||||
if (!it->second.hdKeypath.empty()) {
|
||||
ret.push_back(Pair("hdkeypath", it->second.hdKeypath));
|
||||
ret.push_back(Pair("hdmasterkeyid",
|
||||
it->second.hdMasterKeyID.GetHex()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -245,17 +255,18 @@ CScript _createmultisig_redeemScript(const UniValue& params)
|
||||
const std::string& ks = keys[i].get_str();
|
||||
#ifdef ENABLE_WALLET
|
||||
// Case 1: Bitcoin address and we have full public key:
|
||||
CBitcoinAddress address(ks);
|
||||
if (pwalletMain && address.IsValid())
|
||||
{
|
||||
CKeyID keyID;
|
||||
if (!address.GetKeyID(keyID))
|
||||
throw runtime_error(
|
||||
strprintf("%s does not refer to a key",ks));
|
||||
CTxDestination dest = DecodeDestination(ks);
|
||||
if (pwalletMain && IsValidDestination(dest)) {
|
||||
const CKeyID *keyID = boost::get<CKeyID>(&dest);
|
||||
if (!keyID) {
|
||||
throw std::runtime_error(
|
||||
strprintf("%s does not refer to a key", ks));
|
||||
}
|
||||
CPubKey vchPubKey;
|
||||
if (!pwalletMain->GetPubKey(keyID, vchPubKey))
|
||||
throw runtime_error(
|
||||
strprintf("no full public key for address %s",ks));
|
||||
if (!pwalletMain->GetPubKey(*keyID, vchPubKey)) {
|
||||
throw std::runtime_error(
|
||||
strprintf("no full public key for address %s", ks));
|
||||
}
|
||||
if (!vchPubKey.IsFullyValid())
|
||||
throw runtime_error(" Invalid public key: "+ks);
|
||||
pubkeys[i] = vchPubKey;
|
||||
@@ -319,10 +330,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
|
||||
// Construct using pay-to-script-hash:
|
||||
CScript inner = _createmultisig_redeemScript(params);
|
||||
CScriptID innerID(inner);
|
||||
CBitcoinAddress address(innerID);
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.push_back(Pair("address", address.ToString()));
|
||||
result.push_back(Pair("address", EncodeDestination(innerID)));
|
||||
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
|
||||
|
||||
return result;
|
||||
@@ -357,13 +367,15 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
|
||||
string strSign = params[1].get_str();
|
||||
string strMessage = params[2].get_str();
|
||||
|
||||
CBitcoinAddress addr(strAddress);
|
||||
if (!addr.IsValid())
|
||||
CTxDestination destination = DecodeDestination(strAddress);
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
|
||||
}
|
||||
|
||||
CKeyID keyID;
|
||||
if (!addr.GetKeyID(keyID))
|
||||
const CKeyID *keyID = boost::get<CKeyID>(&destination);
|
||||
if (!keyID) {
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
|
||||
}
|
||||
|
||||
bool fInvalid = false;
|
||||
vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
|
||||
@@ -379,7 +391,7 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
|
||||
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
|
||||
return false;
|
||||
|
||||
return (pubkey.GetID() == keyID);
|
||||
return (pubkey.GetID() == *keyID);
|
||||
}
|
||||
|
||||
UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
|
||||
@@ -458,9 +470,9 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
|
||||
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address)
|
||||
{
|
||||
if (type == 2) {
|
||||
address = CBitcoinAddress(CScriptID(hash)).ToString();
|
||||
address = EncodeDestination(CScriptID(hash));
|
||||
} else if (type == 1) {
|
||||
address = CBitcoinAddress(CKeyID(hash)).ToString();
|
||||
address = EncodeDestination(CKeyID(hash));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -470,10 +482,10 @@ bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &addr
|
||||
bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses)
|
||||
{
|
||||
if (params[0].isStr()) {
|
||||
CBitcoinAddress address(params[0].get_str());
|
||||
CTxDestination dest = DecodeDestination(params[0].get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type)) {
|
||||
if (IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
@@ -488,10 +500,10 @@ bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint16
|
||||
|
||||
for (std::vector<UniValue>::iterator it = values.begin(); it != values.end(); ++it) {
|
||||
|
||||
CBitcoinAddress address(it->get_str());
|
||||
CTxDestination dest = DecodeDestination(it->get_str());
|
||||
uint160 hashBytes;
|
||||
int type = 0;
|
||||
if (!address.GetIndexKey(hashBytes, type)) {
|
||||
if (IsValidDestination(dest)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
|
||||
}
|
||||
addresses.push_back(std::make_pair(hashBytes, type));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "coins.h"
|
||||
#include "consensus/validation.h"
|
||||
#include "core_io.h"
|
||||
#include "dstencode.h"
|
||||
#include "init.h"
|
||||
#include "keystore.h"
|
||||
#include "main.h"
|
||||
@@ -55,8 +56,10 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
|
||||
out.push_back(Pair("type", GetTxnOutputType(type)));
|
||||
|
||||
UniValue a(UniValue::VARR);
|
||||
BOOST_FOREACH(const CTxDestination& addr, addresses)
|
||||
a.push_back(CBitcoinAddress(addr).ToString());
|
||||
for (const CTxDestination &addr : addresses) {
|
||||
a.push_back(EncodeDestination(addr));
|
||||
}
|
||||
|
||||
out.push_back(Pair("addresses", a));
|
||||
}
|
||||
|
||||
@@ -89,9 +92,9 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue&
|
||||
in.push_back(Pair("value", ValueFromAmount(spentInfo.satoshis)));
|
||||
in.push_back(Pair("valueSat", spentInfo.satoshis));
|
||||
if (spentInfo.addressType == 1) {
|
||||
in.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString()));
|
||||
in.push_back(Pair("address", EncodeDestination(CKeyID(spentInfo.addressHash))));
|
||||
} else if (spentInfo.addressType == 2) {
|
||||
in.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString()));
|
||||
in.push_back(Pair("address", EncodeDestination(CScriptID(spentInfo.addressHash))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,25 +515,30 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
|
||||
rawTx.vin.push_back(in);
|
||||
}
|
||||
|
||||
set<CBitcoinAddress> setAddress;
|
||||
vector<string> addrList = sendTo.getKeys();
|
||||
BOOST_FOREACH(const string& name_, addrList) {
|
||||
|
||||
std::set<CTxDestination> destinations;
|
||||
std::vector<std::string> addrList = sendTo.getKeys();
|
||||
for (const std::string &name_ : addrList) {
|
||||
if (name_ == "data") {
|
||||
std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
|
||||
|
||||
CTxOut out(0, CScript() << OP_RETURN << data);
|
||||
rawTx.vout.push_back(out);
|
||||
} else {
|
||||
CBitcoinAddress address(name_);
|
||||
if (!address.IsValid())
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
|
||||
CTxDestination destination = DecodeDestination(name_);
|
||||
if (!IsValidDestination(destination)) {
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY,
|
||||
std::string("Invalid Bitcoin address: ") +
|
||||
name_);
|
||||
}
|
||||
|
||||
if (setAddress.count(address))
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
|
||||
setAddress.insert(address);
|
||||
if (!destinations.insert(destination).second) {
|
||||
throw JSONRPCError(
|
||||
RPC_INVALID_PARAMETER,
|
||||
std::string("Invalid parameter, duplicated address: ") +
|
||||
name_);
|
||||
}
|
||||
|
||||
CScript scriptPubKey = GetScriptForDestination(address.Get());
|
||||
CScript scriptPubKey = GetScriptForDestination(destination);
|
||||
CAmount nAmount = AmountFromValue(sendTo[name_]);
|
||||
|
||||
CTxOut out(nAmount, scriptPubKey);
|
||||
@@ -650,7 +658,7 @@ UniValue decodescript(const UniValue& params, bool fHelp)
|
||||
if (type.isStr() && type.get_str() != "scripthash") {
|
||||
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
|
||||
// don't return the address for a P2SH of the P2SH.
|
||||
r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
|
||||
r.push_back(Pair("p2sh", EncodeDestination(CScriptID(script))));
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
@@ -96,11 +96,23 @@ void RPCTypeCheckObj(const UniValue& o,
|
||||
if (!fAllowNull && v.isNull())
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
|
||||
|
||||
if (!(t.second.typeAny || v.type() == t.second.type || (fAllowNull && v.isNull()))) {
|
||||
if (!(t.second.typeAny || (v.type() == t.second.type) || (fAllowNull && (v.isNull())))) {
|
||||
string err = strprintf("Expected type %s for %s, got %s",
|
||||
uvTypeName(t.second.type), t.first, uvTypeName(v.type()));
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
|
||||
if (fStrict)
|
||||
{
|
||||
for (const std::string &k : o.getKeys())
|
||||
{
|
||||
if (typesExpected.count(k) == 0)
|
||||
{
|
||||
string err = strprintf("Unexpected keys %s", k);
|
||||
throw JSONRPCError(RPC_TYPE_ERROR, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fStrict)
|
||||
|
||||
Reference in New Issue
Block a user