// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include <boost/assign/list_of.hpp>
# include "wallet.h"
# include "walletdb.h"
# include "bitcoinrpc.h"
# include "init.h"
# include "base58.h"
using namespace std ;
using namespace boost ;
using namespace boost : : assign ;
using namespace json_spirit ;
int64 nWalletUnlockTime ;
static CCriticalSection cs_nWalletUnlockTime ;
std : : string HelpRequiringPassphrase ( )
{
return pwalletMain & & pwalletMain - > IsCrypted ( )
? " \n requires wallet passphrase to be set with walletpassphrase first "
: " " ;
}
void EnsureWalletIsUnlocked ( )
{
if ( pwalletMain - > IsLocked ( ) )
throw JSONRPCError ( RPC_WALLET_UNLOCK_NEEDED , " Error: Please enter the wallet passphrase with walletpassphrase first. " ) ;
}
void WalletTxToJSON ( const CWalletTx & wtx , Object & entry )
{
int confirms = wtx . GetDepthInMainChain ( ) ;
entry . push_back ( Pair ( " confirmations " , confirms ) ) ;
if ( wtx . IsCoinBase ( ) )
entry . push_back ( Pair ( " generated " , true ) ) ;
if ( confirms )
{
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 ( " txid " , wtx . GetHash ( ) . GetHex ( ) ) ) ;
entry . push_back ( Pair ( " time " , ( boost : : int64_t ) wtx . GetTxTime ( ) ) ) ;
entry . push_back ( Pair ( " timereceived " , ( boost : : int64_t ) wtx . nTimeReceived ) ) ;
BOOST_FOREACH ( const PAIRTYPE ( string , string ) & item , wtx . mapValue )
entry . push_back ( Pair ( item . first , item . second ) ) ;
}
string AccountFromValue ( const Value & value )
{
string strAccount = value . get_str ( ) ;
if ( strAccount = = " * " )
throw JSONRPCError ( RPC_WALLET_INVALID_ACCOUNT_NAME , " Invalid account name " ) ;
return strAccount ;
}
Value getinfo ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 0 )
throw runtime_error (
" getinfo \n "
" Returns an object containing various state info. " ) ;
proxyType proxy ;
GetProxy ( NET_IPV4 , proxy ) ;
Object obj ;
obj . push_back ( Pair ( " version " , FormatFullVersion ( ) ) ) ;
obj . push_back ( Pair ( " protocolversion " , ( int ) PROTOCOL_VERSION ) ) ;
if ( pwalletMain ) {
obj . push_back ( Pair ( " walletversion " , pwalletMain - > GetVersion ( ) ) ) ;
obj . push_back ( Pair ( " balance " , ValueFromAmount ( pwalletMain - > GetBalance ( ) ) ) ) ;
}
obj . push_back ( Pair ( " blocks " , ( int ) nBestHeight ) ) ;
obj . push_back ( Pair ( " moneysupply " , ValueFromAmount ( pindexBest - > nMoneySupply ) ) ) ;
obj . push_back ( Pair ( " timeoffset " , ( boost : : int64_t ) GetTimeOffset ( ) ) ) ;
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 " , GetLocalAddress ( ) . ToStringIP ( ) ) ) ;
obj . push_back ( Pair ( " difficulty " , ( double ) GetDifficulty ( ) ) ) ;
obj . push_back ( Pair ( " testnet " , fTestNet ) ) ;
if ( pwalletMain ) {
obj . push_back ( Pair ( " keypoololdest " , ( boost : : 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 & & pwalletMain - > IsCrypted ( ) )
obj . push_back ( Pair ( " unlocked_until " , ( boost : : int64_t ) nWalletUnlockTime ) ) ;
obj . push_back ( Pair ( " errors " , GetWarnings ( " statusbar " ) ) ) ;
return obj ;
}
Value getnewaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 1 )
throw runtime_error (
" getnewaddress [account] \n "
" Returns a new Gostcoin address for receiving payments. "
" If [account] is specified (recommended), it is added to the address book "
" so payments received with the address will be credited to [account]. " ) ;
// 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 ) ;
return CBitcoinAddress ( keyID ) . ToString ( ) ;
}
CBitcoinAddress GetAccountAddress ( string strAccount , bool bForceNew = false )
{
CWalletDB walletdb ( pwalletMain - > strWalletFile ) ;
CAccount account ;
walletdb . ReadAccount ( strAccount , account ) ;
bool bKeyUsed = false ;
// Check if the current key has been used
if ( account . vchPubKey . IsValid ( ) )
{
CScript scriptPubKey ;
scriptPubKey . SetDestination ( account . vchPubKey . GetID ( ) ) ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ;
it ! = pwalletMain - > mapWallet . end ( ) & & account . vchPubKey . IsValid ( ) ;
+ + it )
{
const CWalletTx & wtx = ( * it ) . second ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout )
if ( txout . scriptPubKey = = scriptPubKey )
bKeyUsed = true ;
}
}
// Generate a new key
if ( ! account . vchPubKey . IsValid ( ) | | bForceNew | | bKeyUsed )
{
if ( ! pwalletMain - > GetKeyFromPool ( account . vchPubKey , false ) )
throw JSONRPCError ( RPC_WALLET_KEYPOOL_RAN_OUT , " Error: Keypool ran out, please call keypoolrefill first " ) ;
pwalletMain - > SetAddressBookName ( account . vchPubKey . GetID ( ) , strAccount ) ;
walletdb . WriteAccount ( strAccount , account ) ;
}
return CBitcoinAddress ( account . vchPubKey . GetID ( ) ) ;
}
Value getaccountaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaccountaddress <account> \n "
" Returns the current Gostcoin address for receiving payments to this account. " ) ;
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue ( params [ 0 ] ) ;
Value ret ;
ret = GetAccountAddress ( strAccount ) . ToString ( ) ;
return ret ;
}
Value setaccount ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 2 )
throw runtime_error (
" setaccount <gostcoinaddress> <account> \n "
" Sets the account associated with the given address. " ) ;
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
if ( ! address . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Gostcoin address " ) ;
string strAccount ;
if ( params . size ( ) > 1 )
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 ( ) ) )
{
string strOldAccount = pwalletMain - > mapAddressBook [ address . Get ( ) ] ;
if ( address = = GetAccountAddress ( strOldAccount ) )
GetAccountAddress ( strOldAccount , true ) ;
}
pwalletMain - > SetAddressBookName ( address . Get ( ) , strAccount ) ;
return Value : : null ;
}
Value getaccount ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaccount <gostcoinaddress> \n "
" Returns the account associated with the given address. " ) ;
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
if ( ! address . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Gostcoin address " ) ;
string strAccount ;
map < CTxDestination , string > : : iterator mi = pwalletMain - > mapAddressBook . find ( address . Get ( ) ) ;
if ( mi ! = pwalletMain - > mapAddressBook . end ( ) & & ! ( * mi ) . second . empty ( ) )
strAccount = ( * mi ) . second ;
return strAccount ;
}
Value getaddressesbyaccount ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" getaddressesbyaccount <account> \n "
" Returns the list of addresses for the given account. " ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
// Find all addresses that have the given account
Array ret ;
BOOST_FOREACH ( const PAIRTYPE ( CBitcoinAddress , string ) & item , pwalletMain - > mapAddressBook )
{
const CBitcoinAddress & address = item . first ;
const string & strName = item . second ;
if ( strName = = strAccount )
ret . push_back ( address . ToString ( ) ) ;
}
return ret ;
}
Value setmininput ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 1 )
throw runtime_error (
" setmininput <amount> \n "
" <amount> is a real and is rounded to the nearest 0.00000001 " ) ;
// Amount
int64 nAmount = 0 ;
if ( params [ 0 ] . get_real ( ) ! = 0.0 )
nAmount = AmountFromValue ( params [ 0 ] ) ; // rejects 0.0 amounts
nMinimumInputValue = nAmount ;
return true ;
}
Value sendtoaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 2 | | params . size ( ) > 4 )
throw runtime_error (
" sendtoaddress <gostcoinaddress> <amount> [comment] [comment-to] \n "
" <amount> is a real and is rounded to the nearest 0.00000001 "
+ HelpRequiringPassphrase ( ) ) ;
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
if ( ! address . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Gostcoin address " ) ;
// Amount
int64 nAmount = AmountFromValue ( params [ 1 ] ) ;
// Wallet comments
CWalletTx wtx ;
if ( params . size ( ) > 2 & & params [ 2 ] . type ( ) ! = null_type & & ! params [ 2 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " comment " ] = params [ 2 ] . get_str ( ) ;
if ( params . size ( ) > 3 & & params [ 3 ] . type ( ) ! = null_type & & ! params [ 3 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " to " ] = params [ 3 ] . get_str ( ) ;
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 ! = " " )
throw JSONRPCError ( RPC_WALLET_ERROR , strError ) ;
return wtx . GetHash ( ) . GetHex ( ) ;
}
Value listaddressgroupings ( const Array & params , bool fHelp )
{
if ( fHelp )
throw runtime_error (
" listaddressgroupings \n "
" Lists groups of addresses which have had their common ownership \n "
" made public by common use as inputs or as the resulting change \n "
" in past transactions " ) ;
Array jsonGroupings ;
map < CTxDestination , int64 > balances = pwalletMain - > GetAddressBalances ( ) ;
BOOST_FOREACH ( set < CTxDestination > grouping , pwalletMain - > GetAddressGroupings ( ) )
{
Array jsonGrouping ;
BOOST_FOREACH ( CTxDestination address , grouping )
{
Array addressInfo ;
addressInfo . push_back ( CBitcoinAddress ( 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 ) ;
}
jsonGrouping . push_back ( addressInfo ) ;
}
jsonGroupings . push_back ( jsonGrouping ) ;
}
return jsonGroupings ;
}
Value signmessage ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 2 )
throw runtime_error (
" signmessage <gostcoinaddress> <message> \n "
" Sign a message with the private key of an address " ) ;
EnsureWalletIsUnlocked ( ) ;
string strAddress = params [ 0 ] . get_str ( ) ;
string strMessage = params [ 1 ] . get_str ( ) ;
CBitcoinAddress addr ( strAddress ) ;
if ( ! addr . IsValid ( ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Invalid address " ) ;
CKeyID keyID ;
if ( ! addr . GetKeyID ( keyID ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Address does not refer to key " ) ;
CKey key ;
if ( ! pwalletMain - > GetKey ( keyID , key ) )
throw JSONRPCError ( RPC_WALLET_ERROR , " Private key not available " ) ;
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
vector < unsigned char > vchSig ;
if ( ! key . SignCompact ( ss . GetHash ( ) , vchSig ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Sign failed " ) ;
return EncodeBase64 ( & vchSig [ 0 ] , vchSig . size ( ) ) ;
}
Value verifymessage ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 3 )
throw runtime_error (
" verifymessage <gostcoinaddress> <signature> <message> \n "
" Verify a signed message " ) ;
string strAddress = params [ 0 ] . get_str ( ) ;
string strSign = params [ 1 ] . get_str ( ) ;
string strMessage = params [ 2 ] . get_str ( ) ;
CBitcoinAddress addr ( strAddress ) ;
if ( ! addr . IsValid ( ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Invalid address " ) ;
CKeyID keyID ;
if ( ! addr . GetKeyID ( keyID ) )
throw JSONRPCError ( RPC_TYPE_ERROR , " Address does not refer to key " ) ;
bool fInvalid = false ;
vector < unsigned char > vchSig = DecodeBase64 ( strSign . c_str ( ) , & fInvalid ) ;
if ( fInvalid )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Malformed base64 encoding " ) ;
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
CPubKey pubkey ;
if ( ! pubkey . RecoverCompact ( ss . GetHash ( ) , vchSig ) )
return false ;
return ( pubkey . GetID ( ) = = keyID ) ;
}
Value getreceivedbyaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 2 )
throw runtime_error (
" getreceivedbyaddress <gostcoinaddress> [minconf=1] \n "
" Returns the total amount received by <gostcoinaddress> 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 Gostcoin address " ) ;
scriptPubKey . SetDestination ( address . Get ( ) ) ;
if ( ! IsMine ( * pwalletMain , scriptPubKey ) )
return ( double ) 0.0 ;
// Minimum confirmations
int nMinDepth = 1 ;
if ( params . size ( ) > 1 )
nMinDepth = params [ 1 ] . get_int ( ) ;
// Tally
int64 nAmount = 0 ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( wtx . IsCoinBase ( ) | | ! wtx . IsFinal ( ) )
continue ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout )
if ( txout . scriptPubKey = = scriptPubKey )
if ( wtx . GetDepthInMainChain ( ) > = nMinDepth )
nAmount + = txout . nValue ;
}
return ValueFromAmount ( nAmount ) ;
}
void GetAccountAddresses ( string strAccount , set < CTxDestination > & setAddress )
{
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , string ) & item , pwalletMain - > mapAddressBook )
{
const CTxDestination & address = item . first ;
const string & strName = item . second ;
if ( strName = = strAccount )
setAddress . insert ( address ) ;
}
}
Value getreceivedbyaccount ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 2 )
throw runtime_error (
" getreceivedbyaccount <account> [minconf=1] \n "
" Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations. " ) ;
// Minimum confirmations
int nMinDepth = 1 ;
if ( params . size ( ) > 1 )
nMinDepth = params [ 1 ] . get_int ( ) ;
// Get the set of pub keys assigned to account
string strAccount = AccountFromValue ( params [ 0 ] ) ;
set < CTxDestination > setAddress ;
GetAccountAddresses ( strAccount , setAddress ) ;
// Tally
int64 nAmount = 0 ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( wtx . IsCoinBase ( ) | | ! wtx . IsFinal ( ) )
continue ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout )
{
CTxDestination address ;
if ( ExtractDestination ( txout . scriptPubKey , address ) & & IsMine ( * pwalletMain , address ) & & setAddress . count ( address ) )
if ( wtx . GetDepthInMainChain ( ) > = nMinDepth )
nAmount + = txout . nValue ;
}
}
return ( double ) nAmount / ( double ) COIN ;
}
int64 GetAccountBalance ( CWalletDB & walletdb , const string & strAccount , int nMinDepth )
{
int64 nBalance = 0 ;
// Tally wallet transactions
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( ! wtx . IsFinal ( ) )
continue ;
int64 nReceived , nSent , nFee ;
wtx . GetAccountAmounts ( strAccount , nReceived , nSent , nFee ) ;
if ( nReceived ! = 0 & & wtx . GetDepthInMainChain ( ) > = nMinDepth )
nBalance + = nReceived ;
nBalance - = nSent + nFee ;
}
// Tally internal accounting entries
nBalance + = walletdb . GetAccountCreditDebit ( strAccount ) ;
return nBalance ;
}
int64 GetAccountBalance ( const string & strAccount , int nMinDepth )
{
CWalletDB walletdb ( pwalletMain - > strWalletFile ) ;
return GetAccountBalance ( walletdb , strAccount , nMinDepth ) ;
}
Value getbalance ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 2 )
throw runtime_error (
" getbalance [account] [minconf=1] \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 ( params . size ( ) = = 0 )
return ValueFromAmount ( pwalletMain - > GetBalance ( ) ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 1 )
nMinDepth = params [ 1 ] . get_int ( ) ;
if ( params [ 0 ] . get_str ( ) = = " * " ) {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
// getbalance and getbalance '*' 0 should return the same number
int64 nBalance = 0 ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( ! wtx . IsConfirmed ( ) )
continue ;
int64 allFee ;
string strSentAccount ;
list < pair < CTxDestination , int64 > > listReceived ;
list < pair < CTxDestination , int64 > > listSent ;
wtx . GetAmounts ( listReceived , listSent , allFee , strSentAccount ) ;
if ( wtx . GetDepthInMainChain ( ) > = nMinDepth )
{
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & r , listReceived )
nBalance + = r . second ;
}
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & r , listSent )
nBalance - = r . second ;
nBalance - = allFee ;
}
return ValueFromAmount ( nBalance ) ;
}
string strAccount = AccountFromValue ( params [ 0 ] ) ;
int64 nBalance = GetAccountBalance ( strAccount , nMinDepth ) ;
return ValueFromAmount ( nBalance ) ;
}
Value movecmd ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 3 | | params . size ( ) > 5 )
throw runtime_error (
" move <fromaccount> <toaccount> <amount> [minconf=1] [comment] \n "
" Move from one account in your wallet to another. " ) ;
string strFrom = AccountFromValue ( params [ 0 ] ) ;
string strTo = AccountFromValue ( params [ 1 ] ) ;
int64 nAmount = AmountFromValue ( params [ 2 ] ) ;
if ( params . size ( ) > 3 )
// unused parameter, used to be nMinDepth, keep type-checking it though
( void ) params [ 3 ] . get_int ( ) ;
string strComment ;
if ( params . size ( ) > 4 )
strComment = params [ 4 ] . get_str ( ) ;
CWalletDB walletdb ( pwalletMain - > strWalletFile ) ;
if ( ! walletdb . TxnBegin ( ) )
throw JSONRPCError ( RPC_DATABASE_ERROR , " database error " ) ;
int64 nNow = GetAdjustedTime ( ) ;
// Debit
CAccountingEntry debit ;
debit . nOrderPos = pwalletMain - > IncOrderPosNext ( & walletdb ) ;
debit . strAccount = strFrom ;
debit . nCreditDebit = - nAmount ;
debit . nTime = nNow ;
debit . strOtherAccount = strTo ;
debit . strComment = strComment ;
walletdb . WriteAccountingEntry ( debit ) ;
// Credit
CAccountingEntry credit ;
credit . nOrderPos = pwalletMain - > IncOrderPosNext ( & walletdb ) ;
credit . strAccount = strTo ;
credit . nCreditDebit = nAmount ;
credit . nTime = nNow ;
credit . strOtherAccount = strFrom ;
credit . strComment = strComment ;
walletdb . WriteAccountingEntry ( credit ) ;
if ( ! walletdb . TxnCommit ( ) )
throw JSONRPCError ( RPC_DATABASE_ERROR , " database error " ) ;
return true ;
}
Value sendfrom ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 3 | | params . size ( ) > 6 )
throw runtime_error (
" sendfrom <fromaccount> <togostcoinaddress> <amount> [minconf=1] [comment] [comment-to] \n "
" <amount> is a real and is rounded to the nearest 0.00000001 "
+ HelpRequiringPassphrase ( ) ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
CBitcoinAddress address ( params [ 1 ] . get_str ( ) ) ;
if ( ! address . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Gostcoin address " ) ;
int64 nAmount = AmountFromValue ( params [ 2 ] ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 3 )
nMinDepth = params [ 3 ] . get_int ( ) ;
CWalletTx wtx ;
wtx . strFromAccount = strAccount ;
if ( params . size ( ) > 4 & & params [ 4 ] . type ( ) ! = null_type & & ! params [ 4 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " comment " ] = params [ 4 ] . get_str ( ) ;
if ( params . size ( ) > 5 & & params [ 5 ] . type ( ) ! = null_type & & ! params [ 5 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " to " ] = params [ 5 ] . get_str ( ) ;
EnsureWalletIsUnlocked ( ) ;
// Check funds
int64 nBalance = GetAccountBalance ( strAccount , nMinDepth ) ;
if ( nAmount > nBalance )
throw JSONRPCError ( RPC_WALLET_INSUFFICIENT_FUNDS , " Account has insufficient funds " ) ;
// Send
string strError = pwalletMain - > SendMoneyToDestination ( address . Get ( ) , nAmount , wtx ) ;
if ( strError ! = " " )
throw JSONRPCError ( RPC_WALLET_ERROR , strError ) ;
return wtx . GetHash ( ) . GetHex ( ) ;
}
Value sendmany ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 2 | | params . size ( ) > 4 )
throw runtime_error (
" sendmany <fromaccount> {address:amount,...} [minconf=1] [comment] \n "
" amounts are double-precision floating point numbers "
+ HelpRequiringPassphrase ( ) ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
Object sendTo = params [ 1 ] . get_obj ( ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 2 )
nMinDepth = params [ 2 ] . get_int ( ) ;
CWalletTx wtx ;
wtx . strFromAccount = strAccount ;
if ( params . size ( ) > 3 & & params [ 3 ] . type ( ) ! = null_type & & ! params [ 3 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " comment " ] = params [ 3 ] . get_str ( ) ;
set < CBitcoinAddress > setAddress ;
vector < pair < CScript , int64 > > vecSend ;
int64 totalAmount = 0 ;
BOOST_FOREACH ( const Pair & s , sendTo )
{
CBitcoinAddress address ( s . name_ ) ;
if ( ! address . IsValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , string ( " Invalid Gostcoin address: " ) + s . name_ ) ;
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_ ) ;
totalAmount + = nAmount ;
vecSend . push_back ( make_pair ( scriptPubKey , nAmount ) ) ;
}
EnsureWalletIsUnlocked ( ) ;
// Check funds
int64 nBalance = GetAccountBalance ( strAccount , nMinDepth ) ;
if ( totalAmount > nBalance )
throw JSONRPCError ( RPC_WALLET_INSUFFICIENT_FUNDS , " Account has insufficient funds " ) ;
// Send
CReserveKey keyChange ( pwalletMain ) ;
int64 nFeeRequired = 0 ;
string strFailReason ;
bool fCreated = pwalletMain - > CreateTransaction ( vecSend , wtx , keyChange , nFeeRequired , strFailReason ) ;
if ( ! fCreated )
throw JSONRPCError ( RPC_WALLET_INSUFFICIENT_FUNDS , strFailReason ) ;
if ( ! pwalletMain - > CommitTransaction ( wtx , keyChange ) )
throw JSONRPCError ( RPC_WALLET_ERROR , " Transaction commit failed " ) ;
return wtx . GetHash ( ) . GetHex ( ) ;
}
//
// Used by addmultisigaddress / createmultisig:
//
static CScript _createmultisig ( const Array & params )
{
int nRequired = params [ 0 ] . get_int ( ) ;
const Array & keys = params [ 1 ] . get_array ( ) ;
// Gather public keys
if ( nRequired < 1 )
throw runtime_error ( " a multisignature address must require at least one key to redeem " ) ;
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 < CPubKey > pubkeys ;
pubkeys . resize ( keys . size ( ) ) ;
for ( unsigned int i = 0 ; i < keys . size ( ) ; i + + )
{
const std : : string & ks = keys [ i ] . get_str ( ) ;
// Case 1: Litecoin 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 . c_str ( ) ) ) ;
CPubKey vchPubKey ;
if ( ! pwalletMain - > GetPubKey ( keyID , vchPubKey ) )
throw runtime_error (
strprintf ( " no full public key for address %s " , ks . c_str ( ) ) ) ;
if ( ! vchPubKey . IsFullyValid ( ) )
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 . IsFullyValid ( ) )
throw runtime_error ( " Invalid public key: " + ks ) ;
pubkeys [ i ] = vchPubKey ;
}
else
{
throw runtime_error ( " Invalid public key: " + ks ) ;
}
}
CScript result ;
result . SetMultisig ( nRequired , pubkeys ) ;
return result ;
}
Value addmultisigaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 2 | | params . size ( ) > 3 )
{
string msg = " addmultisigaddress <nrequired> <'[ \" key \" , \" key \" ]'> [account] \n "
" Add a nrequired-to-sign multisignature address to the wallet \" \n "
" each key is a Gostcoin address or hex-encoded public key \n "
" If [account] is specified, assign address to [account]. " ;
throw runtime_error ( msg ) ;
}
string strAccount ;
if ( params . size ( ) > 2 )
strAccount = AccountFromValue ( params [ 2 ] ) ;
// Construct using pay-to-script-hash:
CScript inner = _createmultisig ( params ) ;
CScriptID innerID = inner . GetID ( ) ;
pwalletMain - > AddCScript ( inner ) ;
pwalletMain - > SetAddressBookName ( innerID , strAccount ) ;
return CBitcoinAddress ( innerID ) . ToString ( ) ;
}
Value createmultisig ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 2 | | params . size ( ) > 2 )
{
string msg = " createmultisig <nrequired> <'[ \" key \" , \" key \" ]'> \n "
" Creates a multi-signature address and returns a json object \n "
" with keys: \n "
" address : gostcoin address \n "
" redeemScript : hex-encoded redemption script " ;
throw runtime_error ( msg ) ;
}
// Construct using pay-to-script-hash:
CScript inner = _createmultisig ( params ) ;
CScriptID innerID = inner . GetID ( ) ;
CBitcoinAddress address ( innerID ) ;
Object result ;
result . push_back ( Pair ( " address " , address . ToString ( ) ) ) ;
result . push_back ( Pair ( " redeemScript " , HexStr ( inner . begin ( ) , inner . end ( ) ) ) ) ;
return result ;
}
struct tallyitem
{
int64 nAmount ;
int nConf ;
vector < uint256 > txids ;
tallyitem ( )
{
nAmount = 0 ;
nConf = std : : numeric_limits < int > : : max ( ) ;
}
} ;
Value ListReceived ( const Array & params , bool fByAccounts )
{
// Minimum confirmations
int nMinDepth = 1 ;
if ( params . size ( ) > 0 )
nMinDepth = params [ 0 ] . get_int ( ) ;
// Whether to include empty accounts
bool fIncludeEmpty = false ;
if ( params . size ( ) > 1 )
fIncludeEmpty = params [ 1 ] . get_bool ( ) ;
// Tally
map < CBitcoinAddress , tallyitem > mapTally ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( wtx . IsCoinBase ( ) | | ! wtx . IsFinal ( ) )
continue ;
int nDepth = wtx . GetDepthInMainChain ( ) ;
if ( nDepth < nMinDepth )
continue ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout )
{
CTxDestination address ;
if ( ! ExtractDestination ( txout . scriptPubKey , address ) | | ! IsMine ( * pwalletMain , address ) )
continue ;
tallyitem & item = mapTally [ address ] ;
item . nAmount + = txout . nValue ;
item . nConf = min ( item . nConf , nDepth ) ;
item . txids . push_back ( wtx . GetHash ( ) ) ;
}
}
// Reply
Array ret ;
map < string , tallyitem > mapAccountTally ;
BOOST_FOREACH ( const PAIRTYPE ( CBitcoinAddress , string ) & item , pwalletMain - > mapAddressBook )
{
const CBitcoinAddress & address = item . first ;
const string & strAccount = item . second ;
map < CBitcoinAddress , tallyitem > : : iterator it = mapTally . find ( address ) ;
if ( it = = mapTally . end ( ) & & ! fIncludeEmpty )
continue ;
int64 nAmount = 0 ;
int nConf = std : : numeric_limits < int > : : max ( ) ;
if ( it ! = mapTally . end ( ) )
{
nAmount = ( * it ) . second . nAmount ;
nConf = ( * it ) . second . nConf ;
}
if ( fByAccounts )
{
tallyitem & item = mapAccountTally [ strAccount ] ;
item . nAmount + = nAmount ;
item . nConf = min ( item . nConf , nConf ) ;
}
else
{
Object obj ;
obj . push_back ( Pair ( " address " , address . ToString ( ) ) ) ;
obj . push_back ( Pair ( " account " , strAccount ) ) ;
obj . push_back ( Pair ( " amount " , ValueFromAmount ( nAmount ) ) ) ;
obj . push_back ( Pair ( " confirmations " , ( nConf = = std : : numeric_limits < int > : : max ( ) ? 0 : nConf ) ) ) ;
Array transactions ;
if ( it ! = mapTally . end ( ) )
{
BOOST_FOREACH ( const uint256 & item , ( * it ) . second . txids )
{
transactions . push_back ( item . GetHex ( ) ) ;
}
}
obj . push_back ( Pair ( " txids " , transactions ) ) ;
ret . push_back ( obj ) ;
}
}
if ( fByAccounts )
{
for ( map < string , tallyitem > : : iterator it = mapAccountTally . begin ( ) ; it ! = mapAccountTally . end ( ) ; + + it )
{
int64 nAmount = ( * it ) . second . nAmount ;
int nConf = ( * it ) . second . nConf ;
Object obj ;
obj . push_back ( Pair ( " account " , ( * it ) . first ) ) ;
obj . push_back ( Pair ( " amount " , ValueFromAmount ( nAmount ) ) ) ;
obj . push_back ( Pair ( " confirmations " , ( nConf = = std : : numeric_limits < int > : : max ( ) ? 0 : nConf ) ) ) ;
ret . push_back ( obj ) ;
}
}
return ret ;
}
Value listreceivedbyaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 2 )
throw runtime_error (
" listreceivedbyaddress [minconf=1] [includeempty=false] \n "
" [minconf] is the minimum number of confirmations before payments are included. \n "
" [includeempty] whether to include addresses that haven't received any payments. \n "
" Returns an array of objects containing: \n "
" \" address \" : receiving address \n "
" \" account \" : the account of the receiving address \n "
" \" amount \" : total amount received by the address \n "
" \" confirmations \" : number of confirmations of the most recent transaction included \n "
" \" txids \" : list of transactions with outputs to the address \n " ) ;
return ListReceived ( params , false ) ;
}
Value listreceivedbyaccount ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 2 )
throw runtime_error (
" listreceivedbyaccount [minconf=1] [includeempty=false] \n "
" [minconf] is the minimum number of confirmations before payments are included. \n "
" [includeempty] whether to include accounts that haven't received any payments. \n "
" Returns an array of objects containing: \n "
" \" account \" : the account of the receiving addresses \n "
" \" amount \" : total amount received by addresses with this account \n "
" \" confirmations \" : number of confirmations of the most recent transaction included " ) ;
return ListReceived ( params , true ) ;
}
void ListTransactions ( const CWalletTx & wtx , const string & strAccount , int nMinDepth , bool fLong , Array & ret )
{
int64 nFee ;
string strSentAccount ;
list < pair < CTxDestination , int64 > > listReceived ;
list < pair < CTxDestination , int64 > > listSent ;
wtx . GetAmounts ( listReceived , listSent , nFee , strSentAccount ) ;
bool fAllAccounts = ( strAccount = = string ( " * " ) ) ;
// Sent
if ( ( ! listSent . empty ( ) | | nFee ! = 0 ) & & ( fAllAccounts | | strAccount = = strSentAccount ) )
{
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & 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 " ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( - s . second ) ) ) ;
entry . push_back ( Pair ( " fee " , ValueFromAmount ( - nFee ) ) ) ;
if ( fLong )
WalletTxToJSON ( wtx , entry ) ;
ret . push_back ( entry ) ;
}
}
// Received
if ( listReceived . size ( ) > 0 & & wtx . GetDepthInMainChain ( ) > = nMinDepth )
{
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & r , listReceived )
{
string account ;
if ( pwalletMain - > mapAddressBook . count ( r . first ) )
account = pwalletMain - > mapAddressBook [ r . first ] ;
if ( fAllAccounts | | ( account = = strAccount ) )
{
Object entry ;
entry . push_back ( Pair ( " account " , account ) ) ;
entry . push_back ( Pair ( " address " , CBitcoinAddress ( r . first ) . ToString ( ) ) ) ;
if ( wtx . IsCoinBase ( ) )
{
if ( wtx . GetDepthInMainChain ( ) < 1 )
entry . push_back ( Pair ( " category " , " orphan " ) ) ;
else if ( wtx . GetBlocksToMaturity ( ) > 0 )
entry . push_back ( Pair ( " category " , " immature " ) ) ;
else
entry . push_back ( Pair ( " category " , " generate " ) ) ;
}
else
entry . push_back ( Pair ( " category " , " receive " ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( r . second ) ) ) ;
if ( fLong )
WalletTxToJSON ( wtx , entry ) ;
ret . push_back ( entry ) ;
}
}
}
}
void AcentryToJSON ( const CAccountingEntry & acentry , const string & strAccount , Array & ret )
{
bool fAllAccounts = ( strAccount = = string ( " * " ) ) ;
if ( fAllAccounts | | acentry . strAccount = = strAccount )
{
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 ( " amount " , ValueFromAmount ( acentry . nCreditDebit ) ) ) ;
entry . push_back ( Pair ( " otheraccount " , acentry . strOtherAccount ) ) ;
entry . push_back ( Pair ( " comment " , acentry . strComment ) ) ;
ret . push_back ( entry ) ;
}
}
Value listtransactions ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 3 )
throw runtime_error (
" listtransactions [account] [count=10] [from=0] \n "
" Returns up to [count] most recent transactions skipping the first [from] transactions for account [account]. " ) ;
string strAccount = " * " ;
if ( params . size ( ) > 0 )
strAccount = params [ 0 ] . get_str ( ) ;
int nCount = 10 ;
if ( params . size ( ) > 1 )
nCount = params [ 1 ] . get_int ( ) ;
int nFrom = 0 ;
if ( params . size ( ) > 2 )
nFrom = params [ 2 ] . get_int ( ) ;
if ( nCount < 0 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Negative count " ) ;
if ( nFrom < 0 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Negative from " ) ;
Array ret ;
std : : list < CAccountingEntry > acentries ;
CWallet : : TxItems txOrdered = pwalletMain - > OrderedTxItems ( acentries , strAccount ) ;
// iterate backwards until we have nCount items to return:
for ( CWallet : : TxItems : : reverse_iterator it = txOrdered . rbegin ( ) ; it ! = txOrdered . rend ( ) ; + + it )
{
CWalletTx * const pwtx = ( * it ) . second . first ;
if ( pwtx ! = 0 )
ListTransactions ( * pwtx , strAccount , 0 , true , ret ) ;
CAccountingEntry * const pacentry = ( * it ) . second . second ;
if ( pacentry ! = 0 )
AcentryToJSON ( * pacentry , strAccount , ret ) ;
if ( ( int ) ret . size ( ) > = ( nCount + nFrom ) ) break ;
}
// ret is newest to oldest
if ( nFrom > ( int ) ret . size ( ) )
nFrom = ret . size ( ) ;
if ( ( nFrom + nCount ) > ( int ) ret . size ( ) )
nCount = ret . size ( ) - nFrom ;
Array : : iterator first = ret . begin ( ) ;
std : : advance ( first , nFrom ) ;
Array : : iterator last = ret . begin ( ) ;
std : : advance ( last , nFrom + nCount ) ;
if ( last ! = ret . end ( ) ) ret . erase ( last , ret . end ( ) ) ;
if ( first ! = ret . begin ( ) ) ret . erase ( ret . begin ( ) , first ) ;
std : : reverse ( ret . begin ( ) , ret . end ( ) ) ; // Return oldest to newest
return ret ;
}
Value listaccounts ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 1 )
throw runtime_error (
" listaccounts [minconf=1] \n "
" Returns Object that has account names as keys, account balances as values. " ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 0 )
nMinDepth = params [ 0 ] . get_int ( ) ;
map < string , int64 > mapAccountBalances ;
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , string ) & entry , pwalletMain - > mapAddressBook ) {
if ( IsMine ( * pwalletMain , entry . first ) ) // This address belongs to me
mapAccountBalances [ entry . second ] = 0 ;
}
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
int64 nFee ;
string strSentAccount ;
list < pair < CTxDestination , int64 > > listReceived ;
list < pair < CTxDestination , int64 > > listSent ;
wtx . GetAmounts ( listReceived , listSent , nFee , strSentAccount ) ;
mapAccountBalances [ strSentAccount ] - = nFee ;
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & s , listSent )
mapAccountBalances [ strSentAccount ] - = s . second ;
if ( wtx . GetDepthInMainChain ( ) > = nMinDepth )
{
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64 ) & r , listReceived )
if ( pwalletMain - > mapAddressBook . count ( r . first ) )
mapAccountBalances [ pwalletMain - > mapAddressBook [ r . first ] ] + = r . second ;
else
mapAccountBalances [ " " ] + = r . second ;
}
}
list < CAccountingEntry > acentries ;
CWalletDB ( pwalletMain - > strWalletFile ) . ListAccountCreditDebit ( " * " , acentries ) ;
BOOST_FOREACH ( const CAccountingEntry & entry , acentries )
mapAccountBalances [ entry . strAccount ] + = entry . nCreditDebit ;
Object ret ;
BOOST_FOREACH ( const PAIRTYPE ( string , int64 ) & accountBalance , mapAccountBalances ) {
ret . push_back ( Pair ( accountBalance . first , ValueFromAmount ( accountBalance . second ) ) ) ;
}
return ret ;
}
Value listsinceblock ( const Array & params , bool fHelp )
{
if ( fHelp )
throw runtime_error (
" listsinceblock [blockhash] [target-confirmations] \n "
" Get all transactions in blocks since block [blockhash], or all transactions if omitted " ) ;
CBlockIndex * pindex = NULL ;
int target_confirms = 1 ;
if ( params . size ( ) > 0 )
{
uint256 blockId = 0 ;
blockId . SetHex ( params [ 0 ] . get_str ( ) ) ;
pindex = CBlockLocator ( blockId ) . GetBlockIndex ( ) ;
}
if ( params . size ( ) > 1 )
{
target_confirms = params [ 1 ] . get_int ( ) ;
if ( target_confirms < 1 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid parameter " ) ;
}
int depth = pindex ? ( 1 + nBestHeight - pindex - > nHeight ) : - 1 ;
Array transactions ;
for ( map < uint256 , CWalletTx > : : iterator it = pwalletMain - > mapWallet . begin ( ) ; it ! = pwalletMain - > mapWallet . end ( ) ; it + + )
{
CWalletTx tx = ( * it ) . second ;
if ( depth = = - 1 | | tx . GetDepthInMainChain ( ) < depth )
ListTransactions ( tx , " * " , 0 , true , transactions ) ;
}
uint256 lastblock ;
if ( target_confirms = = 1 )
{
lastblock = hashBestChain ;
}
else
{
int target_height = pindexBest - > nHeight + 1 - target_confirms ;
CBlockIndex * block ;
for ( block = pindexBest ;
block & & block - > nHeight > target_height ;
block = block - > pprev ) { }
lastblock = block ? block - > GetBlockHash ( ) : 0 ;
}
Object ret ;
ret . push_back ( Pair ( " transactions " , transactions ) ) ;
ret . push_back ( Pair ( " lastblock " , lastblock . GetHex ( ) ) ) ;
return ret ;
}
Value gettransaction ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" gettransaction <txid> \n "
" Get detailed information about in-wallet transaction <txid> " ) ;
uint256 hash ;
hash . SetHex ( params [ 0 ] . get_str ( ) ) ;
Object entry ;
if ( ! pwalletMain - > mapWallet . count ( hash ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid or non-wallet transaction id " ) ;
const CWalletTx & wtx = pwalletMain - > mapWallet [ hash ] ;
int64 nCredit = wtx . GetCredit ( ) ;
int64 nDebit = wtx . GetDebit ( ) ;
int64 nNet = nCredit - nDebit ;
int64 nFee = ( wtx . IsFromMe ( ) ? wtx . GetValueOut ( ) - nDebit : 0 ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( nNet - nFee ) ) ) ;
if ( wtx . IsFromMe ( ) )
entry . push_back ( Pair ( " fee " , ValueFromAmount ( nFee ) ) ) ;
WalletTxToJSON ( wtx , entry ) ;
Array details ;
ListTransactions ( wtx , " * " , 0 , false , details ) ;
entry . push_back ( Pair ( " details " , details ) ) ;
return entry ;
}
Value backupwallet ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" backupwallet <destination> \n "
" Safely copies wallet.dat to destination, which can be a directory or a path with filename. " ) ;
string strDest = params [ 0 ] . get_str ( ) ;
if ( ! BackupWallet ( * pwalletMain , strDest ) )
throw JSONRPCError ( RPC_WALLET_ERROR , " Error: Wallet backup failed! " ) ;
return Value : : null ;
}
Value keypoolrefill ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 0 )
throw runtime_error (
" keypoolrefill \n "
" Fills the keypool. "
+ HelpRequiringPassphrase ( ) ) ;
EnsureWalletIsUnlocked ( ) ;
pwalletMain - > TopUpKeyPool ( ) ;
if ( pwalletMain - > GetKeyPoolSize ( ) < GetArg ( " -keypool " , 100 ) )
throw JSONRPCError ( RPC_WALLET_ERROR , " Error refreshing keypool. " ) ;
return Value : : null ;
}
void ThreadTopUpKeyPool ( void * parg )
{
// Make this thread recognisable as the key-topping-up thread
RenameThread ( " bitcoin-key-top " ) ;
pwalletMain - > TopUpKeyPool ( ) ;
}
void ThreadCleanWalletPassphrase ( void * parg )
{
// Make this thread recognisable as the wallet relocking thread
RenameThread ( " bitcoin-lock-wa " ) ;
int64 nMyWakeTime = GetTimeMillis ( ) + * ( ( int64 * ) parg ) * 1000 ;
ENTER_CRITICAL_SECTION ( cs_nWalletUnlockTime ) ;
if ( nWalletUnlockTime = = 0 )
{
nWalletUnlockTime = nMyWakeTime ;
do
{
if ( nWalletUnlockTime = = 0 )
break ;
int64 nToSleep = nWalletUnlockTime - GetTimeMillis ( ) ;
if ( nToSleep < = 0 )
break ;
LEAVE_CRITICAL_SECTION ( cs_nWalletUnlockTime ) ;
MilliSleep ( nToSleep ) ;
ENTER_CRITICAL_SECTION ( cs_nWalletUnlockTime ) ;
} while ( 1 ) ;
if ( nWalletUnlockTime )
{
nWalletUnlockTime = 0 ;
pwalletMain - > Lock ( ) ;
}
}
else
{
if ( nWalletUnlockTime < nMyWakeTime )
nWalletUnlockTime = nMyWakeTime ;
}
LEAVE_CRITICAL_SECTION ( cs_nWalletUnlockTime ) ;
delete ( int64 * ) parg ;
}
Value walletpassphrase ( const Array & params , bool fHelp )
{
if ( pwalletMain - > IsCrypted ( ) & & ( fHelp | | params . size ( ) ! = 2 ) )
throw runtime_error (
" walletpassphrase <passphrase> <timeout> \n "
" Stores the wallet decryption key in memory for <timeout> seconds. " ) ;
if ( fHelp )
return true ;
if ( ! pwalletMain - > IsCrypted ( ) )
throw JSONRPCError ( RPC_WALLET_WRONG_ENC_STATE , " Error: running with an unencrypted wallet, but walletpassphrase was called. " ) ;
if ( ! pwalletMain - > IsLocked ( ) )
throw JSONRPCError ( RPC_WALLET_ALREADY_UNLOCKED , " Error: Wallet is already unlocked. " ) ;
// Note that the walletpassphrase is stored in params[0] which is not mlock()ed
SecureString strWalletPass ;
strWalletPass . reserve ( 100 ) ;
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make params[0] mlock()'d to begin with.
strWalletPass = params [ 0 ] . get_str ( ) . c_str ( ) ;
if ( strWalletPass . length ( ) > 0 )
{
if ( ! pwalletMain - > Unlock ( strWalletPass ) )
throw JSONRPCError ( RPC_WALLET_PASSPHRASE_INCORRECT , " Error: The wallet passphrase entered was incorrect. " ) ;
}
else
throw runtime_error (
" walletpassphrase <passphrase> <timeout> \n "
" Stores the wallet decryption key in memory for <timeout> seconds. " ) ;
NewThread ( ThreadTopUpKeyPool , NULL ) ;
int64 * pnSleepTime = new int64 ( params [ 1 ] . get_int64 ( ) ) ;
NewThread ( ThreadCleanWalletPassphrase , pnSleepTime ) ;
return Value : : null ;
}
Value walletpassphrasechange ( const Array & params , bool fHelp )
{
if ( pwalletMain - > IsCrypted ( ) & & ( fHelp | | params . size ( ) ! = 2 ) )
throw runtime_error (
" walletpassphrasechange <oldpassphrase> <newpassphrase> \n "
" Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>. " ) ;
if ( fHelp )
return true ;
if ( ! pwalletMain - > IsCrypted ( ) )
throw JSONRPCError ( RPC_WALLET_WRONG_ENC_STATE , " Error: running with an unencrypted wallet, but walletpassphrasechange was called. " ) ;
// TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
// Alternately, find a way to make params[0] mlock()'d to begin with.
SecureString strOldWalletPass ;
strOldWalletPass . reserve ( 100 ) ;
strOldWalletPass = params [ 0 ] . get_str ( ) . c_str ( ) ;
SecureString strNewWalletPass ;
strNewWalletPass . reserve ( 100 ) ;
strNewWalletPass = params [ 1 ] . get_str ( ) . c_str ( ) ;
if ( strOldWalletPass . length ( ) < 1 | | strNewWalletPass . length ( ) < 1 )
throw runtime_error (
" walletpassphrasechange <oldpassphrase> <newpassphrase> \n "
" Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>. " ) ;
if ( ! pwalletMain - > ChangeWalletPassphrase ( strOldWalletPass , strNewWalletPass ) )
throw JSONRPCError ( RPC_WALLET_PASSPHRASE_INCORRECT , " Error: The wallet passphrase entered was incorrect. " ) ;
return Value : : null ;
}
Value walletlock ( const Array & params , bool fHelp )
{
if ( pwalletMain - > IsCrypted ( ) & & ( fHelp | | params . size ( ) ! = 0 ) )
throw runtime_error (
" walletlock \n "
" Removes the wallet encryption key from memory, locking the wallet. \n "
" After calling this method, you will need to call walletpassphrase again \n "
" before being able to call any methods which require the wallet to be unlocked. " ) ;
if ( fHelp )
return true ;
if ( ! pwalletMain - > IsCrypted ( ) )
throw JSONRPCError ( RPC_WALLET_WRONG_ENC_STATE , " Error: running with an unencrypted wallet, but walletlock was called. " ) ;
{
LOCK ( cs_nWalletUnlockTime ) ;
pwalletMain - > Lock ( ) ;
nWalletUnlockTime = 0 ;
}
return Value : : null ;
}
Value encryptwallet ( const Array & params , bool fHelp )
{
if ( ! pwalletMain - > IsCrypted ( ) & & ( fHelp | | params . size ( ) ! = 1 ) )
throw runtime_error (
" encryptwallet <passphrase> \n "
" Encrypts the wallet with <passphrase>. " ) ;
if ( fHelp )
return true ;
if ( pwalletMain - > IsCrypted ( ) )
throw JSONRPCError ( RPC_WALLET_WRONG_ENC_STATE , " Error: running with an encrypted wallet, but encryptwallet was called. " ) ;
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make params[0] mlock()'d to begin with.
SecureString strWalletPass ;
strWalletPass . reserve ( 100 ) ;
strWalletPass = params [ 0 ] . get_str ( ) . c_str ( ) ;
if ( strWalletPass . length ( ) < 1 )
throw runtime_error (
" encryptwallet <passphrase> \n "
" Encrypts the wallet with <passphrase>. " ) ;
if ( ! pwalletMain - > EncryptWallet ( strWalletPass ) )
throw JSONRPCError ( RPC_WALLET_ENCRYPTION_FAILED , " Error: Failed to encrypt the wallet. " ) ;
// BDB seems to have a bad habit of writing old data into
// slack space in .dat files; that is bad if the old data is
// unencrypted private keys. So:
StartShutdown ( ) ;
return " wallet encrypted; Gostcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup. " ;
}
class DescribeAddressVisitor : public boost : : static_visitor < Object >
{
public :
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 ) ) ) ;
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 < CTxDestination > 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 ) ) ;
return obj ;
}
} ;
Value validateaddress ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" validateaddress <gostcoinaddress> \n "
" Return information about <gostcoinaddress>. " ) ;
CBitcoinAddress address ( params [ 0 ] . get_str ( ) ) ;
bool isValid = address . IsValid ( ) ;
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 = pwalletMain ? IsMine ( * pwalletMain , dest ) : false ;
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 & & pwalletMain - > mapAddressBook . count ( dest ) )
ret . push_back ( Pair ( " account " , pwalletMain - > mapAddressBook [ dest ] ) ) ;
}
return ret ;
}
Value lockunspent ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 2 )
throw runtime_error (
" lockunspent unlock? [array-of-Objects] \n "
" Updates list of temporarily unspendable outputs. " ) ;
if ( params . size ( ) = = 1 )
RPCTypeCheck ( params , list_of ( bool_type ) ) ;
else
RPCTypeCheck ( params , list_of ( bool_type ) ( array_type ) ) ;
bool fUnlock = params [ 0 ] . get_bool ( ) ;
if ( params . size ( ) = = 1 ) {
if ( fUnlock )
pwalletMain - > UnlockAllCoins ( ) ;
return true ;
}
Array outputs = params [ 1 ] . get_array ( ) ;
BOOST_FOREACH ( Value & output , outputs )
{
if ( output . type ( ) ! = obj_type )
throw JSONRPCError ( - 8 , " Invalid parameter, expected object " ) ;
const Object & o = output . get_obj ( ) ;
RPCTypeCheck ( o , map_list_of ( " txid " , str_type ) ( " vout " , int_type ) ) ;
string txid = find_value ( o , " txid " ) . get_str ( ) ;
if ( ! IsHex ( txid ) )
throw JSONRPCError ( - 8 , " Invalid parameter, expected hex txid " ) ;
int nOutput = find_value ( o , " vout " ) . get_int ( ) ;
if ( nOutput < 0 )
throw JSONRPCError ( - 8 , " Invalid parameter, vout must be positive " ) ;
COutPoint outpt ( uint256 ( txid ) , nOutput ) ;
if ( fUnlock )
pwalletMain - > UnlockCoin ( outpt ) ;
else
pwalletMain - > LockCoin ( outpt ) ;
}
return true ;
}
Value listlockunspent ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) > 0 )
throw runtime_error (
" listlockunspent \n "
" Returns list of temporarily unspendable outputs. " ) ;
vector < COutPoint > vOutpts ;
pwalletMain - > ListLockedCoins ( vOutpts ) ;
Array ret ;
BOOST_FOREACH ( COutPoint & outpt , vOutpts ) {
Object o ;
o . push_back ( Pair ( " txid " , outpt . hash . GetHex ( ) ) ) ;
o . push_back ( Pair ( " vout " , ( int ) outpt . n ) ) ;
ret . push_back ( o ) ;
}
return ret ;
}