X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Frpcwallet.cpp;h=aa91f7f68727557d8039e38a503c10845cd9f5d3;hp=acd79447b783999f5d483b717fca3d8ecf8737f8;hb=34694c603fa90378d59d70804a5862df3845b2b8;hpb=4d4c9b251499ec3c8d7fc0ce6e661954f56c6fcf diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index acd7944..aa91f7f 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -7,20 +7,23 @@ #include "walletdb.h" #include "bitcoinrpc.h" #include "init.h" +#include "util.h" +#include "ntp.h" #include "base58.h" using namespace json_spirit; using namespace std; -int64 nWalletUnlockTime; +int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry); +extern int64_t nReserveBalance; +extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry); std::string HelpRequiringPassphrase() { return pwalletMain->IsCrypted() - ? "\nrequires wallet passphrase to be set with walletpassphrase first" + ? "\n\nRequires wallet passphrase to be set with walletpassphrase first" : ""; } @@ -42,11 +45,11 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) { entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); + entry.push_back(Pair("blocktime", (int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); } entry.push_back(Pair("txid", wtx.GetHash().GetHex())); - entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); - entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); + entry.push_back(Pair("time", (int64_t)wtx.GetTxTime())); + entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived)); BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); } @@ -69,58 +72,47 @@ Value getinfo(const Array& params, bool fHelp) proxyType proxy; GetProxy(NET_IPV4, proxy); - Object obj; + Object obj, diff, timestamping; obj.push_back(Pair("version", FormatFullVersion())); obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); + obj.push_back(Pair("unspendable", ValueFromAmount(pwalletMain->GetWatchOnlyBalance()))); obj.push_back(Pair("newmint", ValueFromAmount(pwalletMain->GetNewMint()))); obj.push_back(Pair("stake", ValueFromAmount(pwalletMain->GetStake()))); obj.push_back(Pair("blocks", (int)nBestHeight)); + + timestamping.push_back(Pair("systemclock", GetTime())); + timestamping.push_back(Pair("adjustedtime", GetAdjustedTime())); + + int64_t nNtpOffset = GetNtpOffset(), + nP2POffset = GetNodesOffset(); + + timestamping.push_back(Pair("ntpoffset", nNtpOffset != INT64_MAX ? nNtpOffset : Value::null)); + timestamping.push_back(Pair("p2poffset", nP2POffset != INT64_MAX ? nP2POffset : Value::null)); + + obj.push_back(Pair("timestamping", timestamping)); + obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply))); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); obj.push_back(Pair("ip", addrSeenByPeer.ToStringIP())); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + + diff.push_back(Pair("proof-of-work", GetDifficulty())); + diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true)))); + obj.push_back(Pair("difficulty", diff)); + obj.push_back(Pair("testnet", fTestNet)); - obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); + obj.push_back(Pair("keypoololdest", (int64_t)pwalletMain->GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); + obj.push_back(Pair("mininput", ValueFromAmount(nMinimumInputValue))); if (pwalletMain->IsCrypted()) - obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime / 1000)); + obj.push_back(Pair("unlocked_until", (int64_t)nWalletUnlockTime / 1000)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; } - -Value getnewpubkey(const Array& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getnewpubkey [account]\n" - "Returns new public key for coinbase generation."); - - // Parse the account first so we don't generate a key if there's an error - string strAccount; - if (params.size() > 0) - strAccount = AccountFromValue(params[0]); - - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - // Generate a new key that is added to wallet - CPubKey newKey; - if (!pwalletMain->GetKeyFromPool(newKey, false)) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - CKeyID keyID = newKey.GetID(); - - pwalletMain->SetAddressBookName(keyID, strAccount); - vector vchPubKey = newKey.Raw(); - - return HexStr(vchPubKey.begin(), vchPubKey.end()); -} - - Value getnewaddress(const Array& params, bool fHelp) { if (fHelp || params.size() > 1) @@ -142,11 +134,11 @@ Value getnewaddress(const Array& params, bool fHelp) CPubKey newKey; if (!pwalletMain->GetKeyFromPool(newKey, false)) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - CKeyID keyID = newKey.GetID(); + CBitcoinAddress address(newKey.GetID()); - pwalletMain->SetAddressBookName(keyID, strAccount); + pwalletMain->SetAddressBookName(address, strAccount); - return CBitcoinAddress(keyID).ToString(); + return address.ToString(); } @@ -224,14 +216,14 @@ Value setaccount(const Array& params, bool fHelp) strAccount = AccountFromValue(params[1]); // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwalletMain->mapAddressBook.count(address.Get())) + if (pwalletMain->mapAddressBook.count(address)) { - string strOldAccount = pwalletMain->mapAddressBook[address.Get()]; + string strOldAccount = pwalletMain->mapAddressBook[address]; if (address == GetAccountAddress(strOldAccount)) GetAccountAddress(strOldAccount, true); } - pwalletMain->SetAddressBookName(address.Get(), strAccount); + pwalletMain->SetAddressBookName(address, strAccount); return Value::null; } @@ -249,7 +241,7 @@ Value getaccount(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); string strAccount; - map::iterator mi = pwalletMain->mapAddressBook.find(address.Get()); + map::iterator mi = pwalletMain->mapAddressBook.find(address); if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty()) strAccount = (*mi).second; return strAccount; @@ -277,22 +269,74 @@ Value getaddressesbyaccount(const Array& params, bool fHelp) return ret; } +Value mergecoins(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "mergecoins \n" + " is resulting inputs sum\n" + " is minimum value of inputs which are used in join process\n" + " is resulting value of inputs which will be created\n" + "All values are real and and rounded to the nearest " + FormatMoney(nMinimumInputValue) + + HelpRequiringPassphrase()); + + if (pwalletMain->IsLocked()) + throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); + + // Total amount + int64_t nAmount = AmountFromValue(params[0]); + + // Min input amount + int64_t nMinValue = AmountFromValue(params[1]); + + // Output amount + int64_t nOutputValue = AmountFromValue(params[2]); + + if (nAmount < nMinimumInputValue) + throw JSONRPCError(-101, "Send amount too small"); + + if (nMinValue < nMinimumInputValue) + throw JSONRPCError(-101, "Max value too small"); + + if (nOutputValue < nMinimumInputValue) + throw JSONRPCError(-101, "Output value too small"); + + if (nOutputValue < nMinValue) + throw JSONRPCError(-101, "Output value is lower than min value"); + + list listMerged; + if (!pwalletMain->MergeCoins(nAmount, nMinValue, nOutputValue, listMerged)) + return Value::null; + + Array mergedHashes; + BOOST_FOREACH(const uint256 txHash, listMerged) + mergedHashes.push_back(txHash.GetHex()); + + return mergedHashes; +} + Value sendtoaddress(const Array& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( "sendtoaddress [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.000001" + " is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue) + HelpRequiringPassphrase()); - CBitcoinAddress address(params[0].get_str()); - if (!address.IsValid()) + // Parse address + CScript scriptPubKey; + string strAddress = params[0].get_str(); + + CBitcoinAddress address(strAddress); + if (address.IsValid()) + scriptPubKey.SetAddress(address); + else throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); // Amount - int64 nAmount = AmountFromValue(params[1]); + int64_t nAmount = AmountFromValue(params[1]); - if (nAmount < MIN_TXOUT_AMOUNT) + if (nAmount < nMinimumInputValue) throw JSONRPCError(-101, "Send amount too small"); // Wallet comments @@ -305,8 +349,8 @@ Value sendtoaddress(const Array& params, bool fHelp) if (pwalletMain->IsLocked()) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first."); - string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); - if (strError != "") + string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx); + if (!strError.empty()) throw JSONRPCError(RPC_WALLET_ERROR, strError); return wtx.GetHash().GetHex(); @@ -322,19 +366,19 @@ Value listaddressgroupings(const Array& params, bool fHelp) "in past transactions"); Array jsonGroupings; - map balances = pwalletMain->GetAddressBalances(); - BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings()) + map balances = pwalletMain->GetAddressBalances(); + BOOST_FOREACH(set grouping, pwalletMain->GetAddressGroupings()) { Array jsonGrouping; - BOOST_FOREACH(CTxDestination address, grouping) + BOOST_FOREACH(CBitcoinAddress address, grouping) { Array addressInfo; - addressInfo.push_back(CBitcoinAddress(address).ToString()); + addressInfo.push_back(address.ToString()); addressInfo.push_back(ValueFromAmount(balances[address])); { LOCK(pwalletMain->cs_wallet); - if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end()) - addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second); + if (pwalletMain->mapAddressBook.find(address) != pwalletMain->mapAddressBook.end()) + addressInfo.push_back(pwalletMain->mapAddressBook.find(address)->second); } jsonGrouping.push_back(addressInfo); } @@ -407,11 +451,11 @@ Value verifymessage(const Array& params, bool fHelp) ss << strMessageMagic; ss << strMessage; - CKey key; + CPubKey key; if (!key.SetCompactSignature(Hash(ss.begin(), ss.end()), vchSig)) return false; - return (key.GetPubKey().GetID() == keyID); + return (key.GetID() == keyID); } @@ -419,46 +463,46 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "getreceivedbyaddress [minconf=1]\n" - "Returns the total amount received by in transactions with at least [minconf] confirmations."); + "getreceivedbyaddress [minconf=1]\n" + "Returns the total amount received by in transactions with at least [minconf] confirmations."); // Bitcoin address CBitcoinAddress address = CBitcoinAddress(params[0].get_str()); - CScript scriptPubKey; if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - scriptPubKey.SetDestination(address.Get()); - if (!IsMine(*pwalletMain,scriptPubKey)) - return (double)0.0; + if (!IsMine(*pwalletMain,address)) + return 0.0; // Minimum confirmations int nMinDepth = 1; if (params.size() > 1) nMinDepth = params[1].get_int(); - // Tally - int64 nAmount = 0; + int64_t nAmount = 0; for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal()) continue; - BOOST_FOREACH(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) + { + CBitcoinAddress addressRet; + if (!ExtractAddress(*pwalletMain, txout.scriptPubKey, addressRet)) + continue; + if (addressRet == address) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; + } } return ValueFromAmount(nAmount); } - -void GetAccountAddresses(string strAccount, set& setAddress) +void GetAccountAddresses(string strAccount, set& setAddress) { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) { - const CTxDestination& address = item.first; + const CBitcoinAddress& address = item.first; const string& strName = item.second; if (strName == strAccount) setAddress.insert(address); @@ -479,11 +523,11 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) // Get the set of pub keys assigned to account string strAccount = AccountFromValue(params[0]); - set setAddress; + set setAddress; GetAccountAddresses(strAccount, setAddress); // Tally - int64 nAmount = 0; + int64_t nAmount = 0; for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; @@ -492,8 +536,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) BOOST_FOREACH(const CTxOut& txout, wtx.vout) { - CTxDestination address; - if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) + CBitcoinAddress address; + if (ExtractAddress(*pwalletMain, txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address)) if (wtx.GetDepthInMainChain() >= nMinDepth) nAmount += txout.nValue; } @@ -503,9 +547,9 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) } -int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) +int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) { - int64 nBalance = 0; + int64_t nBalance = 0; // Tally wallet transactions for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) @@ -514,8 +558,8 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD if (!wtx.IsFinal()) continue; - int64 nGenerated, nReceived, nSent, nFee; - wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee); + int64_t nGenerated, nReceived, nSent, nFee; + wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee, filter); if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) nBalance += nReceived; @@ -528,10 +572,10 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD return nBalance; } -int64 GetAccountBalance(const string& strAccount, int nMinDepth) +int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) { CWalletDB walletdb(pwalletMain->strWalletFile); - return GetAccountBalance(walletdb, strAccount, nMinDepth); + return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); } @@ -539,9 +583,10 @@ Value getbalance(const Array& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( - "getbalance [account] [minconf=1]\n" + "getbalance [account] [minconf=1] [watchonly=0]\n" "If [account] is not specified, returns the server's total available balance.\n" - "If [account] is specified, returns the balance in the account."); + "If [account] is specified, returns the balance in the account.\n" + "if [includeWatchonly] is specified, include balance in watchonly addresses (see 'importaddress')."); if (params.size() == 0) return ValueFromAmount(pwalletMain->GetBalance()); @@ -549,31 +594,35 @@ Value getbalance(const Array& params, bool fHelp) int nMinDepth = 1; if (params.size() > 1) nMinDepth = params[1].get_int(); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 2) + if(params[2].get_bool()) + filter = filter | MINE_WATCH_ONLY; if (params[0].get_str() == "*") { // Calculate total balance a different way from GetBalance() // (GetBalance() sums up all unspent TxOuts) - // getbalance and getbalance '*' should always return the same number. - int64 nBalance = 0; + // getbalance and getbalance '*' 0 should return the same number. + int64_t nBalance = 0; for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - if (!wtx.IsFinal()) + if (!wtx.IsTrusted()) continue; - int64 allGeneratedImmature, allGeneratedMature, allFee; + int64_t allGeneratedImmature, allGeneratedMature, allFee; allGeneratedImmature = allGeneratedMature = allFee = 0; string strSentAccount; - list > listReceived; - list > listSent; - wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount); + list > listReceived; + list > listSent; + wtx.GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter); if (wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived) nBalance += r.second; } - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64)& r, listSent) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listSent) nBalance -= r.second; nBalance -= allFee; nBalance += allGeneratedMature; @@ -583,7 +632,7 @@ Value getbalance(const Array& params, bool fHelp) string strAccount = AccountFromValue(params[0]); - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter); return ValueFromAmount(nBalance); } @@ -598,9 +647,9 @@ Value movecmd(const Array& params, bool fHelp) string strFrom = AccountFromValue(params[0]); string strTo = AccountFromValue(params[1]); - int64 nAmount = AmountFromValue(params[2]); + int64_t nAmount = AmountFromValue(params[2]); - if (nAmount < MIN_TXOUT_AMOUNT) + if (nAmount < nMinimumInputValue) throw JSONRPCError(-101, "Send amount too small"); if (params.size() > 3) @@ -614,7 +663,7 @@ Value movecmd(const Array& params, bool fHelp) if (!walletdb.TxnBegin()) throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); - int64 nNow = GetAdjustedTime(); + int64_t nNow = GetAdjustedTime(); // Debit CAccountingEntry debit; @@ -648,16 +697,25 @@ Value sendfrom(const Array& params, bool fHelp) if (fHelp || params.size() < 3 || params.size() > 6) throw runtime_error( "sendfrom [minconf=1] [comment] [comment-to]\n" - " is a real and is rounded to the nearest 0.000001" + " is a real and is rounded to the nearest " + FormatMoney(nMinimumInputValue) + HelpRequiringPassphrase()); string strAccount = AccountFromValue(params[0]); - CBitcoinAddress address(params[1].get_str()); - if (!address.IsValid()) + + // Parse address + CScript scriptPubKey; + string strAddress = params[0].get_str(); + + CBitcoinAddress address(strAddress); + if (address.IsValid()) + scriptPubKey.SetAddress(address); + else throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid NovaCoin address"); - int64 nAmount = AmountFromValue(params[2]); - if (nAmount < MIN_TXOUT_AMOUNT) + + int64_t nAmount = AmountFromValue(params[2]); + + if (nAmount < nMinimumInputValue) throw JSONRPCError(-101, "Send amount too small"); int nMinDepth = 1; @@ -674,13 +732,13 @@ Value sendfrom(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE); if (nAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); // Send - string strError = pwalletMain->SendMoneyToDestination(address.Get(), nAmount, wtx); - if (strError != "") + string strError = pwalletMain->SendMoney(scriptPubKey, nAmount, wtx); + if (!strError.empty()) throw JSONRPCError(RPC_WALLET_ERROR, strError); return wtx.GetHash().GetHex(); @@ -691,7 +749,7 @@ Value sendmany(const Array& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 4) throw runtime_error( - "sendmany {address:amount,...} [minconf=1] [comment]\n" + "sendmany '{address:amount,...}' [minconf=1] [comment]\n" "amounts are double-precision floating point numbers" + HelpRequiringPassphrase()); @@ -707,24 +765,27 @@ Value sendmany(const Array& params, bool fHelp) wtx.mapValue["comment"] = params[3].get_str(); set setAddress; - vector > vecSend; + vector > vecSend; - int64 totalAmount = 0; + int64_t totalAmount = 0; BOOST_FOREACH(const Pair& s, sendTo) { CBitcoinAddress address(s.name_); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid NovaCoin address: ")+s.name_); - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); - setAddress.insert(address); + if (!address.IsPair()) + { + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); + setAddress.insert(address); + } CScript scriptPubKey; - scriptPubKey.SetDestination(address.Get()); - int64 nAmount = AmountFromValue(s.value_); + scriptPubKey.SetAddress(address); + int64_t nAmount = AmountFromValue(s.value_); - if (nAmount < MIN_TXOUT_AMOUNT) + if (nAmount < nMinimumInputValue) throw JSONRPCError(-101, "Send amount too small"); totalAmount += nAmount; @@ -735,17 +796,18 @@ Value sendmany(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64 nBalance = GetAccountBalance(strAccount, nMinDepth); + int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, MINE_SPENDABLE); if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); // Send CReserveKey keyChange(pwalletMain); - int64 nFeeRequired = 0; + int64_t nFeeRequired = 0; bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired); if (!fCreated) { - if (totalAmount + nFeeRequired > pwalletMain->GetBalance()) + int64_t nTotal = pwalletMain->GetBalance(), nWatchOnly = pwalletMain->GetWatchOnlyBalance(); + if (totalAmount + nFeeRequired > nTotal - nWatchOnly) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds"); throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed"); } @@ -778,8 +840,10 @@ Value addmultisigaddress(const Array& params, bool fHelp) if ((int)keys.size() < nRequired) throw runtime_error( strprintf("not enough keys supplied " - "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); - std::vector pubkeys; + "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired)); + if (keys.size() > 16) + throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); + std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) { @@ -797,16 +861,18 @@ Value addmultisigaddress(const Array& params, bool fHelp) if (!pwalletMain->GetPubKey(keyID, vchPubKey)) throw runtime_error( strprintf("no full public key for address %s",ks.c_str())); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } // Case 2: hex public key else if (IsHex(ks)) { CPubKey vchPubKey(ParseHex(ks)); - if (!vchPubKey.IsValid() || !pubkeys[i].SetPubKey(vchPubKey)) + if (!vchPubKey.IsValid()) throw runtime_error(" Invalid public key: "+ks); + pubkeys[i] = vchPubKey; } else { @@ -817,17 +883,45 @@ Value addmultisigaddress(const Array& params, bool fHelp) // Construct using pay-to-script-hash: CScript inner; inner.SetMultisig(nRequired, pubkeys); - CScriptID innerID = inner.GetID(); + + if (inner.size() > MAX_SCRIPT_ELEMENT_SIZE) + throw runtime_error( + strprintf("redeemScript exceeds size limit: %" PRIszu " > %d", inner.size(), MAX_SCRIPT_ELEMENT_SIZE)); + pwalletMain->AddCScript(inner); + CBitcoinAddress address(inner.GetID()); - pwalletMain->SetAddressBookName(innerID, strAccount); - return CBitcoinAddress(innerID).ToString(); + pwalletMain->SetAddressBookName(address, strAccount); + return address.ToString(); } +Value addredeemscript(const Array& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + { + string msg = "addredeemscript [account]\n" + "Add a P2SH address with a specified redeemScript to the wallet.\n" + "If [account] is specified, assign address to [account]."; + throw runtime_error(msg); + } + + string strAccount; + if (params.size() > 1) + strAccount = AccountFromValue(params[1]); + + // Construct using pay-to-script-hash: + vector innerData = ParseHexV(params[0], "redeemScript"); + CScript inner(innerData.begin(), innerData.end()); + pwalletMain->AddCScript(inner); + CBitcoinAddress address(inner.GetID()); + + pwalletMain->SetAddressBookName(address, strAccount); + return address.ToString(); +} struct tallyitem { - int64 nAmount; + int64_t nAmount; int nConf; tallyitem() { @@ -884,7 +978,7 @@ Value ListReceived(const Array& params, bool fByAccounts) if (it == mapTally.end() && !fIncludeEmpty) continue; - int64 nAmount = 0; + int64_t nAmount = 0; int nConf = std::numeric_limits::max(); if (it != mapTally.end()) { @@ -913,7 +1007,7 @@ Value ListReceived(const Array& params, bool fByAccounts) { for (map::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { - int64 nAmount = (*it).second.nAmount; + int64_t nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; Object obj; obj.push_back(Pair("account", (*it).first)); @@ -957,19 +1051,25 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) return ListReceived(params, true); } -void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret) +static void MaybePushAddress(Object & entry, const CBitcoinAddress &dest) +{ + entry.push_back(Pair("address", dest.ToString())); +} + +void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter) { - int64 nGeneratedImmature, nGeneratedMature, nFee; + int64_t nGeneratedImmature, nGeneratedMature, nFee; string strSentAccount; - list > listReceived; - list > listSent; + list > listReceived; + list > listSent; - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, filter); bool fAllAccounts = (strAccount == string("*")); + bool involvesWatchonly = wtx.IsFromMe(MINE_WATCH_ONLY); // Generated blocks assigned to account "" - if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == "")) + if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount.empty())) { Object entry; entry.push_back(Pair("account", string(""))); @@ -991,12 +1091,20 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Sent if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent) { Object entry; entry.push_back(Pair("account", strSentAccount)); - entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); - entry.push_back(Pair("category", "send")); + if(involvesWatchonly || (::IsMine(*pwalletMain, s.first) & MINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); + MaybePushAddress(entry, s.first); + + if (wtx.GetDepthInMainChain() < 0) { + entry.push_back(Pair("category", "conflicted")); + } else { + entry.push_back(Pair("category", "send")); + } + entry.push_back(Pair("amount", ValueFromAmount(-s.second))); entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) @@ -1008,7 +1116,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived) { string account; if (pwalletMain->mapAddressBook.count(r.first)) @@ -1017,7 +1125,9 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", account)); - entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); + if(involvesWatchonly || (::IsMine(*pwalletMain, r.first) & MINE_WATCH_ONLY)) + entry.push_back(Pair("involvesWatchonly", true)); + MaybePushAddress(entry, r.first); if (wtx.IsCoinBase()) { if (wtx.GetDepthInMainChain() < 1) @@ -1047,7 +1157,7 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar Object entry; entry.push_back(Pair("account", acentry.strAccount)); entry.push_back(Pair("category", "move")); - entry.push_back(Pair("time", (boost::int64_t)acentry.nTime)); + entry.push_back(Pair("time", (int64_t)acentry.nTime)); entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit))); entry.push_back(Pair("otheraccount", acentry.strOtherAccount)); entry.push_back(Pair("comment", acentry.strComment)); @@ -1072,6 +1182,11 @@ Value listtransactions(const Array& params, bool fHelp) if (params.size() > 2) nFrom = params[2].get_int(); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 3) + if(params[3].get_bool()) + filter = filter | MINE_WATCH_ONLY; + if (nCount < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); if (nFrom < 0) @@ -1087,7 +1202,7 @@ Value listtransactions(const Array& params, bool fHelp) { CWalletTx *const pwtx = (*it).second.first; if (pwtx != 0) - ListTransactions(*pwtx, strAccount, 0, true, ret); + ListTransactions(*pwtx, strAccount, 0, true, ret, filter); CAccountingEntry *const pacentry = (*it).second.second; if (pacentry != 0) AcentryToJSON(*pacentry, strAccount, ret); @@ -1124,8 +1239,14 @@ Value listaccounts(const Array& params, bool fHelp) if (params.size() > 0) nMinDepth = params[0].get_int(); - map mapAccountBalances; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { + isminefilter includeWatchonly = MINE_SPENDABLE; + if(params.size() > 1) + if(params[1].get_bool()) + includeWatchonly = includeWatchonly | MINE_WATCH_ONLY; + + + map mapAccountBalances; + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first)) // This address belongs to me mapAccountBalances[entry.second] = 0; } @@ -1133,18 +1254,18 @@ Value listaccounts(const Array& params, bool fHelp) for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - int64 nGeneratedImmature, nGeneratedMature, nFee; + int64_t nGeneratedImmature, nGeneratedMature, nFee; string strSentAccount; - list > listReceived; - list > listSent; - wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); + list > listReceived; + list > listSent; + wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount, includeWatchonly); mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& s, listSent) mapAccountBalances[strSentAccount] -= s.second; if (wtx.GetDepthInMainChain() >= nMinDepth) { mapAccountBalances[""] += nGeneratedMature; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64_t)& r, listReceived) if (pwalletMain->mapAddressBook.count(r.first)) mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; else @@ -1158,7 +1279,7 @@ Value listaccounts(const Array& params, bool fHelp) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; Object ret; - BOOST_FOREACH(const PAIRTYPE(string, int64)& accountBalance, mapAccountBalances) { + BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -1173,6 +1294,7 @@ Value listsinceblock(const Array& params, bool fHelp) CBlockIndex *pindex = NULL; int target_confirms = 1; + isminefilter filter = MINE_SPENDABLE; if (params.size() > 0) { @@ -1190,6 +1312,10 @@ Value listsinceblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); } + if(params.size() > 2) + if(params[2].get_bool()) + filter = filter | MINE_WATCH_ONLY; + int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; Array transactions; @@ -1199,7 +1325,7 @@ Value listsinceblock(const Array& params, bool fHelp) CWalletTx tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain() < depth) - ListTransactions(tx, "*", 0, true, transactions); + ListTransactions(tx, "*", 0, true, transactions, filter); } uint256 lastblock; @@ -1237,6 +1363,11 @@ Value gettransaction(const Array& params, bool fHelp) uint256 hash; hash.SetHex(params[0].get_str()); + isminefilter filter = MINE_SPENDABLE; + if(params.size() > 1) + if(params[1].get_bool()) + filter = filter | MINE_WATCH_ONLY; + Object entry; if (pwalletMain->mapWallet.count(hash)) @@ -1245,19 +1376,19 @@ Value gettransaction(const Array& params, bool fHelp) TxToJSON(wtx, 0, entry); - int64 nCredit = wtx.GetCredit(); - int64 nDebit = wtx.GetDebit(); - int64 nNet = nCredit - nDebit; - int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0); + int64_t nCredit = wtx.GetCredit(filter); + int64_t nDebit = wtx.GetDebit(filter); + int64_t nNet = nCredit - nDebit; + int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); - if (wtx.IsFromMe()) + if (wtx.IsFromMe(filter)) entry.push_back(Pair("fee", ValueFromAmount(nFee))); WalletTxToJSON(wtx, entry); Array details; - ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details); + ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details, filter); entry.push_back(Pair("details", details)); } else @@ -1266,7 +1397,6 @@ Value gettransaction(const Array& params, bool fHelp) uint256 hashBlock = 0; if (GetTransaction(hash, tx, hashBlock)) { - entry.push_back(Pair("txid", hash.GetHex())); TxToJSON(tx, 0, entry); if (hashBlock == 0) entry.push_back(Pair("confirmations", 0)); @@ -1278,11 +1408,7 @@ Value gettransaction(const Array& params, bool fHelp) { CBlockIndex* pindex = (*mi).second; if (pindex->IsInMainChain()) - { entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); - entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime)); - entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); - } else entry.push_back(Pair("confirmations", 0)); } @@ -1313,17 +1439,53 @@ Value backupwallet(const Array& params, bool fHelp) Value keypoolrefill(const Array& params, bool fHelp) { - if (fHelp || params.size() > 0) + if (fHelp || params.size() > 1) throw runtime_error( - "keypoolrefill\n" - "Fills the keypool." + "keypoolrefill [new-size]\n" + "Fills the keypool.\n" + "IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated one." + HelpRequiringPassphrase()); + unsigned int nSize = max(GetArgUInt("-keypool", 100), 0); + if (params.size() > 0) { + if (params[0].get_int() < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size"); + nSize = (unsigned int) params[0].get_int(); + } + EnsureWalletIsUnlocked(); - pwalletMain->TopUpKeyPool(); + pwalletMain->TopUpKeyPool(nSize); + + if (pwalletMain->GetKeyPoolSize() < nSize) + throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); + + return Value::null; +} + +Value keypoolreset(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "keypoolreset [new-size]\n" + "Resets the keypool.\n" + "IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated one." + + HelpRequiringPassphrase()); + + unsigned int nSize = max(GetArgUInt("-keypool", 100), 0); + if (params.size() > 0) { + if (params[0].get_int() < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size"); + nSize = (unsigned int) params[0].get_int(); + } + + EnsureWalletIsUnlocked(); - if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) + pwalletMain->NewKeyPool(nSize); + + if (pwalletMain->GetKeyPoolSize() < nSize) throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool."); return Value::null; @@ -1333,7 +1495,7 @@ Value keypoolrefill(const Array& params, bool fHelp) void ThreadTopUpKeyPool(void* parg) { // Make this thread recognisable as the key-topping-up thread - RenameThread("bitcoin-key-top"); + RenameThread("novacoin-key-top"); pwalletMain->TopUpKeyPool(); } @@ -1341,9 +1503,9 @@ void ThreadTopUpKeyPool(void* parg) void ThreadCleanWalletPassphrase(void* parg) { // Make this thread recognisable as the wallet relocking thread - RenameThread("bitcoin-lock-wa"); + RenameThread("novacoin-lock-wa"); - int64 nMyWakeTime = GetTimeMillis() + *((int64*)parg) * 1000; + int64_t nMyWakeTime = GetTimeMillis() + *((int64_t*)parg) * 1000; ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); @@ -1351,11 +1513,11 @@ void ThreadCleanWalletPassphrase(void* parg) { nWalletUnlockTime = nMyWakeTime; - do + for ( ; ; ) { if (nWalletUnlockTime==0) break; - int64 nToSleep = nWalletUnlockTime - GetTimeMillis(); + int64_t nToSleep = nWalletUnlockTime - GetTimeMillis(); if (nToSleep <= 0) break; @@ -1363,7 +1525,7 @@ void ThreadCleanWalletPassphrase(void* parg) Sleep(nToSleep); ENTER_CRITICAL_SECTION(cs_nWalletUnlockTime); - } while(1); + }; if (nWalletUnlockTime) { @@ -1379,7 +1541,7 @@ void ThreadCleanWalletPassphrase(void* parg) LEAVE_CRITICAL_SECTION(cs_nWalletUnlockTime); - delete (int64*)parg; + delete (int64_t*)parg; } Value walletpassphrase(const Array& params, bool fHelp) @@ -1414,7 +1576,7 @@ Value walletpassphrase(const Array& params, bool fHelp) "Stores the wallet decryption key in memory for seconds."); NewThread(ThreadTopUpKeyPool, NULL); - int64* pnSleepTime = new int64(params[1].get_int64()); + int64_t* pnSleepTime = new int64_t(params[1].get_int64()); NewThread(ThreadCleanWalletPassphrase, pnSleepTime); // ppcoin: if user OS account compromised prevent trivial sendmoney commands @@ -1517,35 +1679,44 @@ Value encryptwallet(const Array& params, bool fHelp) class DescribeAddressVisitor : public boost::static_visitor { +private: + isminetype mine; public: - Object operator()(const CNoDestination &dest) const { return Object(); } + DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {} + Object operator()(const CNoDestination &dest) const { return Object(); } Object operator()(const CKeyID &keyID) const { Object obj; CPubKey vchPubKey; pwalletMain->GetPubKey(keyID, vchPubKey); obj.push_back(Pair("isscript", false)); - obj.push_back(Pair("pubkey", HexStr(vchPubKey.Raw()))); - obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); + if (mine == MINE_SPENDABLE) { + pwalletMain->GetPubKey(keyID, vchPubKey); + obj.push_back(Pair("pubkey", HexStr(vchPubKey.begin(), vchPubKey.end()))); + obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); + } return obj; } Object operator()(const CScriptID &scriptID) const { Object obj; obj.push_back(Pair("isscript", true)); - CScript subscript; - pwalletMain->GetCScript(scriptID, subscript); - std::vector addresses; - txnouttype whichType; - int nRequired; - ExtractDestinations(subscript, whichType, addresses, nRequired); - obj.push_back(Pair("script", GetTxnOutputType(whichType))); - Array a; - BOOST_FOREACH(const CTxDestination& addr, addresses) - a.push_back(CBitcoinAddress(addr).ToString()); - obj.push_back(Pair("addresses", a)); - if (whichType == TX_MULTISIG) - obj.push_back(Pair("sigsrequired", nRequired)); + if (mine == MINE_SPENDABLE) { + CScript subscript; + pwalletMain->GetCScript(scriptID, subscript); + std::vector addresses; + txnouttype whichType; + int nRequired; + ExtractDestinations(subscript, whichType, addresses, nRequired); + obj.push_back(Pair("script", GetTxnOutputType(whichType))); + obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); + Array a; + BOOST_FOREACH(const CTxDestination& addr, addresses) + a.push_back(CBitcoinAddress(addr).ToString()); + obj.push_back(Pair("addresses", a)); + if (whichType == TX_MULTISIG) + obj.push_back(Pair("sigsrequired", nRequired)); + } return obj; } }; @@ -1564,54 +1735,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)); - bool fMine = IsMine(*pwalletMain, dest); - ret.push_back(Pair("ismine", fMine)); - if (fMine) { - Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); - ret.insert(ret.end(), detail.begin(), detail.end()); - } - if (pwalletMain->mapAddressBook.count(dest)) - ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); - } - return ret; -} - -Value validatepubkey(const Array& params, bool fHelp) -{ - if (fHelp || !params.size() || params.size() > 2) - throw runtime_error( - "validatepubkey \n" - "Return information about ."); - - std::vector vchPubKey = ParseHex(params[0].get_str()); - CPubKey pubKey(vchPubKey); - - bool isValid = pubKey.IsValid(); - bool isCompressed = pubKey.IsCompressed(); - CKeyID keyID = pubKey.GetID(); + if (address.IsPair()) + { + CMalleablePubKey mpk; + mpk.setvch(address.GetData()); + ret.push_back(Pair("ispair", true)); - CBitcoinAddress address; - address.Set(keyID); + CMalleableKeyView view; + bool isMine = pwalletMain->GetMalleableView(mpk, view); + ret.push_back(Pair("ismine", isMine)); - Object ret; - ret.push_back(Pair("isvalid", isValid)); - if (isValid) - { - CTxDestination dest = address.Get(); - string currentAddress = address.ToString(); - ret.push_back(Pair("address", currentAddress)); - bool fMine = IsMine(*pwalletMain, dest); - ret.push_back(Pair("ismine", fMine)); - ret.push_back(Pair("iscompressed", isCompressed)); - if (fMine) { - Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest); - ret.insert(ret.end(), detail.begin(), detail.end()); + if (isMine) + ret.push_back(Pair("KeyView", view.ToString())); + } + else + { + string currentAddress = address.ToString(); + CTxDestination dest = address.Get(); + ret.push_back(Pair("address", currentAddress)); + isminetype mine = pwalletMain ? IsMine(*pwalletMain, address) : 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(address)) + ret.push_back(Pair("account", pwalletMain->mapAddressBook[address])); } - if (pwalletMain->mapAddressBook.count(dest)) - ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest])); } return ret; } @@ -1634,11 +1785,11 @@ Value reservebalance(const Array& params, bool fHelp) { if (params.size() == 1) throw runtime_error("must provide amount to reserve balance.\n"); - int64 nAmount = AmountFromValue(params[1]); + int64_t nAmount = AmountFromValue(params[1]); nAmount = (nAmount / CENT) * CENT; // round to cent if (nAmount < 0) throw runtime_error("amount cannot be negative.\n"); - mapArgs["-reservebalance"] = FormatMoney(nAmount).c_str(); + mapArgs["-reservebalance"] = FormatMoney(nAmount); } else { @@ -1649,7 +1800,6 @@ Value reservebalance(const Array& params, bool fHelp) } Object result; - int64 nReserveBalance = 0; if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) throw runtime_error("invalid reserve balance amount\n"); result.push_back(Pair("reserve", (nReserveBalance > 0))); @@ -1667,7 +1817,7 @@ Value checkwallet(const Array& params, bool fHelp) "Check wallet for integrity.\n"); int nMismatchSpent; - int64 nBalanceInQuestion; + int64_t nBalanceInQuestion; pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion, true); Object result; if (nMismatchSpent == 0) @@ -1690,7 +1840,7 @@ Value repairwallet(const Array& params, bool fHelp) "Repair wallet if checkwallet reports any problem.\n"); int nMismatchSpent; - int64 nBalanceInQuestion; + int64_t nBalanceInQuestion; pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion); Object result; if (nMismatchSpent == 0) @@ -1712,30 +1862,140 @@ Value resendtx(const Array& params, bool fHelp) "Re-send unconfirmed transactions.\n" ); - ResendWalletTransactions(); + ResendWalletTransactions(true); return Value::null; } -// ppcoin: make a public-private key pair +// Make a public-private key pair Value makekeypair(const Array& params, bool fHelp) { - if (fHelp || params.size() > 1) + if (fHelp || params.size() > 0) throw runtime_error( - "makekeypair [prefix]\n" - "Make a public/private key pair.\n" - "[prefix] is optional preferred prefix for the public key.\n"); + "makekeypair\n" + "Make a public/private key pair.\n"); string strPrefix = ""; if (params.size() > 0) strPrefix = params[0].get_str(); - + CKey key; - key.MakeNewKey(false); + key.MakeNewKey(true); CPrivKey vchPrivKey = key.GetPrivKey(); Object result; result.push_back(Pair("PrivateKey", HexStr(vchPrivKey.begin(), vchPrivKey.end()))); - result.push_back(Pair("PublicKey", HexStr(key.GetPubKey().Raw()))); + + bool fCompressed; + CSecret vchSecret = key.GetSecret(fCompressed); + CPubKey vchPubKey = key.GetPubKey(); + result.push_back(Pair("Secret", HexStr(vchSecret.begin(), vchSecret.end()))); + result.push_back(Pair("PublicKey", HexStr(vchPubKey.begin(), vchPubKey.end()))); return result; } + +Value newmalleablekey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "newmalleablekey\n" + "Make a malleable public/private key pair.\n"); + + // Parse the account first so we don't generate a key if there's an error + string strAccount; + if (params.size() > 0) + strAccount = AccountFromValue(params[0]); + + CMalleableKeyView keyView = pwalletMain->GenerateNewMalleableKey(); + + CMalleableKey mKey; + if (!pwalletMain->GetMalleableKey(keyView, mKey)) + throw runtime_error("Unable to generate new malleable key"); + + CMalleablePubKey mPubKey = mKey.GetMalleablePubKey(); + CBitcoinAddress address(mPubKey); + + pwalletMain->SetAddressBookName(address, strAccount); + + Object result; + result.push_back(Pair("PublicPair", mPubKey.ToString())); + result.push_back(Pair("PublicBytes", HexStr(mPubKey.Raw()))); + result.push_back(Pair("Address", address.ToString())); + result.push_back(Pair("KeyView", keyView.ToString())); + + return result; +} + +Value adjustmalleablekey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "adjustmalleablekey \n" + "Calculate new private key using provided malleable key, public key and R data.\n"); + + CMalleableKey malleableKey; + malleableKey.SetString(params[0].get_str()); + + CKey privKeyVariant; + CPubKey vchPubKeyVariant = CPubKey(ParseHex(params[1].get_str())); + + CPubKey R(ParseHex(params[2].get_str())); + + if (!malleableKey.CheckKeyVariant(R,vchPubKeyVariant, privKeyVariant)) { + throw runtime_error("Unable to calculate the private key"); + } + + Object result; + bool fCompressed; + CSecret vchPrivKeyVariant = privKeyVariant.GetSecret(fCompressed); + + result.push_back(Pair("PrivateKey", CBitcoinSecret(vchPrivKeyVariant, fCompressed).ToString())); + + return result; +} + +Value adjustmalleablepubkey(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 2 || params.size() == 0) + throw runtime_error( + "adjustmalleablepubkey \n" + "Calculate new public key using provided malleable public key data.\n"); + + string pubKeyPair = params[0].get_str(); + CMalleablePubKey malleablePubKey; + + if (pubKeyPair.size() == 136) { + malleablePubKey.setvch(ParseHex(pubKeyPair)); + } else + malleablePubKey.SetString(pubKeyPair); + + CPubKey R, vchPubKeyVariant; + malleablePubKey.GetVariant(R, vchPubKeyVariant); + + Object result; + result.push_back(Pair("R", HexStr(R.begin(), R.end()))); + result.push_back(Pair("PubkeyVariant", HexStr(vchPubKeyVariant.begin(), vchPubKeyVariant.end()))); + result.push_back(Pair("KeyVariantID", CBitcoinAddress(vchPubKeyVariant.GetID()).ToString())); + + return result; +} + +Value listmalleableviews(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "listmalleableviews\n" + "Get list of views for generated malleable keys.\n"); + + std::list keyViewList; + pwalletMain->ListMalleableViews(keyViewList); + + Array result; + BOOST_FOREACH(const CMalleableKeyView &keyView, keyViewList) + { + result.push_back(keyView.ToString()); + } + + return result; +} +