@ -86,7 +86,8 @@ UniValue importprivkey(const JSONRPCRequest& request)
" 1. \" privkey \" (string, required) The private key (see dumpprivkey) \n "
" 1. \" privkey \" (string, required) The private key (see dumpprivkey) \n "
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" \n Note: This call can take minutes to complete if rescan is true. \n "
" \n Note: This call can take minutes to complete if rescan is true, during that time, other rpc calls \n "
" may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes. \n "
" \n Examples: \n "
" \n Examples: \n "
" \n Dump a private key \n "
" \n Dump a private key \n "
+ HelpExampleCli ( " dumpprivkey " , " \" myaddress \" " ) +
+ HelpExampleCli ( " dumpprivkey " , " \" myaddress \" " ) +
@ -101,61 +102,65 @@ UniValue importprivkey(const JSONRPCRequest& request)
) ;
) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
WalletRescanReserver reserver ( pwallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
std : : string strSecret = request . params [ 0 ] . get_str ( ) ;
std : : string strLabel = " " ;
if ( ! request . params [ 1 ] . isNull ( ) )
strLabel = request . params [ 1 ] . get_str ( ) ;
// Whether to perform rescan after import
bool fRescan = true ;
bool fRescan = true ;
if ( ! request . params [ 2 ] . isNull ( ) )
{
fRescan = request . params [ 2 ] . get_bool ( ) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
if ( fRescan & & fPruneMode )
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
CBitcoinSecret vchSecret ;
EnsureWalletIsUnlocked ( pwallet ) ;
bool fGood = vchSecret . SetString ( strSecret ) ;
if ( ! fGood ) throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid private key encoding " ) ;
std : : string strSecret = request . params [ 0 ] . get_str ( ) ;
std : : string strLabel = " " ;
if ( ! request . params [ 1 ] . isNull ( ) )
strLabel = request . params [ 1 ] . get_str ( ) ;
CKey key = vchSecret . GetKey ( ) ;
// Whether to perform rescan after import
if ( ! key . IsValid ( ) ) throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Private key outside allowed range " ) ;
if ( ! request . params [ 2 ] . isNull ( ) )
fRescan = request . params [ 2 ] . get_bool ( ) ;
CPubKey pubkey = key . GetPubKey ( ) ;
if ( fRescan & & fPruneMode )
assert ( key . VerifyPubKey ( pubkey ) ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
CKeyID vchAddress = pubkey . GetID ( ) ;
{
pwallet - > MarkDirty ( ) ;
// We don't know which corresponding address will be used; label them all
if ( fRescan & & ! reserver . reserve ( ) ) {
for ( const auto & dest : GetAllDestinationsForKey ( pubkey ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Wallet is currently rescanning. Abort existing rescan or wait. " ) ;
pwallet - > SetAddressBook ( dest , strLabel , " receive " ) ;
}
}
// Don't throw error in case a key is already there
CBitcoinSecret vchSecret ;
if ( pwallet - > HaveKey ( vchAddress ) ) {
bool fGood = vchSecret . SetString ( strSecret ) ;
return NullUniValue ;
}
pwallet - > mapKeyMetadata [ vchAddress ] . nCreateTime = 1 ;
if ( ! fGood ) throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid private key encoding " ) ;
if ( ! pwallet - > AddKeyPubKey ( key , pubkey ) ) {
CKey key = vchSecret . GetKey ( ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Error adding key to wallet " ) ;
if ( ! key . IsValid ( ) ) throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Private key outside allowed range " ) ;
}
pwallet - > LearnAllRelatedScripts ( pubkey ) ;
// whenever a key is imported, we need to scan the whole chain
CPubKey pubkey = key . GetPubKey ( ) ;
pwallet - > UpdateTimeFirstKey ( 1 ) ;
assert ( key . VerifyPubKey ( pubkey ) ) ;
CKeyID vchAddress = pubkey . GetID ( ) ;
{
pwallet - > MarkDirty ( ) ;
// We don't know which corresponding address will be used; label them all
for ( const auto & dest : GetAllDestinationsForKey ( pubkey ) ) {
pwallet - > SetAddressBook ( dest , strLabel , " receive " ) ;
}
if ( fRescan ) {
// Don't throw error in case a key is already there
pwallet - > RescanFromTime ( TIMESTAMP_MIN , true /* update */ ) ;
if ( pwallet - > HaveKey ( vchAddress ) ) {
return NullUniValue ;
}
// whenever a key is imported, we need to scan the whole chain
pwallet - > UpdateTimeFirstKey ( 1 ) ;
pwallet - > mapKeyMetadata [ vchAddress ] . nCreateTime = 1 ;
if ( ! pwallet - > AddKeyPubKey ( key , pubkey ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Error adding key to wallet " ) ;
}
pwallet - > LearnAllRelatedScripts ( pubkey ) ;
}
}
}
}
if ( fRescan ) {
pwallet - > RescanFromTime ( TIMESTAMP_MIN , reserver , true /* update */ ) ;
}
return NullUniValue ;
return NullUniValue ;
}
}
@ -237,7 +242,8 @@ UniValue importaddress(const JSONRPCRequest& request)
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" 4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well \n "
" 4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well \n "
" \n Note: This call can take minutes to complete if rescan is true. \n "
" \n Note: This call can take minutes to complete if rescan is true, during that time, other rpc calls \n "
" may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes. \n "
" If you have the full public key, you should call importpubkey instead of this. \n "
" If you have the full public key, you should call importpubkey instead of this. \n "
" \n Note: If you import a non-standard raw script in hex form, outputs sending to it will be treated \n "
" \n Note: If you import a non-standard raw script in hex form, outputs sending to it will be treated \n "
" as change, and not show up in many RPCs. \n "
" as change, and not show up in many RPCs. \n "
@ -263,29 +269,35 @@ UniValue importaddress(const JSONRPCRequest& request)
if ( fRescan & & fPruneMode )
if ( fRescan & & fPruneMode )
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
WalletRescanReserver reserver ( pwallet ) ;
if ( fRescan & & ! reserver . reserve ( ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Wallet is currently rescanning. Abort existing rescan or wait. " ) ;
}
// Whether to import a p2sh version, too
// Whether to import a p2sh version, too
bool fP2SH = false ;
bool fP2SH = false ;
if ( ! request . params [ 3 ] . isNull ( ) )
if ( ! request . params [ 3 ] . isNull ( ) )
fP2SH = request . params [ 3 ] . get_bool ( ) ;
fP2SH = request . params [ 3 ] . get_bool ( ) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
{
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
CTxDestination dest = DecodeDestination ( request . params [ 0 ] . get_str ( ) ) ;
CTxDestination dest = DecodeDestination ( request . params [ 0 ] . get_str ( ) ) ;
if ( IsValidDestination ( dest ) ) {
if ( IsValidDestination ( dest ) ) {
if ( fP2SH ) {
if ( fP2SH ) {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Cannot use the p2sh flag with an address - use a script instead " ) ;
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Cannot use the p2sh flag with an address - use a script instead " ) ;
}
ImportAddress ( pwallet , dest , strLabel ) ;
} else if ( IsHex ( request . params [ 0 ] . get_str ( ) ) ) {
std : : vector < unsigned char > data ( ParseHex ( request . params [ 0 ] . get_str ( ) ) ) ;
ImportScript ( pwallet , CScript ( data . begin ( ) , data . end ( ) ) , strLabel , fP2SH ) ;
} else {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Bitcoin address or script " ) ;
}
}
ImportAddress ( pwallet , dest , strLabel ) ;
} else if ( IsHex ( request . params [ 0 ] . get_str ( ) ) ) {
std : : vector < unsigned char > data ( ParseHex ( request . params [ 0 ] . get_str ( ) ) ) ;
ImportScript ( pwallet , CScript ( data . begin ( ) , data . end ( ) ) , strLabel , fP2SH ) ;
} else {
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Invalid Bitcoin address or script " ) ;
}
}
if ( fRescan )
if ( fRescan )
{
{
pwallet - > RescanFromTime ( TIMESTAMP_MIN , true /* update */ ) ;
pwallet - > RescanFromTime ( TIMESTAMP_MIN , reserver , true /* update */ ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
}
}
@ -406,7 +418,8 @@ UniValue importpubkey(const JSONRPCRequest& request)
" 1. \" pubkey \" (string, required) The hex-encoded public key \n "
" 1. \" pubkey \" (string, required) The hex-encoded public key \n "
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 2. \" label \" (string, optional, default= \" \" ) An optional label \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" 3. rescan (boolean, optional, default=true) Rescan the wallet for transactions \n "
" \n Note: This call can take minutes to complete if rescan is true. \n "
" \n Note: This call can take minutes to complete if rescan is true, during that time, other rpc calls \n "
" may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes. \n "
" \n Examples: \n "
" \n Examples: \n "
" \n Import a public key with rescan \n "
" \n Import a public key with rescan \n "
+ HelpExampleCli ( " importpubkey " , " \" mypubkey \" " ) +
+ HelpExampleCli ( " importpubkey " , " \" mypubkey \" " ) +
@ -429,6 +442,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
if ( fRescan & & fPruneMode )
if ( fRescan & & fPruneMode )
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Rescan is disabled in pruned mode " ) ;
WalletRescanReserver reserver ( pwallet ) ;
if ( fRescan & & ! reserver . reserve ( ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Wallet is currently rescanning. Abort existing rescan or wait. " ) ;
}
if ( ! IsHex ( request . params [ 0 ] . get_str ( ) ) )
if ( ! IsHex ( request . params [ 0 ] . get_str ( ) ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Pubkey must be a hex string " ) ;
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Pubkey must be a hex string " ) ;
std : : vector < unsigned char > data ( ParseHex ( request . params [ 0 ] . get_str ( ) ) ) ;
std : : vector < unsigned char > data ( ParseHex ( request . params [ 0 ] . get_str ( ) ) ) ;
@ -436,17 +454,18 @@ UniValue importpubkey(const JSONRPCRequest& request)
if ( ! pubKey . IsFullyValid ( ) )
if ( ! pubKey . IsFullyValid ( ) )
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Pubkey is not a valid public key " ) ;
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Pubkey is not a valid public key " ) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
{
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
for ( const auto & dest : GetAllDestinationsForKey ( pubKey ) ) {
for ( const auto & dest : GetAllDestinationsForKey ( pubKey ) ) {
ImportAddress ( pwallet , dest , strLabel ) ;
ImportAddress ( pwallet , dest , strLabel ) ;
}
ImportScript ( pwallet , GetScriptForRawPubKey ( pubKey ) , strLabel , false ) ;
pwallet - > LearnAllRelatedScripts ( pubKey ) ;
}
}
ImportScript ( pwallet , GetScriptForRawPubKey ( pubKey ) , strLabel , false ) ;
pwallet - > LearnAllRelatedScripts ( pubKey ) ;
if ( fRescan )
if ( fRescan )
{
{
pwallet - > RescanFromTime ( TIMESTAMP_MIN , true /* update */ ) ;
pwallet - > RescanFromTime ( TIMESTAMP_MIN , reserver , true /* update */ ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
}
}
@ -479,91 +498,98 @@ UniValue importwallet(const JSONRPCRequest& request)
if ( fPruneMode )
if ( fPruneMode )
throw JSONRPCError ( RPC_WALLET_ERROR , " Importing wallets is disabled in pruned mode " ) ;
throw JSONRPCError ( RPC_WALLET_ERROR , " Importing wallets is disabled in pruned mode " ) ;
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
WalletRescanReserver reserver ( pwallet ) ;
if ( ! reserver . reserve ( ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Wallet is currently rescanning. Abort existing rescan or wait. " ) ;
}
EnsureWalletIsUnlocked ( pwallet ) ;
int64_t nTimeBegin = 0 ;
bool fGood = true ;
{
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
std : : ifstream file ;
EnsureWalletIsUnlocked ( pwallet ) ;
file . open ( request . params [ 0 ] . get_str ( ) . c_str ( ) , std : : ios : : in | std : : ios : : ate ) ;
if ( ! file . is_open ( ) )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Cannot open wallet dump file " ) ;
int64_t nTimeBegin = chainActive . Tip ( ) - > GetBlockTime ( ) ;
std : : ifstream file ;
file . open ( request . params [ 0 ] . get_str ( ) . c_str ( ) , std : : ios : : in | std : : ios : : ate ) ;
if ( ! file . is_open ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Cannot open wallet dump file " ) ;
}
nTimeBegin = chainActive . Tip ( ) - > GetBlockTime ( ) ;
bool fGood = true ;
int64_t nFilesize = std : : max ( ( int64_t ) 1 , ( int64_t ) file . tellg ( ) ) ;
file . seekg ( 0 , file . beg ) ;
int64_t nFilesize = std : : max ( ( int64_t ) 1 , ( int64_t ) file . tellg ( ) ) ;
pwallet - > ShowProgress ( _ ( " Importing... " ) , 0 ) ; // show progress dialog in GUI
file . seekg ( 0 , file . beg ) ;
while ( file . good ( ) ) {
pwallet - > ShowProgress ( " " , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( ( double ) file . tellg ( ) / ( double ) nFilesize ) * 100 ) ) ) ) ;
pwallet - > ShowProgress ( _ ( " Importing... " ) , 0 ) ; // show progress dialog in GUI
std : : string line ;
while ( file . good ( ) ) {
std : : getline ( file , line ) ;
pwallet - > ShowProgress ( " " , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( ( double ) file . tellg ( ) / ( double ) nFilesize ) * 100 ) ) ) ) ;
if ( line . empty ( ) | | line [ 0 ] = = ' # ' )
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 ] ) ) {
CKey key = vchSecret . GetKey ( ) ;
CPubKey pubkey = key . GetPubKey ( ) ;
assert ( key . VerifyPubKey ( pubkey ) ) ;
CKeyID keyid = pubkey . GetID ( ) ;
if ( pwallet - > HaveKey ( keyid ) ) {
LogPrintf ( " Skipping import of %s (key already present) \n " , EncodeDestination ( keyid ) ) ;
continue ;
continue ;
}
int64_t nTime = DecodeDumpTime ( vstr [ 1 ] ) ;
std : : vector < std : : string > vstr ;
std : : string strLabel ;
boost : : split ( vstr , line , boost : : is_any_of ( " " ) ) ;
bool fLabel = true ;
if ( vstr . size ( ) < 2 )
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 ;
}
}
LogPrintf ( " Importing %s... \n " , EncodeDestination ( keyid ) ) ;
if ( ! pwallet - > AddKeyPubKey ( key , pubkey ) ) {
fGood = false ;
continue ;
continue ;
CBitcoinSecret vchSecret ;
if ( vchSecret . SetString ( vstr [ 0 ] ) ) {
CKey key = vchSecret . GetKey ( ) ;
CPubKey pubkey = key . GetPubKey ( ) ;
assert ( key . VerifyPubKey ( pubkey ) ) ;
CKeyID keyid = pubkey . GetID ( ) ;
if ( pwallet - > HaveKey ( keyid ) ) {
LogPrintf ( " Skipping import of %s (key already present) \n " , EncodeDestination ( keyid ) ) ;
continue ;
}
int64_t 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 ;
}
}
LogPrintf ( " Importing %s... \n " , EncodeDestination ( keyid ) ) ;
if ( ! pwallet - > AddKeyPubKey ( key , pubkey ) ) {
fGood = false ;
continue ;
}
pwallet - > mapKeyMetadata [ keyid ] . nCreateTime = nTime ;
if ( fLabel )
pwallet - > SetAddressBook ( keyid , strLabel , " receive " ) ;
nTimeBegin = std : : min ( nTimeBegin , nTime ) ;
} else if ( IsHex ( vstr [ 0 ] ) ) {
std : : vector < unsigned char > vData ( ParseHex ( vstr [ 0 ] ) ) ;
CScript script = CScript ( vData . begin ( ) , vData . end ( ) ) ;
if ( pwallet - > HaveCScript ( script ) ) {
LogPrintf ( " Skipping import of %s (script already present) \n " , vstr [ 0 ] ) ;
continue ;
}
if ( ! pwallet - > AddCScript ( script ) ) {
LogPrintf ( " Error importing script %s \n " , vstr [ 0 ] ) ;
fGood = false ;
continue ;
}
int64_t birth_time = DecodeDumpTime ( vstr [ 1 ] ) ;
if ( birth_time > 0 ) {
pwallet - > m_script_metadata [ CScriptID ( script ) ] . nCreateTime = birth_time ;
nTimeBegin = std : : min ( nTimeBegin , birth_time ) ;
}
}
}
pwallet - > mapKeyMetadata [ keyid ] . nCreateTime = nTime ;
if ( fLabel )
pwallet - > SetAddressBook ( keyid , strLabel , " receive " ) ;
nTimeBegin = std : : min ( nTimeBegin , nTime ) ;
} else if ( IsHex ( vstr [ 0 ] ) ) {
std : : vector < unsigned char > vData ( ParseHex ( vstr [ 0 ] ) ) ;
CScript script = CScript ( vData . begin ( ) , vData . end ( ) ) ;
if ( pwallet - > HaveCScript ( script ) ) {
LogPrintf ( " Skipping import of %s (script already present) \n " , vstr [ 0 ] ) ;
continue ;
}
if ( ! pwallet - > AddCScript ( script ) ) {
LogPrintf ( " Error importing script %s \n " , vstr [ 0 ] ) ;
fGood = false ;
continue ;
}
int64_t birth_time = DecodeDumpTime ( vstr [ 1 ] ) ;
if ( birth_time > 0 ) {
pwallet - > m_script_metadata [ CScriptID ( script ) ] . nCreateTime = birth_time ;
nTimeBegin = std : : min ( nTimeBegin , birth_time ) ;
}
}
}
file . close ( ) ;
pwallet - > ShowProgress ( " " , 100 ) ; // hide progress dialog in GUI
pwallet - > UpdateTimeFirstKey ( nTimeBegin ) ;
}
}
file . close ( ) ;
pwallet - > RescanFromTime ( nTimeBegin , reserver , false /* update */ ) ;
pwallet - > ShowProgress ( " " , 100 ) ; // hide progress dialog in GUI
pwallet - > UpdateTimeFirstKey ( nTimeBegin ) ;
pwallet - > RescanFromTime ( nTimeBegin , false /* update */ ) ;
pwallet - > MarkDirty ( ) ;
pwallet - > MarkDirty ( ) ;
if ( ! fGood )
if ( ! fGood )
@ -685,7 +711,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
file < < strprintf ( " # mined on %s \n " , EncodeDumpTime ( chainActive . Tip ( ) - > GetBlockTime ( ) ) ) ;
file < < strprintf ( " # mined on %s \n " , EncodeDumpTime ( chainActive . Tip ( ) - > GetBlockTime ( ) ) ) ;
file < < " \n " ;
file < < " \n " ;
// add the base58check encoded extended master if the wallet uses HD
// add the base58check encoded extended master if the wallet uses HD
CKeyID masterKeyID = pwallet - > GetHDChain ( ) . masterKeyID ;
CKeyID masterKeyID = pwallet - > GetHDChain ( ) . masterKeyID ;
if ( ! masterKeyID . IsNull ( ) )
if ( ! masterKeyID . IsNull ( ) )
{
{
@ -1110,6 +1136,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" { \n "
" { \n "
" \" rescan \" : <false>, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports \n "
" \" rescan \" : <false>, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports \n "
" } \n "
" } \n "
" \n Note: This call can take minutes to complete if rescan is true, during that time, other rpc calls \n "
" may report that the imported keys, addresses or scripts exists but related transactions are still missing. \n "
" \n Examples: \n " +
" \n Examples: \n " +
HelpExampleCli ( " importmulti " , " '[{ \" scriptPubKey \" : { \" address \" : \" <my address> \" }, \" timestamp \" :1455191478 }, "
HelpExampleCli ( " importmulti " , " '[{ \" scriptPubKey \" : { \" address \" : \" <my address> \" }, \" timestamp \" :1455191478 }, "
" { \" scriptPubKey \" : { \" address \" : \" <my 2nd address> \" }, \" label \" : \" example 2 \" , \" timestamp \" : 1455191480 }]' " ) +
" { \" scriptPubKey \" : { \" address \" : \" <my 2nd address> \" }, \" label \" : \" example 2 \" , \" timestamp \" : 1455191480 }]' " ) +
@ -1135,49 +1163,55 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
}
}
}
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
WalletRescanReserver reserver ( pwallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
if ( fRescan & & ! reserver . reserve ( ) ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " Wallet is currently rescanning. Abort existing rescan or wait. " ) ;
// Verify all timestamps are present before importing any keys.
const int64_t now = chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetMedianTimePast ( ) : 0 ;
for ( const UniValue & data : requests . getValues ( ) ) {
GetImportTimestamp ( data , now ) ;
}
}
int64_t now = 0 ;
bool fRunScan = false ;
bool fRunScan = false ;
const int64_t minimumTimestamp = 1 ;
int64_t nLowestTimestamp = 0 ;
int64_t nLowestTimestamp = 0 ;
if ( fRescan & & chainActive . Tip ( ) ) {
nLowestTimestamp = chainActive . Tip ( ) - > GetBlockTime ( ) ;
} else {
fRescan = false ;
}
UniValue response ( UniValue : : VARR ) ;
UniValue response ( UniValue : : VARR ) ;
{
LOCK2 ( cs_main , pwallet - > cs_wallet ) ;
EnsureWalletIsUnlocked ( pwallet ) ;
for ( const UniValue & data : requests . getValues ( ) ) {
// Verify all timestamps are present before importing any keys.
const int64_t timestamp = std : : max ( GetImportTimestamp ( data , now ) , minimumTimestamp ) ;
now = chainActive . Tip ( ) ? chainActive . Tip ( ) - > GetMedianTimePast ( ) : 0 ;
const UniValue result = ProcessImport ( pwallet , data , timestamp ) ;
for ( const UniValue & data : requests . getValues ( ) ) {
response . push_back ( result ) ;
GetImportTimestamp ( data , now ) ;
if ( ! fRescan ) {
continue ;
}
}
// If at least one request was successful then allow rescan.
const int64_t minimumTimestamp = 1 ;
if ( result [ " success " ] . get_bool ( ) ) {
fRunScan = true ;
if ( fRescan & & chainActive . Tip ( ) ) {
nLowestTimestamp = chainActive . Tip ( ) - > GetBlockTime ( ) ;
} else {
fRescan = false ;
}
}
// Get the lowest timestamp.
for ( const UniValue & data : requests . getValues ( ) ) {
if ( timestamp < nLowestTimestamp ) {
const int64_t timestamp = std : : max ( GetImportTimestamp ( data , now ) , minimumTimestamp ) ;
nLowestTimestamp = timestamp ;
const UniValue result = ProcessImport ( pwallet , data , timestamp ) ;
response . push_back ( result ) ;
if ( ! fRescan ) {
continue ;
}
// If at least one request was successful then allow rescan.
if ( result [ " success " ] . get_bool ( ) ) {
fRunScan = true ;
}
// Get the lowest timestamp.
if ( timestamp < nLowestTimestamp ) {
nLowestTimestamp = timestamp ;
}
}
}
}
}
if ( fRescan & & fRunScan & & requests . size ( ) ) {
if ( fRescan & & fRunScan & & requests . size ( ) ) {
int64_t scannedTime = pwallet - > RescanFromTime ( nLowestTimestamp , true /* update */ ) ;
int64_t scannedTime = pwallet - > RescanFromTime ( nLowestTimestamp , reserver , true /* update */ ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
pwallet - > ReacceptWalletTransactions ( ) ;
if ( scannedTime > nLowestTimestamp ) {
if ( scannedTime > nLowestTimestamp ) {