aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorRussell Yanofsky <russ@yanofsky.org>2017-02-03 16:23:13 -0500
committerRussell Yanofsky <russ@yanofsky.org>2017-02-10 15:40:28 -0500
commit442887f27fb5809e72862d4385eba86588bc97d0 (patch)
tree203a8fb48e26aaa644aa5f21c9a3bf92ef886786 /src/wallet
parent02464da5e4aa8c19d4fff3859dcdee822e2af78c (diff)
Require timestamps for importmulti keys
Additionally, accept a "now" timestamp, to allow avoiding rescans for keys which are known never to have been used. Note that the behavior when "now" is specified is slightly different than the previous behavior when no timestamp was specified at all. Previously, when no timestamp was specified, it would avoid rescanning during the importmulti call, but set the key's nCreateTime value to 1, which would not prevent future block reads in later ScanForWalletTransactions calls. With this change, passing a "now" timestamp will set the key's nCreateTime to the current block time instead of 1. Fixes #9491
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp35
1 files changed, 29 insertions, 6 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 7d4ed70ed9..4674c95bfe 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -640,7 +640,8 @@ UniValue dumpwallet(const JSONRPCRequest& request)
}
-UniValue processImport(const UniValue& data) {
+UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
+{
try {
bool success = false;
@@ -659,7 +660,6 @@ UniValue processImport(const UniValue& data) {
const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false;
const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
const string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
- const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > 1 ? data["timestamp"].get_int64() : 1;
bool isScript = scriptPubKey.getType() == UniValue::VSTR;
bool isP2SH = strRedeemScript.length() > 0;
@@ -958,6 +958,20 @@ UniValue processImport(const UniValue& data) {
}
}
+int64_t GetImportTimestamp(const UniValue& data, int64_t now)
+{
+ if (data.exists("timestamp")) {
+ const UniValue& timestamp = data["timestamp"];
+ if (timestamp.isNum()) {
+ return timestamp.get_int64();
+ } else if (timestamp.isStr() && timestamp.get_str() == "now") {
+ return now;
+ }
+ throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
+ }
+ throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
+}
+
UniValue importmulti(const JSONRPCRequest& mainRequest)
{
// clang-format off
@@ -970,13 +984,17 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" [ (array of json objects)\n"
" {\n"
" \"scriptPubKey\": \"<script>\" | { \"address\":\"<address>\" }, (string / json, required) Type of scriptPubKey (string for script, json for address)\n"
+ " \"timestamp\": timestamp | \"now\" , (integer / string, required) Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n"
+ " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
+ " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
+ " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
+ " 0 can be specified to scan the entire blockchain.\n"
" \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
" \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
" \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
" \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
" \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n"
- " \"timestamp\": 1454686740, (integer, optional, default now) Timestamp\n"
" }\n"
" ,...\n"
" ]\n"
@@ -1015,6 +1033,12 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
+ // Verify all timestamps are present before importing any keys.
+ const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetBlockTime() : 0;
+ for (const UniValue& data : requests.getValues()) {
+ GetImportTimestamp(data, now);
+ }
+
bool fRunScan = false;
const int64_t minimumTimestamp = 1;
int64_t nLowestTimestamp = 0;
@@ -1028,7 +1052,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
UniValue response(UniValue::VARR);
BOOST_FOREACH (const UniValue& data, requests.getValues()) {
- const UniValue result = processImport(data);
+ const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
+ const UniValue result = ProcessImport(data, timestamp);
response.push_back(result);
if (!fRescan) {
@@ -1041,8 +1066,6 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
}
// Get the lowest timestamp.
- const int64_t& timestamp = data.exists("timestamp") && data["timestamp"].get_int64() > minimumTimestamp ? data["timestamp"].get_int64() : minimumTimestamp;
-
if (timestamp < nLowestTimestamp) {
nLowestTimestamp = timestamp;
}