From fbd44e84d5841867d36d295d4f347fd5e55d293f Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Sun, 6 Mar 2016 02:02:57 +0300 Subject: [PATCH] PUBKEY_PAIR_ADDRESS / PUBKEY_PAIR_ADDRESS_TEST --- src/base58.cpp | 38 ++++++++++++++ src/base58.h | 18 ++++++- src/bitcoinrpc.cpp | 1 - src/bitcoinrpc.h | 1 - src/key.cpp | 8 +++ src/key.h | 1 + src/qt/coincontroldialog.cpp | 2 +- src/rpcdump.cpp | 4 +- src/rpcrawtransaction.cpp | 34 +++++++----- src/rpcwallet.cpp | 115 +++++++++++++++++++++--------------------- src/wallet.cpp | 2 +- 11 files changed, 143 insertions(+), 81 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index 1842853..a524be6 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -183,6 +183,11 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe if (!vchData.empty()) memcpy(&vchData[0], pdata, nSize); } + + const std::vector &CBase58Data::GetData() const + { + return vchData; + } void CBase58Data::SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend) { @@ -243,12 +248,22 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); } + bool CBitcoinAddress::Set(const CMalleablePubKey &mpk) { + std::vector vchPubkeyPair = mpk.Raw(); + SetData(fTestNet ? PUBKEY_PAIR_ADDRESS_TEST : PUBKEY_PAIR_ADDRESS, &vchPubkeyPair[0], 68); + return true; + } + bool CBitcoinAddress::IsValid() const { unsigned int nExpectedSize = 20; bool fExpectTestNet = false; switch(nVersion) { + case PUBKEY_PAIR_ADDRESS: + nExpectedSize = 68; // Serialized pair of public keys + fExpectTestNet = false; + break; case PUBKEY_ADDRESS: nExpectedSize = 20; // Hash of public key fExpectTestNet = false; @@ -258,6 +273,10 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe fExpectTestNet = false; break; + case PUBKEY_PAIR_ADDRESS_TEST: + nExpectedSize = 68; + fExpectTestNet = true; + break; case PUBKEY_ADDRESS_TEST: nExpectedSize = 20; fExpectTestNet = true; @@ -304,6 +323,13 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe keyID = CKeyID(id); return true; } + case PUBKEY_PAIR_ADDRESS: + case PUBKEY_PAIR_ADDRESS_TEST: + { + CMalleablePubKey mPubKey; + mPubKey.setvch(vchData); + keyID = mPubKey.GetID(); + } default: return false; } } @@ -319,6 +345,18 @@ bool DecodeBase58Check(const std::string& str, std::vector& vchRe default: return false; } } + + bool CBitcoinAddress::IsPair() const { + if (!IsValid()) + return false; + switch (nVersion) { + case PUBKEY_PAIR_ADDRESS: + case PUBKEY_PAIR_ADDRESS_TEST: { + return true; + } + default: return false; + } + } void CBitcoinSecret::SetSecret(const CSecret& vchSecret, bool fCompressed) { diff --git a/src/base58.h b/src/base58.h index b8a0e45..b312443 100644 --- a/src/base58.h +++ b/src/base58.h @@ -67,6 +67,7 @@ public: bool SetString(const char* psz); bool SetString(const std::string& str); std::string ToString() const; + const std::vector &GetData() const; int CompareTo(const CBase58Data& b58) const; bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } @@ -91,6 +92,7 @@ public: CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } bool operator()(const CKeyID &id) const; bool operator()(const CScriptID &id) const; + bool operator()(const CMalleablePubKey &mpk) const; bool operator()(const CNoDestination &no) const; }; @@ -99,8 +101,10 @@ class CBitcoinAddress : public CBase58Data public: enum { + PUBKEY_PAIR_ADDRESS = 1, PUBKEY_ADDRESS = 8, SCRIPT_ADDRESS = 20, + PUBKEY_PAIR_ADDRESS_TEST = 6, PUBKEY_ADDRESS_TEST = 111, SCRIPT_ADDRESS_TEST = 196 }; @@ -108,6 +112,7 @@ public: bool Set(const CKeyID &id); bool Set(const CScriptID &id); bool Set(const CTxDestination &dest); + bool Set(const CMalleablePubKey &mpk); bool IsValid() const; CBitcoinAddress() @@ -119,6 +124,11 @@ public: Set(dest); } + CBitcoinAddress(const CMalleablePubKey &mpk) + { + Set(mpk); + } + CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); @@ -132,11 +142,13 @@ public: CTxDestination Get() const; bool GetKeyID(CKeyID &keyID) const; bool IsScript() const; + bool IsPair() const; }; -bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } +bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CMalleablePubKey &mpk) const { return addr->Set(mpk); } +bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } /** A base58-encoded secret key */ class CBitcoinSecret : public CBase58Data diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 80674d6..f52ae80 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -321,7 +321,6 @@ static const CRPCCommand vRPCCommands[] = { "adjustmalleablepubkey", &adjustmalleablepubkey, false, false}, { "listmalleableviews", &listmalleableviews, false, false}, { "dumpmalleablekey", &dumpmalleablekey, false, false}, - { "validatemalleablepubkey",&validatemalleablepubkey,true, false }, { "importmalleablekey", &importmalleablekey, true, false }, { "encryptdata", &encryptdata, false, false }, { "decryptdata", &decryptdata, false, false }, diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 84dd6a4..5befb76 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -211,7 +211,6 @@ extern json_spirit::Value adjustmalleablekey(const json_spirit::Array& params, b extern json_spirit::Value adjustmalleablepubkey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value listmalleableviews(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value dumpmalleablekey(const json_spirit::Array& params, bool fHelp); -extern json_spirit::Value validatemalleablepubkey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value importmalleablekey(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value encryptdata(const json_spirit::Array& params, bool fHelp); // in rpccrypt.cpp diff --git a/src/key.cpp b/src/key.cpp index b1db7cb..1012915 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -725,6 +725,14 @@ std::string CMalleablePubKey::ToString() const return EncodeBase58Check(vch); } +bool CMalleablePubKey::setvch(const std::vector &vchPubKeyPair) +{ + CDataStream ssKey(vchPubKeyPair, SER_NETWORK, PROTOCOL_VERSION); + ssKey >> *this; + + return IsValid(); +} + std::vector CMalleablePubKey::Raw() const { CDataStream ssKey(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/key.h b/src/key.h index bf1557a..bc7e2ab 100644 --- a/src/key.h +++ b/src/key.h @@ -251,6 +251,7 @@ public: return pubKeyL.GetID(); } + bool setvch(const std::vector &vchPubKeyPair); std::vector Raw() const; CPubKey& GetL() { return pubKeyL; } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 998a992..3f67ee6 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -686,7 +686,7 @@ void CoinControlDialog::updateView() // Pay-to-Pubkey-R CMalleableKeyView view; pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view); - sAddress = view.GetMalleablePubKey().ToString().c_str(); + sAddress = CBitcoinAddress(view.GetMalleablePubKey()).ToString().c_str(); } // if listMode or change => show bitcoin address. In tree mode, address is not shown again for direct wallet address outputs diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 6a83604..6e72688 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -260,7 +260,7 @@ Value dumpmalleablekey(const Array& params, bool fHelp) Object result; result.push_back(Pair("PrivatePair", mKey.ToString())); - result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString())); + result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString())); return result; } @@ -284,7 +284,7 @@ Value importmalleablekey(const Array& params, bool fHelp) { fSuccess = pwalletMain->AddMalleableKey(mKey); result.push_back(Pair("Successful", fSuccess)); - result.push_back(Pair("PublicPair", mKey.GetMalleablePubKey().ToString())); + result.push_back(Pair("Address", CBitcoinAddress(mKey.GetMalleablePubKey()).ToString())); result.push_back(Pair("KeyView", CMalleableKeyView(mKey).ToString())); } else diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 7767898..1272156 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -49,7 +49,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH CMalleableKeyView view; if (pwalletMain->CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view)) - out.push_back(Pair("pubkeyPair", view.GetMalleablePubKey().ToString())); + out.push_back(Pair("pubkeyPair", CBitcoinAddress(view.GetMalleablePubKey()).ToString())); } else { @@ -293,23 +293,29 @@ Value createrawtransaction(const Array& params, bool fHelp) // Create output destination script CScript scriptPubKey; CBitcoinAddress address(s.name_); - if (!address.IsValid()) + + if (address.IsValid()) { - CMalleablePubKey mpk(s.name_); - if (!mpk.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_); + if (!address.IsPair()) + { + scriptPubKey.SetDestination(address.Get()); + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); + setAddress.insert(address); + } + else + { + CMalleablePubKey mpk; + if (!mpk.setvch(address.GetData())) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_); - CPubKey keyVariant, R; - mpk.GetVariant(R, keyVariant); - scriptPubKey.SetDestination(R, keyVariant); + CPubKey R, pubKeyVariant; + mpk.GetVariant(R, pubKeyVariant); + scriptPubKey.SetDestination(R, pubKeyVariant); + } } else - { - scriptPubKey.SetDestination(address.Get()); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); - setAddress.insert(address); - } + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid output destination: ")+s.name_); int64_t nAmount = AmountFromValue(s.value_); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 12b6603..a0e6afc 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -329,17 +329,22 @@ Value sendtoaddress(const Array& params, bool fHelp) CBitcoinAddress address(strAddress); if (address.IsValid()) - scriptPubKey.SetDestination(address.Get()); - else { - CMalleablePubKey mpk(strAddress); - if (!mpk.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); + if (!address.IsPair()) + scriptPubKey.SetDestination(address.Get()); + else + { + CMalleablePubKey mpk; + if (!mpk.setvch(address.GetData())) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - CPubKey R, pubKeyVariant; - mpk.GetVariant(R, pubKeyVariant); - scriptPubKey.SetDestination(R, pubKeyVariant); + CPubKey R, pubKeyVariant; + mpk.GetVariant(R, pubKeyVariant); + scriptPubKey.SetDestination(R, pubKeyVariant); + } } + else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); // Amount int64_t nAmount = AmountFromValue(params[1]); @@ -716,17 +721,23 @@ Value sendfrom(const Array& params, bool fHelp) CBitcoinAddress address(strAddress); if (address.IsValid()) - scriptPubKey.SetDestination(address.Get()); - else { - CMalleablePubKey mpk(strAddress); - if (!mpk.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); + if (!address.IsPair()) + scriptPubKey.SetDestination(address.Get()); + else + { + CMalleablePubKey mpk; + if (!mpk.setvch(address.GetData())) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - CPubKey R, pubKeyVariant; - mpk.GetVariant(R, pubKeyVariant); - scriptPubKey.SetDestination(R, pubKeyVariant); + CPubKey R, pubKeyVariant; + mpk.GetVariant(R, pubKeyVariant); + scriptPubKey.SetDestination(R, pubKeyVariant); + } } + else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); + int64_t nAmount = AmountFromValue(params[2]); @@ -1747,18 +1758,34 @@ Value validateaddress(const Array& params, bool fHelp) ret.push_back(Pair("isvalid", isValid)); if (isValid) { - CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); - ret.push_back(Pair("address", currentAddress)); - isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO; - ret.push_back(Pair("ismine", mine != MINE_NO)); - if (mine != MINE_NO) { - ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY)); - Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); - ret.insert(ret.end(), detail.begin(), detail.end()); + if (address.IsPair()) + { + CMalleablePubKey mpk; + mpk.setvch(address.GetData()); + ret.push_back(Pair("ispair", true)); + + CMalleableKeyView view; + bool isMine = pwalletMain->GetMalleableView(mpk, view); + ret.push_back(Pair("ismine", isMine)); + + if (isMine) + ret.push_back(Pair("KeyView", view.ToString())); + } + else + { + CTxDestination dest = address.Get(); + string currentAddress = address.ToString(); + ret.push_back(Pair("address", currentAddress)); + isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : MINE_NO; + ret.push_back(Pair("ismine", mine != MINE_NO)); + if (mine != MINE_NO) { + ret.push_back(Pair("watchonly", mine == MINE_WATCH_ONLY)); + Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); + ret.insert(ret.end(), detail.begin(), detail.end()); + } + if (pwalletMain->mapAddressBook.count(dest)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); } - if (pwalletMain->mapAddressBook.count(dest)) - ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); } return ret; } @@ -1906,43 +1933,16 @@ Value newmalleablekey(const Array& params, bool fHelp) throw runtime_error("Unable to generate new malleable key"); CMalleablePubKey mPubKey = mKey.GetMalleablePubKey(); - CDataStream ssPublicBytes(SER_NETWORK, PROTOCOL_VERSION); - ssPublicBytes << mPubKey; Object result; result.push_back(Pair("PublicPair", mPubKey.ToString())); - result.push_back(Pair("PublicBytes", HexStr(ssPublicBytes.begin(), ssPublicBytes.end()))); + result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw()))); + result.push_back(Pair("Address", CBitcoinAddress(mPubKey).ToString())); result.push_back(Pair("KeyView", keyView.ToString())); return result; } -Value validatemalleablepubkey(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "validatemalleablekey \n" - "Check the validity and ownership for priovided malleable public key.\n"); - - CMalleablePubKey mpk; - bool isValid = mpk.SetString(params[0].get_str()); - - Object result; - result.push_back(Pair("isvalid", isValid)); - - if (isValid) - { - CMalleableKeyView view; - bool isMine = pwalletMain->GetMalleableView(mpk, view); - result.push_back(Pair("ismine", isMine)); - - if (isMine) - result.push_back(Pair("KeyView", view.ToString())); - } - - return result; -} - Value adjustmalleablekey(const Array& params, bool fHelp) { if (fHelp || params.size() != 3) @@ -1982,8 +1982,7 @@ Value adjustmalleablepubkey(const Array& params, bool fHelp) CMalleablePubKey malleablePubKey; if (pubKeyPair.size() == 136) { - CDataStream ssPublicBytes(ParseHex(pubKeyPair), SER_NETWORK, PROTOCOL_VERSION); - ssPublicBytes >> malleablePubKey; + malleablePubKey.setvch(ParseHex(pubKeyPair)); } else malleablePubKey.SetString(pubKeyPair); diff --git a/src/wallet.cpp b/src/wallet.cpp index ee601ca..908afaa 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -2829,7 +2829,7 @@ bool CWallet::ExtractAddress(const CScript& scriptPubKey, std::string& addressRe if (!CheckOwnership(CPubKey(vSolutions[0]), CPubKey(vSolutions[1]), view)) return false; - addressRet = view.GetMalleablePubKey().ToString(); + addressRet = CBitcoinAddress(view.GetMalleablePubKey()).ToString(); return true; } else if (whichType == TX_PUBKEYHASH) -- 1.7.1