@ -84,7 +84,13 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
@@ -84,7 +84,13 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry . push_back ( Pair ( item . first , item . second ) ) ;
}
string AccountFromValue ( const Value & value )
{
string strAccount = value . get_str ( ) ;
if ( strAccount = = " * " )
throw JSONRPCError ( - 11 , " Invalid account name " ) ;
return strAccount ;
}
@ -296,7 +302,7 @@ Value getnewaddress(const Array& params, bool fHelp)
@@ -296,7 +302,7 @@ Value getnewaddress(const Array& params, bool fHelp)
// Parse the account first so we don't generate a key if there's an error
string strAccount ;
if ( params . size ( ) > 0 )
strAccount = params [ 0 ] . get_str ( ) ;
strAccount = AccountFromValue ( params [ 0 ] ) ;
// Generate a new key that is added to wallet
string strAddress = PubKeyToAddress ( GetKeyFromKeyPool ( ) ) ;
@ -314,7 +320,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
@@ -314,7 +320,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
" Returns the current bitcoin 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 = params [ 0 ] . get_str ( ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
@ -365,7 +371,7 @@ Value setaccount(const Array& params, bool fHelp)
@@ -365,7 +371,7 @@ Value setaccount(const Array& params, bool fHelp)
string strAddress = params [ 0 ] . get_str ( ) ;
string strAccount ;
if ( params . size ( ) > 1 )
strAccount = params [ 1 ] . get_str ( ) ;
strAccount = AccountFromValue ( params [ 1 ] ) ;
SetAddressBookName ( strAddress , strAccount ) ;
return Value : : null ;
@ -399,7 +405,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
@@ -399,7 +405,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
" getaddressesbyaccount <account> \n "
" Returns the list of addresses for the given account. " ) ;
string strAccount = params [ 0 ] . get_str ( ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
// Find all addresses that have the given account
Array ret ;
@ -436,7 +442,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
@@ -436,7 +442,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
// Wallet comments
CWalletTx wtx ;
if ( params . size ( ) > 2 & & params [ 2 ] . type ( ) ! = null_type & & ! params [ 2 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " message " ] = params [ 2 ] . get_str ( ) ;
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 ( ) ;
@ -522,7 +528,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
@@ -522,7 +528,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
nMinDepth = params [ 1 ] . get_int ( ) ;
// Get the set of pub keys that have the label
string strAccount = params [ 0 ] . get_str ( ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
set < CScript > setPubKey ;
GetAccountPubKeys ( strAccount , setPubKey ) ;
@ -549,9 +555,6 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
@@ -549,9 +555,6 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
int64 GetAccountBalance ( CWalletDB & walletdb , const string & strAccount , int nMinDepth )
{
set < CScript > setPubKey ;
GetAccountPubKeys ( strAccount , setPubKey ) ;
int64 nBalance = 0 ;
CRITICAL_BLOCK ( cs_mapWallet )
{
@ -563,7 +566,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
@@ -563,7 +566,7 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
continue ;
int64 nGenerated , nReceived , nSent , nFee ;
wtx . GetAccountAmounts ( strAccount , setPubKey , nGenerated , nReceived , nSent , nFee ) ;
wtx . GetAccountAmounts ( strAccount , nGenerated , nReceived , nSent , nFee ) ;
if ( nReceived ! = 0 & & wtx . GetDepthInMainChain ( ) > = nMinDepth )
nBalance + = nReceived ;
@ -595,7 +598,7 @@ Value getbalance(const Array& params, bool fHelp)
@@ -595,7 +598,7 @@ Value getbalance(const Array& params, bool fHelp)
if ( params . size ( ) = = 0 )
return ( ( double ) GetBalance ( ) / ( double ) COIN ) ;
string strAccount = params [ 0 ] . get_str ( ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 1 )
nMinDepth = params [ 1 ] . get_int ( ) ;
@ -613,8 +616,8 @@ Value movecmd(const Array& params, bool fHelp)
@@ -613,8 +616,8 @@ Value movecmd(const Array& params, bool fHelp)
" move <fromaccount> <toaccount> <amount> [minconf=1] [comment] \n "
" Move from one account in your wallet to another. " ) ;
string strFrom = params [ 0 ] . get_str ( ) ;
string strTo = params [ 1 ] . get_str ( ) ;
string strFrom = AccountFromValue ( params [ 0 ] ) ;
string strTo = AccountFromValue ( params [ 1 ] ) ;
int64 nAmount = AmountFromValue ( params [ 2 ] ) ;
int nMinDepth = 1 ;
if ( params . size ( ) > 3 )
@ -647,19 +650,21 @@ Value movecmd(const Array& params, bool fHelp)
@@ -647,19 +650,21 @@ Value movecmd(const Array& params, bool fHelp)
// Debit
CAccountingEntry debit ;
debit . strAccount = strFrom ;
debit . nCreditDebit = - nAmount ;
debit . nTime = nNow ;
debit . strOtherAccount = strTo ;
debit . strComment = strComment ;
walletdb . WriteAccountingEntry ( strFrom , debit ) ;
walletdb . WriteAccountingEntry ( debit ) ;
// Credit
CAccountingEntry credit ;
credit . strAccount = strTo ;
credit . nCreditDebit = nAmount ;
credit . nTime = nNow ;
credit . strOtherAccount = strFrom ;
credit . strComment = strComment ;
walletdb . WriteAccountingEntry ( strTo , credit ) ;
walletdb . WriteAccountingEntry ( credit ) ;
walletdb . TxnCommit ( ) ;
}
@ -674,7 +679,7 @@ Value sendfrom(const Array& params, bool fHelp)
@@ -674,7 +679,7 @@ Value sendfrom(const Array& params, bool fHelp)
" sendfrom <fromaccount> <tobitcoinaddress> <amount> [minconf=1] [comment] [comment-to] \n "
" <amount> is a real and is rounded to the nearest 0.01 " ) ;
string strAccount = params [ 0 ] . get_str ( ) ;
string strAccount = AccountFromValue ( params [ 0 ] ) ;
string strAddress = params [ 1 ] . get_str ( ) ;
int64 nAmount = AmountFromValue ( params [ 2 ] ) ;
int nMinDepth = 1 ;
@ -684,7 +689,7 @@ Value sendfrom(const Array& params, bool fHelp)
@@ -684,7 +689,7 @@ Value sendfrom(const Array& params, bool fHelp)
CWalletTx wtx ;
wtx . strFromAccount = strAccount ;
if ( params . size ( ) > 4 & & params [ 4 ] . type ( ) ! = null_type & & ! params [ 4 ] . get_str ( ) . empty ( ) )
wtx . mapValue [ " message " ] = params [ 4 ] . get_str ( ) ;
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 ( ) ;
@ -849,97 +854,180 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
@@ -849,97 +854,180 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
return ListReceived ( params , true ) ;
}
void ListAccount Transactions ( CWalletDB & walletdb , const string & strAccount , int nMinDepth , multimap < int64 , Object > & ret )
void ListTransactions ( const CWalletTx & wtx , const string & strAccount , int nMinDepth , Array & ret )
{
set < CScript > setPubKey ;
GetAccountPubKeys ( strAccount , setPubKey ) ;
int64 nGenerated , nSent , nFee ;
string strSentAccount ;
list < pair < string , int64 > > listReceived ;
wtx . GetAmounts ( nGenerated , listReceived , nSent , nFee , strSentAccount ) ;
CRITICAL_BLOCK ( cs_mapWallet )
{
// Wallet: generate/send/receive transactions
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( ! wtx . IsFinal ( ) )
continue ;
int64 nGenerated , nReceived , nSent , nFee ;
wtx . GetAccountAmounts ( strAccount , setPubKey , nGenerated , nReceived , nSent , nFee ) ;
bool fAllAccounts = ( strAccount = = string ( " * " ) ) ;
// Generated blocks count to account ""
if ( nGenerated ! = 0 )
// Generated blocks assigned to account ""
if ( nGenerated ! = 0 & & ( fAllAccounts | | strAccount = = " " ) )
{
Object entry ;
entry . push_back ( Pair ( " account " , string ( " " ) ) ) ;
entry . push_back ( Pair ( " category " , " generate " ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( nGenerated ) ) ) ;
WalletTxToJSON ( wtx , entry ) ;
ret . insert ( make_pair ( wtx . GetTxTime ( ) , entry ) ) ;
ret . push_back ( entry ) ;
}
// Sent
if ( nSent ! = 0 | | nFee ! = 0 )
if ( ( nSent ! = 0 | | nFee ! = 0 ) & & ( fAllAccounts | | strAccount = = strSentAccount ) )
{
Object entry ;
entry . push_back ( Pair ( " account " , strSentAccount ) ) ;
entry . push_back ( Pair ( " category " , " send " ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( - nSent ) ) ) ;
entry . push_back ( Pair ( " fee " , ValueFromAmount ( - nFee ) ) ) ;
WalletTxToJSON ( wtx , entry ) ;
ret . insert ( make_pair ( wtx . GetTxTime ( ) , entry ) ) ;
ret . push_back ( entry ) ;
}
// Received
if ( nReceived ! = 0 & & wtx . GetDepthInMainChain ( ) > = nMinDepth )
if ( listReceived . size ( ) > 0 & & wtx . GetDepthInMainChain ( ) > = nMinDepth )
CRITICAL_BLOCK ( cs_mapAddressBook )
{
foreach ( const PAIRTYPE ( string , int64 ) & r , listReceived )
if ( mapAddressBook . count ( r . first ) & & ( fAllAccounts | | r . first = = strAccount ) )
{
Object entry ;
entry . push_back ( Pair ( " account " , r . first ) ) ;
entry . push_back ( Pair ( " category " , " receive " ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( nReceived ) ) ) ;
entry . push_back ( Pair ( " amount " , ValueFromAmount ( r . secon d) ) ) ;
WalletTxToJSON ( wtx , entry ) ;
ret . insert ( make_pair ( wtx . GetTxTime ( ) , entry ) ) ;
ret . push_back ( entry ) ;
}
}
// Internal accounting entries
list < CAccountingEntry > acentries ;
walletdb . ListAccountCreditDebit ( strAccount , acentries ) ;
foreach ( const CAccountingEntry & acentry , acentries )
}
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 ( " amount " , ValueFromAmount ( acentry . nCreditDebit ) ) ) ;
entry . push_back ( Pair ( " otheraccount " , acentry . strOtherAccount ) ) ;
ret . insert ( make_pair ( acentry . nTime , entry ) ) ;
}
entry . push_back ( Pair ( " comment " , acentry . strComment ) ) ;
ret . push_back ( entry ) ;
}
}
Value listtransactions ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) < 1 | | params . size ( ) > 2 )
if ( fHelp | | params . size ( ) > 2 )
throw runtime_error (
" listtransactions <account> [count=10] \n "
" listtransactions [account] [count=10] \n "
" Returns up to [count] most recent transactions for account <account>. " ) ;
string strAccount = params [ 0 ] . get_str ( ) ;
string strAccount = " * " ;
if ( params . size ( ) > 0 )
strAccount = params [ 0 ] . get_str ( ) ;
int nCount = 10 ;
if ( params . size ( ) > 1 )
nCount = params [ 1 ] . get_int ( ) ;
Array ret ;
CWalletDB walletdb ;
multimap < int64 , Object > mapByTime ; // keys are transaction time
ListAccountTransactions ( walletdb , strAccount , 0 , mapByTime ) ;
// Return only last nCount items:
int nToErase = mapByTime . size ( ) - nCount ;
if ( nToErase > 0 )
CRITICAL_BLOCK ( cs_mapWallet )
{
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
typedef pair < CWalletTx * , CAccountingEntry * > TxPair ;
typedef multimap < int64 , TxPair > TxItems ;
TxItems txByTime ;
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
multimap < int64 , Object > : : iterator end = mapByTime . begin ( ) ;
std : : advance ( end , nToErase ) ;
mapByTime . erase ( mapByTime . begin ( ) , end ) ;
CWalletTx * wtx = & ( ( * it ) . second ) ;
txByTime . insert ( make_pair ( wtx - > GetTxTime ( ) , TxPair ( wtx , 0 ) ) ) ;
}
list < CAccountingEntry > acentries ;
walletdb . ListAccountCreditDebit ( strAccount , acentries ) ;
foreach ( CAccountingEntry & entry , acentries )
{
txByTime . insert ( make_pair ( entry . nTime , TxPair ( 0 , & entry ) ) ) ;
}
Array ret ;
foreach ( const PAIRTYPE ( int64 , Object ) & item , mapByTime )
ret . push_back ( item . second ) ;
// Now: iterate backwards until we have nCount items to return:
for ( TxItems : : reverse_iterator it = txByTime . rbegin ( ) ; it ! = txByTime . rend ( ) ; + + it )
{
CWalletTx * const pwtx = ( * it ) . second . first ;
if ( pwtx ! = 0 )
ListTransactions ( * pwtx , strAccount , 0 , ret ) ;
CAccountingEntry * const pacentry = ( * it ) . second . second ;
if ( pacentry ! = 0 )
AcentryToJSON ( * pacentry , strAccount , ret ) ;
if ( ret . size ( ) > = nCount ) break ;
}
// ret is now newest to oldest
}
// Make sure we return only last nCount items (sends-to-self might give us an extra):
if ( ret . size ( ) > nCount )
{
Array : : iterator last = ret . begin ( ) ;
std : : advance ( last , nCount ) ;
ret . erase ( last , ret . end ( ) ) ;
}
std : : reverse ( ret . begin ( ) , ret . end ( ) ) ; // 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 ( ) > 1 )
nMinDepth = params [ 1 ] . get_int ( ) ;
map < string , int64 > mapAccountBalances ;
CRITICAL_BLOCK ( cs_mapWallet )
CRITICAL_BLOCK ( cs_mapAddressBook )
{
foreach ( const PAIRTYPE ( string , string ) & entry , mapAddressBook )
mapAccountBalances [ entry . second ] = 0 ;
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
int64 nGenerated , nSent , nFee ;
string strSentAccount ;
list < pair < string , int64 > > listReceived ;
wtx . GetAmounts ( nGenerated , listReceived , nSent , nFee , strSentAccount ) ;
mapAccountBalances [ strSentAccount ] - = nSent + nFee ;
if ( wtx . GetDepthInMainChain ( ) > = nMinDepth )
{
mapAccountBalances [ " " ] + = nGenerated ;
foreach ( const PAIRTYPE ( string , int64 ) & r , listReceived )
if ( mapAddressBook . count ( r . first ) )
mapAccountBalances [ mapAddressBook [ r . first ] ] + = r . second ;
}
}
}
list < CAccountingEntry > acentries ;
CWalletDB ( ) . ListAccountCreditDebit ( " * " , acentries ) ;
foreach ( const CAccountingEntry & entry , acentries )
mapAccountBalances [ entry . strAccount ] + = entry . nCreditDebit ;
Object ret ;
foreach ( const PAIRTYPE ( string , int64 ) & accountBalance , mapAccountBalances ) {
ret . push_back ( Pair ( accountBalance . first , ValueFromAmount ( accountBalance . second ) ) ) ;
}
return ret ;
}
@ -1175,6 +1263,7 @@ pair<string, rpcfn_type> pCallTable[] =
@@ -1175,6 +1263,7 @@ pair<string, rpcfn_type> pCallTable[] =
make_pair ( " gettransaction " , & gettransaction ) ,
make_pair ( " listtransactions " , & listtransactions ) ,
make_pair ( " getwork " , & getwork ) ,
make_pair ( " listaccounts " , & listaccounts ) ,
} ;
map < string , rpcfn_type > mapCallTable ( pCallTable , pCallTable + sizeof ( pCallTable ) / sizeof ( pCallTable [ 0 ] ) ) ;
@ -1247,7 +1336,7 @@ string HTTPReply(int nStatus, const string& strMsg)
@@ -1247,7 +1336,7 @@ string HTTPReply(int nStatus, const string& strMsg)
" Server: bitcoin-json-rpc \r \n "
" WWW-Authenticate: Basic realm= \" jsonrpc \" \r \n "
" Content-Type: text/html \r \n "
" Content-Length: 311 \r \n "
" Content-Length: 296 \r \n "
" \r \n "
" <!DOCTYPE HTML PUBLIC \" -//W3C//DTD HTML 4.01 Transitional//EN \" \r \n "
" \" http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd \" > \r \n "
@ -1421,6 +1510,17 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
@@ -1421,6 +1510,17 @@ string JSONRPCReply(const Value& result, const Value& error, const Value& id)
return write_string ( Value ( reply ) , false ) + " \n " ;
}
void ErrorReply ( std : : ostream & stream , const Object & objError , const Value & id )
{
// Send error reply from json-rpc error object
int nStatus = 500 ;
int code = find_value ( objError , " code " ) . get_int ( ) ;
if ( code = = - 32600 ) nStatus = 400 ;
else if ( code = = - 32601 ) nStatus = 404 ;
string strReply = JSONRPCReply ( Value : : null , objError , id ) ;
stream < < HTTPReply ( nStatus , strReply ) < < std : : flush ;
}
bool ClientAllowed ( const string & strAddress )
{
if ( strAddress = = asio : : ip : : address_v4 : : loopback ( ) . to_string ( ) )
@ -1581,10 +1681,16 @@ void ThreadRPCServer2(void* parg)
@@ -1581,10 +1681,16 @@ void ThreadRPCServer2(void* parg)
if ( ! ClientAllowed ( peer . address ( ) . to_string ( ) ) )
continue ;
// Receive request
map < string , string > mapHeaders ;
string strRequest ;
ReadHTTP ( stream , mapHeaders , strRequest ) ;
boost : : thread api_caller ( ReadHTTP , ref ( stream ) , ref ( mapHeaders ) , ref ( strRequest ) ) ;
if ( ! api_caller . timed_join ( boost : : posix_time : : seconds ( GetArg ( " -rpctimeout " , 30 ) ) ) )
{ // Timed out:
acceptor . cancel ( ) ;
printf ( " ThreadRPCServer ReadHTTP timeout \n " ) ;
continue ;
}
// Check authorization
if ( mapHeaders . count ( " Authorization " ) = = 0 )
@ -1656,26 +1762,16 @@ void ThreadRPCServer2(void* parg)
@@ -1656,26 +1762,16 @@ void ThreadRPCServer2(void* parg)
}
catch ( std : : exception & e )
{
// Send error reply from method
string strReply = JSONRPCReply ( Value : : null , JSONRPCError ( - 1 , e . what ( ) ) , id ) ;
stream < < HTTPReply ( 500 , strReply ) < < std : : flush ;
ErrorReply ( stream , JSONRPCError ( - 1 , e . what ( ) ) , id ) ;
}
}
catch ( Object & objError )
{
// Send error reply from json-rpc error object
int nStatus = 500 ;
int code = find_value ( objError , " code " ) . get_int ( ) ;
if ( code = = - 32600 ) nStatus = 400 ;
else if ( code = = - 32601 ) nStatus = 404 ;
string strReply = JSONRPCReply ( Value : : null , objError , id ) ;
stream < < HTTPReply ( nStatus , strReply ) < < std : : flush ;
ErrorReply ( stream , objError , id ) ;
}
catch ( std : : exception & e )
{
// Send error reply from other json-rpc parsing errors
string strReply = JSONRPCReply ( Value : : null , JSONRPCError ( - 32700 , e . what ( ) ) , id ) ;
stream < < HTTPReply ( 500 , strReply ) < < std : : flush ;
ErrorReply ( stream , JSONRPCError ( - 32700 , e . what ( ) ) , id ) ;
}
}
}
@ -1812,6 +1908,7 @@ int CommandLineRPC(int argc, char *argv[])
@@ -1812,6 +1908,7 @@ int CommandLineRPC(int argc, char *argv[])
if ( strMethod = = " sendfrom " & & n > 2 ) ConvertTo < double > ( params [ 2 ] ) ;
if ( strMethod = = " sendfrom " & & n > 3 ) ConvertTo < boost : : int64_t > ( params [ 3 ] ) ;
if ( strMethod = = " listtransactions " & & n > 1 ) ConvertTo < boost : : int64_t > ( params [ 1 ] ) ;
if ( strMethod = = " listaccounts " & & n > 1 ) ConvertTo < boost : : int64_t > ( params [ 1 ] ) ;
// Execute
Object reply = CallRPC ( strMethod , params ) ;