@ -2,35 +2,68 @@
// Distributed under the MIT/X11 software license, see the accompanying
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include <iostream>
# include <fstream>
# include "init.h" // for pwalletMain
# include "init.h" // for pwalletMain
# include "bitcoinrpc.h"
# include "bitcoinrpc.h"
# include "ui_interface.h"
# include "ui_interface.h"
# include "base58.h"
# include "base58.h"
# include <boost/date_time/posix_time/posix_time.hpp>
# include <boost/lexical_cast.hpp>
# include <boost/lexical_cast.hpp>
# include <boost/variant/get.hpp>
# include <boost/algorithm/string.hpp>
# define printf OutputDebugStringF
# define printf OutputDebugStringF
using namespace json_spirit ;
using namespace json_spirit ;
using namespace std ;
using namespace std ;
class CTxDump
void EnsureWalletIsUnlocked ( ) ;
{
public :
std : : string static EncodeDumpTime ( int64 nTime ) {
CBlockIndex * pindex ;
return DateTimeStrFormat ( " %Y-%m-%dT%H:%M:%SZ " , nTime ) ;
int64 nValue ;
}
bool fSpent ;
CWalletTx * ptx ;
int64 static DecodeDumpTime ( const std : : string & str ) {
int nOut ;
static const boost : : posix_time : : time_input_facet facet ( " %Y-%m-%dT%H:%M:%SZ " ) ;
CTxDump ( CWalletTx * ptx = NULL , int nOut = - 1 )
static const boost : : posix_time : : ptime epoch = boost : : posix_time : : from_time_t ( 0 ) ;
{
const std : : locale loc ( std : : locale : : classic ( ) , & facet ) ;
pindex = NULL ;
std : : istringstream iss ( str ) ;
nValue = 0 ;
iss . imbue ( loc ) ;
fSpent = false ;
boost : : posix_time : : ptime ptime ( boost : : date_time : : not_a_date_time ) ;
this - > ptx = ptx ;
iss > > ptime ;
this - > nOut = nOut ;
if ( ptime . is_not_a_date_time ( ) )
return 0 ;
return ( ptime - epoch ) . total_seconds ( ) ;
}
std : : string static EncodeDumpString ( const std : : string & str ) {
std : : stringstream ret ;
BOOST_FOREACH ( unsigned char c , str ) {
if ( c < = 32 | | c > = 128 | | c = = ' % ' ) {
ret < < ' % ' < < HexStr ( & c , & c + 1 ) ;
} else {
ret < < c ;
}
}
} ;
}
return ret . str ( ) ;
}
std : : string DecodeDumpString ( const std : : string & str ) {
std : : stringstream ret ;
for ( unsigned int pos = 0 ; pos < str . length ( ) ; pos + + ) {
unsigned char c = str [ pos ] ;
if ( c = = ' % ' & & pos + 2 < str . length ( ) ) {
c = ( ( ( str [ pos + 1 ] > > 6 ) * 9 + ( ( str [ pos + 1 ] - ' 0 ' ) & 15 ) ) < < 4 ) |
( ( str [ pos + 2 ] > > 6 ) * 9 + ( ( str [ pos + 2 ] - ' 0 ' ) & 15 ) ) ;
pos + = 2 ;
}
ret < < c ;
}
return ret . str ( ) ;
}
Value importprivkey ( const Array & params , bool fHelp )
Value importprivkey ( const Array & params , bool fHelp )
{
{
@ -63,6 +96,10 @@ Value importprivkey(const Array& params, bool fHelp)
pwalletMain - > MarkDirty ( ) ;
pwalletMain - > MarkDirty ( ) ;
pwalletMain - > SetAddressBookName ( vchAddress , strLabel ) ;
pwalletMain - > SetAddressBookName ( vchAddress , strLabel ) ;
// Don't throw error in case a key is already there
if ( pwalletMain - > HaveKey ( vchAddress ) )
return Value : : null ;
if ( ! pwalletMain - > AddKeyPubKey ( key , pubkey ) )
if ( ! pwalletMain - > AddKeyPubKey ( key , pubkey ) )
throw JSONRPCError ( RPC_WALLET_ERROR , " Error adding key to wallet " ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Error adding key to wallet " ) ;
@ -75,6 +112,86 @@ Value importprivkey(const Array& params, bool fHelp)
return Value : : null ;
return Value : : null ;
}
}
Value importwallet ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" importwallet <filename> \n "
" Imports keys from a wallet dump file (see dumpwallet). " ) ;
EnsureWalletIsUnlocked ( ) ;
ifstream file ;
file . open ( params [ 0 ] . get_str ( ) . c_str ( ) ) ;
if ( ! file . is_open ( ) )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Cannot open wallet dump file " ) ;
int64 nTimeBegin = pindexBest - > nTime ;
bool fGood = true ;
while ( file . good ( ) ) {
std : : string line ;
std : : getline ( file , line ) ;
if ( line . empty ( ) | | line [ 0 ] = = ' # ' )
continue ;
std : : vector < std : : string > vstr ;
boost : : split ( vstr , line , boost : : is_any_of ( " " ) ) ;
if ( vstr . size ( ) < 2 )
continue ;
CBitcoinSecret vchSecret ;
if ( ! vchSecret . SetString ( vstr [ 0 ] ) )
continue ;
CKey key = vchSecret . GetKey ( ) ;
CPubKey pubkey = key . GetPubKey ( ) ;
CKeyID keyid = pubkey . GetID ( ) ;
if ( pwalletMain - > HaveKey ( keyid ) ) {
printf ( " Skipping import of %s (key already present) \n " , CBitcoinAddress ( keyid ) . ToString ( ) . c_str ( ) ) ;
continue ;
}
int64 nTime = DecodeDumpTime ( vstr [ 1 ] ) ;
std : : string strLabel ;
bool fLabel = true ;
for ( unsigned int nStr = 2 ; nStr < vstr . size ( ) ; nStr + + ) {
if ( boost : : algorithm : : starts_with ( vstr [ nStr ] , " # " ) )
break ;
if ( vstr [ nStr ] = = " change=1 " )
fLabel = false ;
if ( vstr [ nStr ] = = " reserve=1 " )
fLabel = false ;
if ( boost : : algorithm : : starts_with ( vstr [ nStr ] , " label= " ) ) {
strLabel = DecodeDumpString ( vstr [ nStr ] . substr ( 6 ) ) ;
fLabel = true ;
}
}
printf ( " Importing %s... \n " , CBitcoinAddress ( keyid ) . ToString ( ) . c_str ( ) ) ;
if ( ! pwalletMain - > AddKeyPubKey ( key , pubkey ) ) {
fGood = false ;
continue ;
}
pwalletMain - > mapKeyMetadata [ keyid ] . nCreateTime = nTime ;
if ( fLabel )
pwalletMain - > SetAddressBookName ( keyid , strLabel ) ;
nTimeBegin = std : : min ( nTimeBegin , nTime ) ;
}
file . close ( ) ;
CBlockIndex * pindex = pindexBest ;
while ( pindex & & pindex - > pprev & & pindex - > nTime > nTimeBegin - 7200 )
pindex = pindex - > pprev ;
printf ( " Rescanning last %i blocks \n " , pindexBest - > nHeight - pindex - > nHeight + 1 ) ;
pwalletMain - > ScanForWalletTransactions ( pindex ) ;
pwalletMain - > ReacceptWalletTransactions ( ) ;
pwalletMain - > MarkDirty ( ) ;
if ( ! fGood )
throw JSONRPCError ( RPC_WALLET_ERROR , " Error adding some keys to wallet " ) ;
return Value : : null ;
}
Value dumpprivkey ( const Array & params , bool fHelp )
Value dumpprivkey ( const Array & params , bool fHelp )
{
{
if ( fHelp | | params . size ( ) ! = 1 )
if ( fHelp | | params . size ( ) ! = 1 )
@ -82,6 +199,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
" dumpprivkey <bitcoinaddress> \n "
" dumpprivkey <bitcoinaddress> \n "
" Reveals the private key corresponding to <bitcoinaddress>. " ) ;
" Reveals the private key corresponding to <bitcoinaddress>. " ) ;
EnsureWalletIsUnlocked ( ) ;
string strAddress = params [ 0 ] . get_str ( ) ;
string strAddress = params [ 0 ] . get_str ( ) ;
CBitcoinAddress address ;
CBitcoinAddress address ;
if ( ! address . SetString ( strAddress ) )
if ( ! address . SetString ( strAddress ) )
@ -94,3 +213,58 @@ Value dumpprivkey(const Array& params, bool fHelp)
throw JSONRPCError ( RPC_WALLET_ERROR , " Private key for address " + strAddress + " is not known " ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Private key for address " + strAddress + " is not known " ) ;
return CBitcoinSecret ( vchSecret ) . ToString ( ) ;
return CBitcoinSecret ( vchSecret ) . ToString ( ) ;
}
}
Value dumpwallet ( const Array & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 )
throw runtime_error (
" dumpwallet <filename> \n "
" Dumps all wallet keys in a human-readable format. " ) ;
EnsureWalletIsUnlocked ( ) ;
ofstream file ;
file . open ( params [ 0 ] . get_str ( ) . c_str ( ) ) ;
if ( ! file . is_open ( ) )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Cannot open wallet dump file " ) ;
std : : map < CKeyID , int64 > mapKeyBirth ;
std : : set < CKeyID > setKeyPool ;
pwalletMain - > GetKeyBirthTimes ( mapKeyBirth ) ;
pwalletMain - > GetAllReserveKeys ( setKeyPool ) ;
// sort time/key pairs
std : : vector < std : : pair < int64 , CKeyID > > vKeyBirth ;
for ( std : : map < CKeyID , int64 > : : const_iterator it = mapKeyBirth . begin ( ) ; it ! = mapKeyBirth . end ( ) ; it + + ) {
vKeyBirth . push_back ( std : : make_pair ( it - > second , it - > first ) ) ;
}
mapKeyBirth . clear ( ) ;
std : : sort ( vKeyBirth . begin ( ) , vKeyBirth . end ( ) ) ;
// produce output
file < < strprintf ( " # Wallet dump created by Bitcoin %s (%s) \n " , CLIENT_BUILD . c_str ( ) , CLIENT_DATE . c_str ( ) ) ;
file < < strprintf ( " # * Created on %s \n " , EncodeDumpTime ( GetTime ( ) ) . c_str ( ) ) ;
file < < strprintf ( " # * Best block at time of backup was %i (%s), \n " , nBestHeight , hashBestChain . ToString ( ) . c_str ( ) ) ;
file < < strprintf ( " # mined on %s \n " , EncodeDumpTime ( pindexBest - > nTime ) . c_str ( ) ) ;
file < < " \n " ;
for ( std : : vector < std : : pair < int64 , CKeyID > > : : const_iterator it = vKeyBirth . begin ( ) ; it ! = vKeyBirth . end ( ) ; it + + ) {
const CKeyID & keyid = it - > second ;
std : : string strTime = EncodeDumpTime ( it - > first ) ;
std : : string strAddr = CBitcoinAddress ( keyid ) . ToString ( ) ;
CKey key ;
if ( pwalletMain - > GetKey ( keyid , key ) ) {
if ( pwalletMain - > mapAddressBook . count ( keyid ) ) {
file < < strprintf ( " %s %s label=%s # addr=%s \n " , CBitcoinSecret ( key ) . ToString ( ) . c_str ( ) , strTime . c_str ( ) , EncodeDumpString ( pwalletMain - > mapAddressBook [ keyid ] ) . c_str ( ) , strAddr . c_str ( ) ) ;
} else if ( setKeyPool . count ( keyid ) ) {
file < < strprintf ( " %s %s reserve=1 # addr=%s \n " , CBitcoinSecret ( key ) . ToString ( ) . c_str ( ) , strTime . c_str ( ) , strAddr . c_str ( ) ) ;
} else {
file < < strprintf ( " %s %s change=1 # addr=%s \n " , CBitcoinSecret ( key ) . ToString ( ) . c_str ( ) , strTime . c_str ( ) , strAddr . c_str ( ) ) ;
}
}
}
file < < " \n " ;
file < < " # End of dump \n " ;
file . close ( ) ;
return Value : : null ;
}