[Wallet] Add RPC call “rescanblockchain #7061

pull jonasschnelli wants to merge 2 commits into bitcoin:master from jonasschnelli:2015/11/wallet_rescan_rpc changing 7 files +117 −11
  1. jonasschnelli commented at 3:10 pm on November 19, 2015: contributor

    A RPC rescan command is much more flexible for the following reasons:

    • You can define the start and end-height
    • It can be called during runtime
    • It can work in multiwallet environment
  2. jonasschnelli added the label Wallet on Nov 19, 2015
  3. jonasschnelli added the label RPC on Nov 19, 2015
  4. laanwj commented at 3:14 pm on November 19, 2015: member
    I’d rather have it that the API is such that an explicit rescan is never needed. Wasn’t there some work on a multi-import w/ timestamps?
  5. jonasschnelli commented at 3:19 pm on November 19, 2015: contributor

    Yes. There is a PR (see PR description). I agree that it would be better to avoid rescans at all, although it might be complicated to catch all edge-cases and a manual trigger can help in situations where someone needs to deal with multiple/complex imports (you only want to do one rescan).

    And I think some people will cancel a rescan because they want to do other stuff and/or had not considered that a rescan can take a long time. Afterward calling -rescan (from genesis) is a time consuming option.

  6. laanwj commented at 3:35 pm on November 19, 2015: member

    But manually specifying a block # to rescan from is extremely fragile… it’s very easy to get this wrong.

    Also, rescanning doesn’t interact with pruning which will be more and more common in the future.

  7. gmaxwell commented at 8:29 pm on November 19, 2015: contributor
    @lannwj I thought thats part of what the height parameter here was for– addressing pruning comparability?
  8. petertodd commented at 10:03 pm on November 20, 2015: contributor

    How about we call this rescanfromheight instead, to make it possible to add a rescanfromtime later if users demand? Equally, some kind of RPC call that finds the first block with a nTime after a specific time might be useful here.

    Do we have a way of querying what block # is the oldest non-pruned block?

  9. petertodd commented at 10:04 pm on November 20, 2015: contributor
    It also occurs to me that for this usecase we might instead want to have pruning not happen automatically, but rather be an on-demand thing where the user specifies the oldest time they’re interested in.
  10. gmaxwell commented at 10:44 pm on November 20, 2015: contributor

    So the biggest negative I personally see here is that it furthers this misunderstanding that rescan is some thing users generally need to be doing. Until we added these non-rescan imports a user initiated rescan is something that never should have been needed (and indicated a serious bug we’d like to know about if it was). As a result of the -rescan argument there is now this whole cargo cult of people that rescan every time they’re scarred by a shadow. I hate to further that.

    But I can’t deny how really useful this will be.

  11. petertodd commented at 0:07 am on November 21, 2015: contributor
    @gmaxwell A possible way around that would be to make the rescan check if you have any addresses that haven’t yet been scanned in that range and error out if not. (basically make it say “no rescan needed”)
  12. gmaxwell commented at 10:13 pm on November 22, 2015: contributor
    Hm. this could also take a stop argument, allowing you to scan single blocks or avoid rescan overlap. Also, I think all the wallet re-scanning should traverse its interval backwards– for more instant gratification; though this would dork with the wallet transaction ordering… actually import at all breaks that, I should go talk to luke-jr about that.
  13. in src/wallet/rpcdump.cpp: in 8017237b5b outdated
    537+         pIndexRescan = chainActive.Genesis();
    538+
    539+    //We can't rescan beyond non-pruned blocks, stop and throw an error
    540+    if (fPruneMode)
    541+    {
    542+        if (fPruneMode)
    


    promag commented at 2:07 am on November 23, 2015:
    Remove?

    jonasschnelli commented at 12:07 pm on November 24, 2015:
    Oops. A rebase issue. Thanks for point out. Fixed.
  14. jonasschnelli force-pushed on Nov 24, 2015
  15. pstratem commented at 12:17 pm on November 24, 2015: contributor
    agree with gmaxwell that this should scan a range of blocks
  16. jonasschnelli commented at 12:22 pm on November 24, 2015: contributor
    Agree with the stop parameter. Working on a implementation….
  17. sipa commented at 12:29 pm on November 24, 2015: member
    I would still prefer an approach that imports with birthdate instead of explicit rescanning.
  18. jonasschnelli commented at 3:42 pm on November 24, 2015: contributor

    Added a commit that allows providing a optional parameter with a height where the rescan should stop. @sipa: I agree that rescan height over a key/address birthday would be nice to have (see #6570). But a explicit rescan RPC call can be useful IMO. It’s trivial to maintain and it can save lots of rescan-time on the user side. But agree, it has to be considered as “experts” feature.

    What about implementing a threshold for autodetecting wether the parameter is a blockheight or timestamp (similar to LOCKTIME_THRESHOLD)?

  19. promag commented at 3:57 pm on November 24, 2015: member
    @jonasschnelli see #6570 (comment) regarding your last comment.
  20. GIJensen commented at 6:49 am on December 7, 2015: none
    ACK
  21. mrbandrews commented at 5:59 pm on March 14, 2016: contributor
    If this is still moving forward - I tested it a bit (including pruned mode) and it looks fine to me. One suggestion is to make the start-height a required parameter so that the user specifies “rescanblockchain 1” to scan from genesis. If the start-height is < 1 or higher than current height, throw an error. Otherwise, ACK.
  22. in src/wallet/wallet.cpp: in 5279c98202 outdated
    1086@@ -1084,6 +1087,8 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
    1087                 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
    1088                     ret++;
    1089             }
    1090+            if (pindex == pindexStop)
    


    promag commented at 1:17 pm on May 2, 2016:
    Move to while condition?

    promag commented at 1:19 pm on May 2, 2016:
    Because it’s inclusive?
  23. laanwj added the label Feature on Jun 16, 2016
  24. luke-jr referenced this in commit 0d5247880d on Jun 27, 2016
  25. luke-jr referenced this in commit d94e08f5a8 on Jun 27, 2016
  26. luke-jr referenced this in commit 8c521c7b2a on Jun 28, 2016
  27. jonasschnelli force-pushed on Jul 20, 2016
  28. jonasschnelli commented at 12:58 pm on July 20, 2016: contributor
    Rebased. I think there are still reasons to consider that PR. At the moment, it would really be useful. Even once we have #7551 (importmulti) it could see use cases for rescanblockchain.
  29. sipa commented at 12:53 pm on August 25, 2016: member
    This seems better #7984, but I still prefer not furthering the usage of various rescans. We need APIs that don’t require users to keep track of the concept of rescanning IMHO.
  30. jonasschnelli commented at 12:58 pm on August 25, 2016: contributor
    I agree. Ideally, there will be no need to rescan. But in practice, rescans are sometimes required (I guess everyone who gave some users support has encountered that). IMO a rpc rescan commend with an optional hight is much more flexible then -rescan as a startup argument.
  31. sipa commented at 12:59 pm on August 25, 2016: member
    I think we should work on importmulti instead (or at least an importprivkey that takes a key birthdate as parameter), not on more ways to rescan.
  32. jonasschnelli commented at 1:00 pm on August 25, 2016: contributor

    I think we should work on importmulti instead (or at least an importprivkey that takes a key birthdate as parameter), not on more ways to rescan.

    Yes. I can agree with that.

  33. jonasschnelli commented at 9:29 am on September 14, 2016: contributor
    Another thing where this could be useful is restoring hd wallets
  34. MarcoFalke commented at 11:53 pm on October 29, 2016: member
    Since importmulti #7551 is merged, some use cases are covered by that.
  35. laanwj commented at 2:14 pm on November 2, 2016: member

    I think we should work on importmulti instead (or at least an importprivkey that takes a key birthdate as parameter), not on more ways to rescan.

    Tend to agree. Closing this for now.

  36. laanwj closed this on Nov 2, 2016

  37. jonasschnelli commented at 8:11 pm on December 22, 2016: contributor
    IMO something like that would be very handy if you rescan a HD wallet (old backup). -rescan does not allow direct user feedback IMO rescanning an old HD backup should by default start at the height where we introduces HD (optional down to genesis).
  38. jonasschnelli reopened this on May 24, 2017

  39. jonasschnelli force-pushed on May 24, 2017
  40. jonasschnelli renamed this:
    [Wallet] add rescanblockchain <height> RPC command
    [Wallet] Replace -rescan with a new RPC call "rescanblockchain"
    on May 24, 2017
  41. jonasschnelli commented at 12:40 pm on May 24, 2017: contributor

    Reopened and overhauled. This now does replace the -rescan startup argument with a new RPC call rescanblockchain. The reasons for that are:

    • You can define the start and end-height
    • It can be called during runtime
    • It can work in multiwallet environment

    Using -rescan will cancel the startup with an error referring to the new RPC call.

  42. jonasschnelli force-pushed on May 24, 2017
  43. jonasschnelli force-pushed on May 24, 2017
  44. jonasschnelli force-pushed on May 24, 2017
  45. in src/init.cpp:370 in 6217140cfe outdated
    366@@ -367,7 +367,7 @@ std::string HelpMessage(HelpMessageMode mode)
    367 #ifndef WIN32
    368     strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), BITCOIN_PID_FILENAME));
    369 #endif
    370-    strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -rescan. "
    371+    strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex"
    


    ryanofsky commented at 2:12 pm on May 24, 2017:
    Maybe still worth mentioning that pruning can get in the way of successfully importing wallet keys & rescanning.
  46. in src/wallet/rpcdump.cpp:1164 in 24ee9c8351 outdated
    1159+    if (request.fHelp || request.params.size() > 2)
    1160+        throw std::runtime_error(
    1161+            "rescanblockchain (\"start-height\") (\"stop-height\")\n"
    1162+            "\nRescan the local blockchain for wallet related transactions.\n"
    1163+            "\nArguments:\n"
    1164+            "1. \"start-height\"    (number, optional) blockheight where the rescan should start\n"
    


    ryanofsky commented at 2:19 pm on May 24, 2017:
    Maybe this should take either times or heights like the pruneblockchain RPC: https://github.com/bitcoin/bitcoin/blob/46771514fa86b9a5a0e0af34c1abfa1da22212f7/src/rpc/blockchain.cpp#L838

    jnewbery commented at 4:48 pm on May 24, 2017:
    suggest you change the argument names to startheight and stopheight. No other rpcs use - as word delimiter.

    jonasschnelli commented at 7:12 am on May 25, 2017:
    Indeed. Fixed.
  47. in src/wallet/rpcdump.cpp:1192 in 24ee9c8351 outdated
    1187+        CBlockIndex *block = chainActive.Tip();
    1188+        while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))
    1189+            block = block->pprev;
    1190+
    1191+        if (pIndexStart->nHeight < block->nHeight)
    1192+            throw JSONRPCError(RPC_WALLET_ERROR, "Can't rescan beyond pruned data.");
    


    ryanofsky commented at 2:23 pm on May 24, 2017:
    Might be helpful if error message could mention getblockchaininfo RPC for getting pruned height.

    jonasschnelli commented at 7:12 am on May 25, 2017:
    Fixed.
  48. in src/wallet/rpcdump.cpp:1185 in 24ee9c8351 outdated
    1180+
    1181+    if (!pIndexStart)
    1182+         pIndexStart = chainActive.Genesis();
    1183+
    1184+    //We can't rescan beyond non-pruned blocks, stop and throw an error
    1185+    if (fPruneMode)
    


    ryanofsky commented at 2:25 pm on May 24, 2017:
    Style might need to be updated for this code (moving opening brace to same line here, adding missing braces other lines)

    jonasschnelli commented at 7:12 am on May 25, 2017:
    Fixed.
  49. in doc/man/bitcoind.1:93 in 6217140cfe outdated
    89@@ -90,7 +90,7 @@ Reduce storage requirements by enabling pruning (deleting) of old
    90 blocks. This allows the pruneblockchain RPC to be called to
    91 delete specific blocks, and enables automatic pruning of old
    92 blocks if a target size in MiB is provided. This mode is
    93-incompatible with \fB\-txindex\fR and \fB\-rescan\fR. Warning: Reverting this
    94+incompatible with \fB\-txindex\fR. Warning: Reverting this
    


    ryanofsky commented at 2:26 pm on May 24, 2017:
    I think these files are automatically generated from -help output and could be reverted in the PR.

    jonasschnelli commented at 7:12 am on May 25, 2017:
    Fixed.
  50. in src/wallet/wallet.cpp:3994 in 6217140cfe outdated
    3870@@ -3865,7 +3871,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
    3871     RegisterValidationInterface(walletInstance);
    3872 
    3873     CBlockIndex *pindexRescan = chainActive.Genesis();
    3874-    if (!GetBoolArg("-rescan", false))
    


    ryanofsky commented at 2:31 pm on May 24, 2017:
    Is there any advantage to getting rid of the -rescan option if we still have keep all the rescan logic below? Is there a future cleanup or new feature that will be easier to implement with the option gone?

    jonasschnelli commented at 3:02 pm on May 24, 2017:

    The -rescan option is global while this PR changes it (partially) to per-wallet. Still, -zapwallettx, etc. need to also be moved to per-wallet basis (I don’t know how right now).

    But removing the global -rescan option has to be done sooner or later if we want proper multiwallet.


    ryanofsky commented at 3:18 pm on May 24, 2017:

    But removing the global -rescan option has to be done sooner or later if we want proper multiwallet.

    Do -zapwallettx, etc also need to be removed to support proper multiwallet?


    jonasschnelli commented at 3:40 pm on May 24, 2017:
    IMO Yes. It’s pure db utility. Either we move it to RPC or to a new wallet/db tool.

    jnewbery commented at 4:46 pm on May 24, 2017:

    This is confusing: the if statement requires !needsRescan. Shouldn’t that be the other way around? If needsRescan is true, we should rescan. I think the if statement should be:

    0if (needsRescan || GetBoolArg("-salvagewallet", true) || GetBoolArg("-zapwallettxes", true))
    

    re: zapwallet and salvagewallet. I agree that they should be changed to RPCs for multiwallet.


    jonasschnelli commented at 6:59 am on May 25, 2017:
    No. I don’t think so. If that if statement is true, we load the wallet best block which prevents a complete rescan (so it’s the opposite). So we only load the wallet best block (== no rescan) if needsRescan is false and -salvagewallet and --zapwallettxes` have not been set.

    jnewbery commented at 6:42 pm on May 25, 2017:
    Yes, you’re right.
  51. in src/wallet/wallet.cpp:1598 in 24ee9c8351 outdated
    1511@@ -1508,6 +1512,9 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
    1512             } else {
    1513                 ret = nullptr;
    1514             }
    1515+            if (pindex == pindexStop) {
    


    ryanofsky commented at 2:41 pm on May 24, 2017:
    I don’t understand what the use-case is for the stop argument. Can you describe a scenario where you would want to provide it? I can see how it might have been desirable before there was an abortrescan RPC to break a big scan up into little scans, but I don’t see why you’d want it now.

    jonasschnelli commented at 3:00 pm on May 24, 2017:
    See the discussion about the stop argument: #7061 (comment)
  52. ryanofsky commented at 2:58 pm on May 24, 2017: member

    Should add some test coverage for this. One easy way might be to add a new Rescan.manual enum value here: https://github.com/bitcoin/bitcoin/blob/46771514fa86b9a5a0e0af34c1abfa1da22212f7/test/functional/import-rescan.py#L32, then put

    0if self.rescan == Rescan.manual:
    1    self.node.rescanblockchain()
    

    at the end of the do_import method.

  53. in src/wallet/wallet.cpp:1471 in 6217140cfe outdated
    1467@@ -1468,11 +1468,15 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
    1468  * before CWallet::nTimeFirstKey). Returns null if there is no such range, or
    


    jnewbery commented at 4:39 pm on May 24, 2017:
    nit: update function comment to say that the rescan is up to pindexStop if it is non-null

    jonasschnelli commented at 7:13 am on May 25, 2017:
    Fixed.
  54. in src/wallet/wallet.cpp:1553 in 6217140cfe outdated
    1488@@ -1485,7 +1489,7 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
    1489         while (pindex && nTimeFirstKey && (pindex->GetBlockTime() < (nTimeFirstKey - TIMESTAMP_WINDOW)))
    1490             pindex = chainActive.Next(pindex);
    1491 
    1492-        ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
    1493+        ShowProgress(_("Rescanning..."), 0); // show rescan progress in GUI as dialog or on splashscreen
    


    jnewbery commented at 4:40 pm on May 24, 2017:

    Need to remove more of this comment, so that it just reads:

    // show rescan progress in GUI as dialog


    jonasschnelli commented at 7:00 am on May 25, 2017:
    But can’t it also happens during startup when the GUI will show the progress only in the splash-screen and not in a dialog?
  55. in src/wallet/rpcdump.cpp:1175 in 6217140cfe outdated
    1170+
    1171+    LOCK2(cs_main, pwallet->cs_wallet);
    1172+
    1173+    CBlockIndex *pIndexStart = NULL;
    1174+    CBlockIndex *pIndexStop = NULL;
    1175+    if (request.params.size() > 0 && request.params[0].isNum())
    


    jnewbery commented at 4:51 pm on May 24, 2017:

    This should throw an error if the argument isn’t a number, rather than continue. It should allow the argument to be Null. I think the if test you need is:

    0if (request.params.size() > 0 && !request.params[0].isNull()) {
    
  56. in src/wallet/rpcdump.cpp:1224 in 6217140cfe outdated
    1193+    }
    1194+
    1195+    if (pwallet)
    1196+        pwallet->ScanForWalletTransactions(pIndexStart, pIndexStop, true);
    1197+
    1198+    return NullUniValue;
    


    jnewbery commented at 5:52 pm on May 24, 2017:
    This RPC should return a message to the user if it is successful, eg “Blockchain rescanned from block <hash> height <height> to block <hash> height <height>. <numtx> transactions added to wallet”. Otherwise it’s impossible for the user to know whether the call was successful or not.

    ryanofsky commented at 3:38 pm on July 25, 2017:
    Should at least throw an error this isn’t successful (the ScanForWalletTransactions call will return null on success, otherwise a pointer to the last failing block, so this should be pretty easy).
  57. in src/wallet/rpcdump.cpp:1178 in 6217140cfe outdated
    1173+    CBlockIndex *pIndexStart = NULL;
    1174+    CBlockIndex *pIndexStop = NULL;
    1175+    if (request.params.size() > 0 && request.params[0].isNum())
    1176+        pIndexStart = chainActive[request.params[0].get_int()];
    1177+
    1178+    if (request.params.size() > 1 && request.params[1].isNum())
    


    jnewbery commented at 5:53 pm on May 24, 2017:
    should this return an error if heightstop is lower than heightstart? If heightstop is higher than the tip height?
  58. in src/wallet/db.cpp:168 in 6217140cfe outdated
    166@@ -167,8 +167,8 @@ bool CDB::Recover(const std::string& filename, void *callbackDataIn, bool (*reco
    167     // Call Salvage with fAggressive=true to
    168     // get as much data as possible.
    169     // Rewrite salvaged data to fresh wallet file
    170-    // Set -rescan so any missing transactions will be
    171-    // found.
    172+    // call rescanblockchain (RPC) so any missing
    


    jnewbery commented at 7:02 pm on May 24, 2017:
    I can’t see where rescanblockchain() is being called. Am I missing something?

    jonasschnelli commented at 6:44 am on May 25, 2017:
    It happens outside of this call (somewhere in wallet.cpp). But the comment doesn’t say “It” calls rescanblockchain, it either says “you” can call rescanblockchain().

    jnewbery commented at 6:53 pm on May 25, 2017:

    I don’t understand. The comment is:

    0    // Recovery procedure:
    1    // move wallet file to wallet.timestamp.bak
    2    // Call Salvage with fAggressive=true to
    3    // get as much data as possible.
    4    // Rewrite salvaged data to fresh wallet file
    5    // call rescanblockchain (RPC) so any missing
    6    // transactions will be found.
    

    This function does:

    • move wallet file to wallet.timestamp.bak
    • Call Salvage with fAggressive=true to get as much data as possible.
    • Rewrite salvaged data to fresh wallet file

    but it doesn’t call rescanblockchain, and I can’t see rescanblockchain being called by the callers.


    jonasschnelli commented at 7:24 pm on May 25, 2017:
    Yes. You right. The rescan is not part of the call. But the part that calls CDB::Recover does always call a rescan. But now I got your point. We should refer to ScanForWalletTransactions() instead to rescanblockchain (RPC). Right?

    jnewbery commented at 7:33 pm on May 25, 2017:
    sorry, I’m still not seeing it. You say “the part that calls CDB::Recover does always call a rescan”. Where?

    jonasschnelli commented at 7:36 pm on May 25, 2017:
    It’s confusing. But CDB::Recover only gets calls by setting -salvagewallet which does set -rescan. Maybe I should remove that comment part… I don’t know what’s best because -rescan is currently mentioned there.

    jnewbery commented at 8:42 pm on May 25, 2017:

    ah, makes sense now. Thank you. I wasn’t looking in init.cpp, but now I think I see how this fits together. CWallet::Verify() is called first, which calls CWalletDB::Recover() if -salvagewallet is set. Later in AppInitMain(), we call CWallet::AppInitMain(), which is where the rescan happens if -salvagewallet is set.

    Perhaps change the comment to something like:

    0    // Try to recover the wallet:
    1    // - move wallet file to wallet.timestamp.bak
    2    // - call Salvage with fAggressive=true to get as much data as possible.
    3    // - rewrite salvaged data to fresh wallet file
    4    //
    5    // CWallet::AppInitMain() will later run a full blockchain rescan to find
    6    // any missing transactions.
    
  59. jonasschnelli force-pushed on May 25, 2017
  60. luke-jr referenced this in commit e6e0efb93b on Jun 15, 2017
  61. TheBlueMatt commented at 5:41 pm on July 11, 2017: member
    This needs rebase (probably just wait till after 15 at this point). I think outstanding objections to the idea have all largely been removed, Concept ACK from me, at least.
  62. jonasschnelli force-pushed on Jul 21, 2017
  63. jonasschnelli commented at 7:54 am on July 21, 2017: contributor
    Rebased.
  64. in src/wallet/rpcdump.cpp:1188 in 76e98222cd outdated
    1183+
    1184+    LOCK2(cs_main, pwallet->cs_wallet);
    1185+
    1186+    CBlockIndex *pIndexStart = NULL;
    1187+    CBlockIndex *pIndexStop = NULL;
    1188+    if (request.params.size() > 0 && request.params[0].isNum()) {
    


    ryanofsky commented at 3:24 pm on July 25, 2017:
    Size checks can be dropped here and below. params[0] will return a null value if the param is missing.
  65. in src/wallet/rpcdump.cpp:1203 in 76e98222cd outdated
    1198+    }
    1199+
    1200+    //We can't rescan beyond non-pruned blocks, stop and throw an error
    1201+    if (fPruneMode) {
    1202+        CBlockIndex *block = chainActive.Tip();
    1203+        while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
    


    ryanofsky commented at 3:31 pm on July 25, 2017:
    This should check against pIndexStop too, so error won’t trigger unnecessarily in cases where missing blocks are noncontinuous (which can happen with manual pruning).
  66. in src/wallet/rpcdump.cpp:1176 in 76e98222cd outdated
    1171+    if (request.fHelp || request.params.size() > 2) {
    1172+        throw std::runtime_error(
    1173+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    1174+            "\nRescan the local blockchain for wallet related transactions.\n"
    1175+            "\nArguments:\n"
    1176+            "1. \"startHeight\"    (number, optional) blockheight where the rescan should start\n"
    


    ryanofsky commented at 3:40 pm on July 25, 2017:
    Capitalization of height doesn’t match actual param name.
  67. in src/wallet/rpcdump.cpp:1177 in 76e98222cd outdated
    1172+        throw std::runtime_error(
    1173+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    1174+            "\nRescan the local blockchain for wallet related transactions.\n"
    1175+            "\nArguments:\n"
    1176+            "1. \"startHeight\"    (number, optional) blockheight where the rescan should start\n"
    1177+            "2. \"stopHeight\"     (number, optional) blockheight where the rescan should stop\n"
    


    ryanofsky commented at 3:44 pm on July 25, 2017:
    Could do what pruneblockchain does and allow height to be specified either as a physical height or a time: https://github.com/bitcoin/bitcoin/blob/1caafa6cde3b88d926611771f9b4c06fcc6e0007/src/rpc/blockchain.cpp#L855
  68. ryanofsky commented at 3:54 pm on July 25, 2017: member
    utACK 7858b9fc739bdbf8dc5916fb17a7d44811bbe919, but I would prefer if this just deprecated the -rescan option instead of removing it. Removing it with no warning seems needless and kind of jerky, since it barely saves any code.
  69. promag commented at 9:37 pm on July 27, 2017: member
    If #10941 goes first then the test can be extended to do a rescanblockchain and assert the notified blocks.
  70. luke-jr commented at 6:52 pm on August 11, 2017: member
    Rebased and addressed @ryanofsky ’s comments on my rpc_rescan branch.
  71. jonasschnelli force-pushed on Aug 11, 2017
  72. jonasschnelli commented at 7:14 pm on August 11, 2017: contributor
    Cherry picked @luke-jr rebased / overhauled version. Still needs an RPC test.
  73. in src/wallet/rpcdump.cpp:1174 in 79a11731f3 outdated
    1168+        return NullUniValue;
    1169+    }
    1170+
    1171+    if (request.fHelp || request.params.size() > 2) {
    1172+        throw std::runtime_error(
    1173+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    


    promag commented at 2:07 am on August 12, 2017:
    Remove inner ) (.

    luke-jr commented at 10:52 am on August 12, 2017:
    No… they’re both independently optional.

    promag commented at 10:55 am on August 12, 2017:
    But without named args that’s not possible.

    luke-jr commented at 11:46 am on August 12, 2017:
    Yes it is…

    promag commented at 1:52 pm on August 12, 2017:
    How?

    luke-jr commented at 2:03 pm on August 12, 2017:
    JSON null is equivalent to omitting a parameter.

    promag commented at 2:09 pm on August 12, 2017:
    What I mean is that with bitcoin-cli rescanblockchain 10 10 will always be startheight and to specify only stopheight you have to call bitcoin-cli rescanblockchain null 10, hence stopheight depends on startheight.

    luke-jr commented at 3:27 pm on August 12, 2017:
    Not sure what you’re getting at. Null is omitted.
  74. in src/wallet/rpcdump.cpp:1177 in 79a11731f3 outdated
    1171+    if (request.fHelp || request.params.size() > 2) {
    1172+        throw std::runtime_error(
    1173+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    1174+            "\nRescan the local blockchain for wallet related transactions.\n"
    1175+            "\nArguments:\n"
    1176+            "1. \"startheight\"    (number, optional) blockheight where the rescan should start\n"
    


    promag commented at 2:11 am on August 12, 2017:

    Just start?

    Also, if positive then height, if negative then depth relative to tip. Same for stop.


    jnewbery commented at 9:12 pm on September 12, 2017:

    if positive then height, if negative then depth relative to tip

    In general we don’t like overloading arguments with multiple meanings in this way (I know - I’ve tried to do it myself before and got NACKed.

    The argument names should be changed to start_height and stop_height to follow style guidelines. I know that this PR was opened before the style changes so I won’t suggest that you change variable names, but this is a public interface so it should adhere to the new guidelines.

  75. in src/wallet/rpcdump.cpp:1188 in 79a11731f3 outdated
    1183+
    1184+    LOCK2(cs_main, pwallet->cs_wallet);
    1185+
    1186+    CBlockIndex *pindexStart = NULL;
    1187+    CBlockIndex *pindexStop = NULL;
    1188+    if (request.params[0].isNum()) {
    


    promag commented at 2:14 am on August 12, 2017:
    IMO if (!request.params[0].isNull()) so that get_int throws if invalid value is supplied.
  76. in src/wallet/rpcdump.cpp:1195 in 79a11731f3 outdated
    1190+    }
    1191+    if (!pindexStart) {
    1192+        pindexStart = chainActive.Genesis();
    1193+    }
    1194+
    1195+    if (request.params[1].isNum()) {
    


    promag commented at 2:14 am on August 12, 2017:
    Same as above.
  77. in src/wallet/rpcdump.cpp:1201 in 79a11731f3 outdated
    1196+        pindexStop = chainActive[request.params[1].get_int()];
    1197+    }
    1198+
    1199+    if (pindexStop && pindexStop->nHeight < pindexStart->nHeight) {
    1200+        // Flip the parameters to the expected order
    1201+        CBlockIndex * const tmp = pindexStart;
    


    promag commented at 2:15 am on August 12, 2017:
    Use std::swap?
  78. in src/wallet/rpcdump.cpp:1200 in 79a11731f3 outdated
    1195+    if (request.params[1].isNum()) {
    1196+        pindexStop = chainActive[request.params[1].get_int()];
    1197+    }
    1198+
    1199+    if (pindexStop && pindexStop->nHeight < pindexStart->nHeight) {
    1200+        // Flip the parameters to the expected order
    


    promag commented at 2:16 am on August 12, 2017:
    Should be an error instead?

    luke-jr commented at 10:55 am on August 12, 2017:
    Why?

    promag commented at 10:58 am on August 12, 2017:
    Why would start be greater than stop? Seems to be a bad call?

    luke-jr commented at 11:47 am on August 12, 2017:
    It doesn’t make much less sense to scan backward than to scan forward. We only actually support scanning forward, but the outcome is the same either way.

    promag commented at 1:52 pm on August 12, 2017:
    I see your point :+1:.
  79. in src/wallet/wallet.cpp:1567 in 79a11731f3 outdated
    1553+CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
    1554 {
    1555     int64_t nNow = GetTime();
    1556     const CChainParams& chainParams = Params();
    1557 
    1558+    if (pindexStop && pindexStop->nHeight < pindexStart->nHeight) {
    


    promag commented at 2:19 am on August 12, 2017:
    Should not happen, assert instead?

    jonasschnelli commented at 5:15 pm on October 4, 2017:
    Can happen from the perspective of the function. But maybe not with the current consumption of the function.
  80. in src/wallet/rpcdump.cpp:1209 in 79a11731f3 outdated
    1204+    }
    1205+
    1206+    // We can't rescan beyond non-pruned blocks, stop and throw an error
    1207+    if (fPruneMode) {
    1208+        int nHeight = pindexStart->nHeight;
    1209+        while ((!pindexStop) || nHeight <= pindexStop->nHeight) {
    


    promag commented at 2:25 am on August 12, 2017:
    Correct me if I’m wrong, but if start has BLOCK_HAVE_DATA then the remaining blocks also have, therefore no need to loop?

    luke-jr commented at 10:55 am on August 12, 2017:
    I think this may be currently true, but perhaps not safe to assume for the future. Unsure.

    promag commented at 11:00 am on August 12, 2017:
    Maybe factor out to a CChain function so in the future it’s more contained and for now remove the loop?

    jonasschnelli commented at 11:58 pm on September 5, 2017:
    We loop backwards here which the check is necessary. Or am I wrong?

    promag commented at 0:48 am on September 6, 2017:
    Something is wrong now because nothing changes the the loop exit conditions.
  81. in src/wallet/rpcdump.cpp:1186 in 79a11731f3 outdated
    1181+            );
    1182+    }
    1183+
    1184+    LOCK2(cs_main, pwallet->cs_wallet);
    1185+
    1186+    CBlockIndex *pindexStart = NULL;
    


    promag commented at 2:27 am on August 12, 2017:
    pindex_start?
  82. in src/wallet/rpcdump.cpp:1197 in 79a11731f3 outdated
    1192+        pindexStart = chainActive.Genesis();
    1193+    }
    1194+
    1195+    if (request.params[1].isNum()) {
    1196+        pindexStop = chainActive[request.params[1].get_int()];
    1197+    }
    


    promag commented at 2:28 am on August 12, 2017:
    Maybe we should } else { pindex_stop = chainActive.Tip(); }?

    jonasschnelli commented at 11:59 pm on September 5, 2017:
    The stop height can just be a nullptr (== scan up to the tip).
  83. in src/wallet/rpcdump.cpp:1178 in 79a11731f3 outdated
    1172+        throw std::runtime_error(
    1173+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    1174+            "\nRescan the local blockchain for wallet related transactions.\n"
    1175+            "\nArguments:\n"
    1176+            "1. \"startheight\"    (number, optional) blockheight where the rescan should start\n"
    1177+            "2. \"stopheight\"     (number, optional) blockheight where the rescan should stop\n"
    


    promag commented at 2:30 am on August 12, 2017:
    Note that it’s inclusive?
  84. promag commented at 2:33 am on August 12, 2017: member

    Need to change the progress calculation:

    0         double dProgressTip = GuessVerificationProgress(chainParams.TxData(), chainActive.Tip());
    

    Should rename to dProgressStop.

  85. in src/wallet/rpcdump.cpp:1224 in 79a11731f3 outdated
    1219+
    1220+    if (pwallet) {
    1221+        pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
    1222+    }
    1223+
    1224+    return NullUniValue;
    


    promag commented at 2:18 pm on August 12, 2017:
    Could return the scanned range? Then the client can keep the returned stopheight to be the next startheight.
  86. in src/wallet/rpcdump.cpp:1214 in 79a11731f3 outdated
    1209+        while ((!pindexStop) || nHeight <= pindexStop->nHeight) {
    1210+            CBlockIndex * const block = chainActive[nHeight];
    1211+            if (!block) {
    1212+                break;
    1213+            }
    1214+            if (!(block->pprev->nStatus & BLOCK_HAVE_DATA)) {
    


    promag commented at 10:23 pm on August 12, 2017:

    block->pprev can be nullptr:

    0bitcoind -regtest -prune=1
    1bitcoin-cli -regtest rescanblockchain   <- segfault
    
  87. jonasschnelli renamed this:
    [Wallet] Replace -rescan with a new RPC call "rescanblockchain"
    [Wallet] Add RPC call "rescanblockchain <startheight> <stopheight>"
    on Sep 6, 2017
  88. jonasschnelli force-pushed on Sep 6, 2017
  89. jonasschnelli commented at 0:39 am on September 6, 2017: contributor
    Rebased and overhauled. This no longer evicts the startup -rescan option. Also added a RPC test.
  90. jonasschnelli force-pushed on Sep 6, 2017
  91. meshcollider approved
  92. in src/wallet/rpcdump.cpp:1195 in bf6f25373a outdated
    1190+        pindexStart = chainActive[request.params[0].get_int()];
    1191+        if (!pindexStart) {
    1192+            throw JSONRPCError(RPC_WALLET_ERROR, "Invalid startheight");
    1193+        }
    1194+    }
    1195+    if (!pindexStart) {
    


    jnewbery commented at 9:13 pm on September 12, 2017:
    Why not just assign chainActive.Genesis() to pindexStart when declaring the variable (and then overwrite if !request.params[0].isNull())

    jonasschnelli commented at 4:00 am on September 16, 2017:
    Makes sense. Will update.
  93. in src/wallet/rpcdump.cpp:1188 in bf6f25373a outdated
    1183+    }
    1184+
    1185+    LOCK2(cs_main, pwallet->cs_wallet);
    1186+
    1187+    CBlockIndex *pindexStart = nullptr;
    1188+    CBlockIndex *pindexStop = nullptr;
    


    jnewbery commented at 9:13 pm on September 12, 2017:
    nit: slight preference to declare this variable immediately above the if (!request.params[1].isNull()) code block

    jonasschnelli commented at 3:57 am on September 16, 2017:
    IMO they should be declared / initialised together (for better code readability).
  94. in src/wallet/rpcdump.cpp:1192 in bf6f25373a outdated
    1187+    CBlockIndex *pindexStart = nullptr;
    1188+    CBlockIndex *pindexStop = nullptr;
    1189+    if (!request.params[0].isNull()) {
    1190+        pindexStart = chainActive[request.params[0].get_int()];
    1191+        if (!pindexStart) {
    1192+            throw JSONRPCError(RPC_WALLET_ERROR, "Invalid startheight");
    


    jnewbery commented at 9:14 pm on September 12, 2017:
    This should be RPC_INVALID_PARAMETER, not RPC_WALLET_ERROR
  95. in src/wallet/rpcdump.cpp:1202 in bf6f25373a outdated
    1197+    }
    1198+
    1199+    if (!request.params[1].isNull()) {
    1200+        pindexStop = chainActive[request.params[1].get_int()];
    1201+        if (!pindexStop || pindexStop->nHeight < pindexStart->nHeight) {
    1202+            throw JSONRPCError(RPC_WALLET_ERROR, "Invalid stopheight");
    


    jnewbery commented at 9:14 pm on September 12, 2017:
    As above, this should be RPC_INVALID_PARAMETER, not RPC_WALLET_ERROR

    luke-jr commented at 3:17 pm on September 13, 2017:
    If the heights are inverted, they should be flipped. 100..90 is no less rational than 90..100. This was in 79a11731f3, but seems to have disappeared silently in a rebase?

    jnewbery commented at 3:35 pm on September 13, 2017:
    @luke-jr - do you have a particular use-case for inverting the block heights? If not, I think this is fine as is. We should err towards being more strict in the interface to keep the code simpler.

    luke-jr commented at 4:48 pm on September 13, 2017:

    Already discussed here.

    There’s no reason to have an arbitrary restriction that doesn’t make sense and is undocumented, especially when we can trivially just do the right thing.


    jnewbery commented at 4:55 pm on September 13, 2017:

    ‘The right thing’ is a value judgement. In my opinion, the right thing is to keep APIs as tightly defined as possible in order to keep code simple and remove corner cases.

    Of course, if there’s a legitimate use case, we should allow both, but I don’t see it.


    luke-jr commented at 5:03 am on September 16, 2017:
    The legitimate use case is to rescan the blockchain… There’s no reason why one direction is to be preferred over the other for these arguments.
  96. in src/wallet/rpcdump.cpp:1214 in bf6f25373a outdated
    1209+        while (block) {
    1210+            if (block->nHeight <= pindexStart->nHeight) {
    1211+                break;
    1212+            }
    1213+            if (!(block->nStatus & BLOCK_HAVE_DATA)) {
    1214+                throw JSONRPCError(RPC_WALLET_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
    


    jnewbery commented at 9:16 pm on September 12, 2017:
    This should be RPC_MISC_ERROR. Trying to scan a pruned block is not an error in the wallet.
  97. in src/wallet/rpcdump.cpp:1221 in bf6f25373a outdated
    1216+            block = block->pprev;
    1217+        }
    1218+    }
    1219+
    1220+    CBlockIndex *stopBlock = nullptr;
    1221+    if (pwallet) {
    


    jnewbery commented at 9:20 pm on September 12, 2017:
    why is this required? The call to EnsureWalletIsAvailable() above should ensure that the wallet is available.

    jonasschnelli commented at 4:01 am on September 16, 2017:
    Right… Will remove it. I think this is a rebase issue since the PR is originally from 2015.
  98. in src/wallet/rpcdump.cpp:1230 in bf6f25373a outdated
    1225+            stopBlock = pindexStop ? pindexStop : chainActive.Tip();
    1226+        }
    1227+    }
    1228+
    1229+    UniValue response(UniValue::VOBJ);
    1230+    response.pushKV("startheight", pindexStart->nHeight);
    


    jnewbery commented at 9:21 pm on September 12, 2017:
    These return fields should be documented in the help text.
  99. in src/wallet/wallet.h:922 in bf6f25373a outdated
    918@@ -919,7 +919,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
    919     void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
    920     bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
    921     int64_t RescanFromTime(int64_t startTime, bool update);
    922-    CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
    923+    CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop = nullptr, bool fUpdate = false);
    


    jnewbery commented at 9:23 pm on September 12, 2017:
    It looks like you’ve updated all the calls to ScanForWalletTransactions() to explicitly set pindexStop (except in wallet_tests.cpp). Why not update wallet_tests.cpp and remove the default argument. I think in general it’s best to avoid default arguments if possible.
  100. in test/functional/wallet-hd.py:96 in bf6f25373a outdated
    90@@ -91,6 +91,21 @@ def run_test (self):
    91         self.start_node(1, extra_args=self.extra_args[1] + ['-rescan'])
    92         assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
    93 
    94+        # Try a RPC based rescan
    95+        self.stop_node(1)
    96+        shutil.rmtree(tmpdir + "/node1/regtest/blocks")
    


    jnewbery commented at 9:38 pm on September 12, 2017:

    Really, this should use os.path.join to construct the path, but I see this pattern is used in other tests, so I don’t think you need to change it here.

    Even better would be to move these functions to be methods in the TestNode class - remove_block_files(), remove_chainstate_files(), backup_wallet_file(), restore_wallet_file(), etc.

  101. in test/functional/wallet-hd.py:103 in bf6f25373a outdated
     97+        shutil.rmtree(tmpdir + "/node1/regtest/chainstate")
     98+        shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
     99+        self.start_node(1, extra_args=self.extra_args[1])
    100+        connect_nodes_bi(self.nodes, 0, 1)
    101+        self.sync_all()
    102+        out = self.nodes[1].rescanblockchain(0,1)
    


    jnewbery commented at 9:40 pm on September 12, 2017:
    nit: add a space: (0, 1)
  102. in test/functional/wallet-hd.py:109 in bf6f25373a outdated
    102+        out = self.nodes[1].rescanblockchain(0,1)
    103+        assert_equal(out['startheight'], 0)
    104+        assert_equal(out['stopheight'], 1)
    105+        out = self.nodes[1].rescanblockchain()
    106+        assert_equal(out['startheight'], 0)
    107+        assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
    


    jnewbery commented at 9:42 pm on September 12, 2017:

    Perhaps assert that the rescan scanned up to the tip:

    assert_equal(out['stopheight'], self.nodes[1].getblockcount())

  103. jnewbery commented at 9:43 pm on September 12, 2017: member
    Looks generally good. A few nits inline.
  104. in src/wallet/rpcwallet.cpp:3239 in bf6f25373a outdated
    3235@@ -3235,6 +3236,7 @@ static const CRPCCommand commands[] =
    3236     { "wallet",             "removeprunedfunds",        &removeprunedfunds,        {"txid"} },
    3237 
    3238     { "generating",         "generate",                 &generate,                 {"nblocks","maxtries"} },
    3239+    { "wallet",             "rescanblockchain",         &rescanblockchain,         {"startheight", "stopheight"} },
    


    luke-jr commented at 3:18 pm on September 13, 2017:
    I think this was more appropriately positioned after “removeprunedfunds” as before. Probably after “move” makes the most sense, since it seems to be alphabetised.
  105. luke-jr commented at 3:19 pm on September 13, 2017: member
    Also not sure rpcdump.cpp makes sense for this one.
  106. jonasschnelli force-pushed on Sep 16, 2017
  107. jonasschnelli force-pushed on Sep 16, 2017
  108. jonasschnelli commented at 4:51 am on September 16, 2017: contributor
    Addresses @jnewbery’s points. Agree with @luke-jr that it should be in rpcwallet and not in rpcdump (moved it there).
  109. in src/wallet/rpcwallet.cpp:3204 in 12133020f6 outdated
    3199+    CBlockIndex *pindexStart = chainActive.Genesis();
    3200+    CBlockIndex *pindexStop = nullptr;
    3201+    if (!request.params[0].isNull()) {
    3202+        pindexStart = chainActive[request.params[0].get_int()];
    3203+        if (!pindexStart) {
    3204+            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid startheight");
    


    kallewoof commented at 6:48 am on September 28, 2017:
    μNit: start_height since you’re calling it that in the help.
  110. in src/wallet/rpcwallet.cpp:3211 in 12133020f6 outdated
    3206+    }
    3207+
    3208+    if (!request.params[1].isNull()) {
    3209+        pindexStop = chainActive[request.params[1].get_int()];
    3210+        if (!pindexStop || pindexStop->nHeight < pindexStart->nHeight) {
    3211+            throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stopheight");
    


    kallewoof commented at 6:49 am on September 28, 2017:
    μNit: stop_height
  111. in src/wallet/rpcwallet.cpp:3220 in 12133020f6 outdated
    3212+        }
    3213+    }
    3214+
    3215+    // We can't rescan beyond non-pruned blocks, stop and throw an error
    3216+    if (fPruneMode) {
    3217+        CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
    


    kallewoof commented at 6:49 am on September 28, 2017:
    Can be abbreviated to CBlockIndex *block = pindexStop ?: chainActive.Tip();

    jonasschnelli commented at 4:33 am on October 1, 2017:
    Fixed.
  112. in src/wallet/rpcwallet.cpp:3221 in 12133020f6 outdated
    3216+    if (fPruneMode) {
    3217+        CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
    3218+        while (block) {
    3219+            if (block->nHeight <= pindexStart->nHeight) {
    3220+                break;
    3221+            }
    


    kallewoof commented at 6:51 am on September 28, 2017:
    Why not just while (block && block->nHeight > pindexStart->nHeight) {?

    jonasschnelli commented at 4:33 am on October 1, 2017:
    Fixed.
  113. in src/wallet/rpcwallet.cpp:3235 in 12133020f6 outdated
    3228+
    3229+    CBlockIndex *stopBlock = nullptr;
    3230+    stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
    3231+    if (!stopBlock) {
    3232+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    3233+        stopBlock = pindexStop ? pindexStop : chainActive.Tip();
    


    kallewoof commented at 6:53 am on September 28, 2017:
    Same as above here; stopBlock = pindexStop ?: chainActive.Tip();

    jonasschnelli commented at 4:33 am on October 1, 2017:
    Fixed.
  114. in src/wallet/wallet.h:922 in 12133020f6 outdated
    918@@ -919,7 +919,7 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
    919     void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
    920     bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
    921     int64_t RescanFromTime(int64_t startTime, bool update);
    922-    CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
    923+    CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
    


    kallewoof commented at 6:55 am on September 28, 2017:
    CBlockIndex* pindexStop = nullptr will let existing code default to current behavior (mostly in the test cases in wallet/test/wallet_tests.cpp).

    jonasschnelli commented at 4:27 am on October 1, 2017:
    Heh. I had it before but then @jnewbery convinced me to remove it: #7061 (review)
  115. kallewoof approved
  116. kallewoof commented at 6:57 am on September 28, 2017: member

    utACK fe471a9d5a0ac7b10765f99dae0741410f85804d

    Did not look at test code yet.

  117. jonasschnelli force-pushed on Oct 1, 2017
  118. jonasschnelli commented at 4:34 am on October 1, 2017: contributor
    Adressed @kallewoof’s points.
  119. in src/wallet/rpcwallet.cpp:3181 in 9b34215467 outdated
    3176+        return NullUniValue;
    3177+    }
    3178+
    3179+    if (request.fHelp || request.params.size() > 2) {
    3180+        throw std::runtime_error(
    3181+            "rescanblockchain (\"startheight\") (\"stopheight\")\n"
    


    kallewoof commented at 4:48 am on October 1, 2017:
    I missed this last time: start_height and stop_height here to match the rest.

    jonasschnelli commented at 4:51 am on October 1, 2017:
    Fixed.
  120. kallewoof approved
  121. kallewoof commented at 4:49 am on October 1, 2017: member
    utACK 6a51097090cda330a9d83be61be28baed8b0f11d
  122. jonasschnelli force-pushed on Oct 1, 2017
  123. kallewoof approved
  124. kallewoof commented at 4:56 am on October 1, 2017: member
    re-utACK e2d376b376c4861d90ee1a9c52933abb3cbbd03b
  125. in src/wallet/rpcwallet.cpp:3188 in e2d376b376 outdated
    3183+            "\nArguments:\n"
    3184+            "1. \"start_height\"    (number, optional) block height where the rescan should start\n"
    3185+            "2. \"stop_height\"     (number, optional) block height where the rescan should stop\n"
    3186+            "\nResult:\n"
    3187+            "{\n"
    3188+            "  \"start_height\" :   (number) The block height where the rescan has started\n"
    


    promag commented at 9:56 pm on October 1, 2017:
    Nit, remove space before :.
  126. promag commented at 10:02 pm on October 1, 2017: member

    utACK e2d376b.

    Will test tomorrow. While there’s few ACK’s why not update variables to snake case?

  127. in src/wallet/rpcwallet.cpp:3184 in e2d376b376 outdated
    3179+    if (request.fHelp || request.params.size() > 2) {
    3180+        throw std::runtime_error(
    3181+            "rescanblockchain (\"start_height\") (\"stop_height\")\n"
    3182+            "\nRescan the local blockchain for wallet related transactions.\n"
    3183+            "\nArguments:\n"
    3184+            "1. \"start_height\"    (number, optional) block height where the rescan should start\n"
    


    jnewbery commented at 5:16 pm on October 2, 2017:
    nit: add “If omitted, rescan starts from the genesis block.”

    meshcollider commented at 9:34 am on October 5, 2017:
    Or just default=0
  128. in src/wallet/rpcwallet.cpp:3185 in e2d376b376 outdated
    3180+        throw std::runtime_error(
    3181+            "rescanblockchain (\"start_height\") (\"stop_height\")\n"
    3182+            "\nRescan the local blockchain for wallet related transactions.\n"
    3183+            "\nArguments:\n"
    3184+            "1. \"start_height\"    (number, optional) block height where the rescan should start\n"
    3185+            "2. \"stop_height\"     (number, optional) block height where the rescan should stop\n"
    


    jnewbery commented at 5:16 pm on October 2, 2017:
    nit: add “If omitted, rescan stops at the chain tip.”

    JeremyRubin commented at 3:44 pm on October 4, 2017:

    Please specify if the scan stops before or after this block.

    I think semantically it makes more sense to provide an inclusive range (if I say “scan blocks 10-20”, not scanning 20 seems confusing).

    If you really want an exclusive range, providing the number of blocks to scan (e.g., “scan 10 blocks starting at 10”) has better ux, but still worse than inclusive.

  129. in src/wallet/rpcwallet.cpp:3234 in e2d376b376 outdated
    3224+    }
    3225+
    3226+    CBlockIndex *stopBlock = nullptr;
    3227+    stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
    3228+    if (!stopBlock) {
    3229+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    


    jnewbery commented at 5:25 pm on October 2, 2017:

    minor bug: sadly, the comment about the return value for ScanForWalletTransactions() added in #10208 is incomplete. If abortrescan is called during a rescan, then ScanForWalletTransactions() will return nullptr even if the though scan didn’t complete successfully to the tip (or requested pindexStop after this PR)

    I think the only way to correctly return the status of the rescan would be to have more information passed back by ScanForWalletTransactions().

    (Test this by running rescanblockchain in one window and calling abortrescan in a different window. rescanblockchain returns the requested stop_height even though the rescan didn’t extend that far). @ryanofsky since he changed the semantics of ScanForWalletTransactions() in #10208.


    jonasschnelli commented at 3:34 am on October 4, 2017:
    Nice catch… added a protection that detects aborted rescans via a check of CWallet::IsAbortingRescan() after ScanForWalletTransactions().

    jnewbery commented at 2:07 pm on October 4, 2017:

    Seems like a good pragmatic change. There’s a (pathological) race condition where another thread starts a rescan and resets fAbortRescan before this RPC returns, but that’s extremely unlikely.

    I still think it would be nice to have ScanForWalletTransactions() give a more meaningful return value that indicates whether the rescan was aborted. The same bug exists in importmulti where RescanFromTime() will return the wrong time value if the rescan is aborted. However, that fix can be for another PR.

  130. jnewbery commented at 5:25 pm on October 2, 2017: member
    2 nits and a minor bug
  131. jonasschnelli force-pushed on Oct 4, 2017
  132. jonasschnelli commented at 3:34 am on October 4, 2017: contributor
    Fixed @jnewbery and @promag’s nits.
  133. in test/functional/wallet-hd.py:13 in bdae58ebcd outdated
     9@@ -10,6 +10,7 @@
    10     connect_nodes_bi,
    11 )
    12 import shutil
    13+import os
    


    jnewbery commented at 2:09 pm on October 4, 2017:

    nit: please sort imports :)

    and ideally place them in PEP8 ordering (ie standard library before project imports)

  134. jnewbery commented at 2:15 pm on October 4, 2017: member
    Looks good. One style nit, but ACK bdae58ebcd274629bc57f790ef3e1c9e13e1c91f with or without.
  135. in src/wallet/rpcwallet.cpp:3226 in bdae58ebcd outdated
    3221+            }
    3222+            block = block->pprev;
    3223+        }
    3224+    }
    3225+
    3226+    CBlockIndex *stopBlock = nullptr;
    


    promag commented at 2:32 pm on October 4, 2017:
    Join this with next line.
  136. in src/wallet/rpcwallet.cpp:3233 in bdae58ebcd outdated
    3228+    if (!stopBlock) {
    3229+        if (pwallet->IsAbortingRescan()) {
    3230+            throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
    3231+        }
    3232+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    3233+        stopBlock = pindexStop ?: chainActive.Tip();
    


    promag commented at 2:33 pm on October 4, 2017:
    Avoid this GNU extension (empty operand)?

    promag commented at 2:43 pm on October 4, 2017:
    BTW, first time in this source code.

    kallewoof commented at 3:06 pm on October 4, 2017:
    I did not know a ?: b was a GNU extension. Sorry for bad nit earlier. :(

    jonasschnelli commented at 5:52 pm on October 4, 2017:
    Fixed.
  137. in src/wallet/rpcwallet.cpp:3234 in bdae58ebcd outdated
    3227+    stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
    3228+    if (!stopBlock) {
    3229+        if (pwallet->IsAbortingRescan()) {
    3230+            throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
    3231+        }
    3232+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    


    promag commented at 2:38 pm on October 4, 2017:

    This is wrong, from ScanForWalletTransactions doc:

    Returns null if scan was successful. Otherwise, if a complete rescan was not possible (due to pruning or corruption), returns pointer to the most recent block that could not be scanned.

    So it can return a non nullptr but catch transactions further in the chain. It only stops rescanning when abortrescan RPC is called.


    promag commented at 2:42 pm on October 4, 2017:
    Maybe we should add the most recent block that could not be scanned to the response.

    jonasschnelli commented at 5:07 pm on October 4, 2017:
    It’s not correct, right. I think we leave that fix for another PR (not directly related to this PR).
  138. in src/wallet/rpcwallet.cpp:3210 in bdae58ebcd outdated
    3205+        }
    3206+    }
    3207+
    3208+    if (!request.params[1].isNull()) {
    3209+        pindexStop = chainActive[request.params[1].get_int()];
    3210+        if (!pindexStop || pindexStop->nHeight < pindexStart->nHeight) {
    


    JeremyRubin commented at 3:15 pm on October 4, 2017:

    I think with this (and with the above pindexStart check), I’d like to see these errors differentiate between:

    1. Invalid Start Height: no negative heights
    2. Invalid Start Height: Beyond what’s been synced
    3. Invalid Stop Height: No negative heights
    4. Invalid Stop Height: Beyond what’s been synced
    5. Invalid Range: stop must be greater than start.

    At the very least, 5. should be represented because it could be the start_height which is invalid.


    jonasschnelli commented at 5:52 pm on October 4, 2017:
    Added case 5.
  139. in src/wallet/rpcwallet.cpp:3223 in bdae58ebcd outdated
    3215+    // We can't rescan beyond non-pruned blocks, stop and throw an error
    3216+    if (fPruneMode) {
    3217+        CBlockIndex *block = pindexStop ?: chainActive.Tip();
    3218+        while (block && block->nHeight > pindexStart->nHeight) {
    3219+            if (!(block->nStatus & BLOCK_HAVE_DATA)) {
    3220+                throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
    


    JeremyRubin commented at 3:27 pm on October 4, 2017:

    There is a race condition for using getblockchaininfo RPC call if a new block comes in, unless you can pause pruning.

    Maybe worth just documenting to retry until there is a pruning pause feature.

  140. in src/wallet/rpcwallet.cpp:3188 in bdae58ebcd outdated
    3183+            "\nArguments:\n"
    3184+            "1. \"start_height\"    (number, optional) block height where the rescan should start\n"
    3185+            "2. \"stop_height\"     (number, optional) block height where the rescan should stop\n"
    3186+            "\nResult:\n"
    3187+            "{\n"
    3188+            "  \"start_height\"     (number) The block height where the rescan has started. If omitted, rescan starts from the genesis block.\n"
    


    JeremyRubin commented at 3:30 pm on October 4, 2017:
    tense error s/start/started
  141. in src/wallet/rpcwallet.cpp:3189 in bdae58ebcd outdated
    3184+            "1. \"start_height\"    (number, optional) block height where the rescan should start\n"
    3185+            "2. \"stop_height\"     (number, optional) block height where the rescan should stop\n"
    3186+            "\nResult:\n"
    3187+            "{\n"
    3188+            "  \"start_height\"     (number) The block height where the rescan has started. If omitted, rescan starts from the genesis block.\n"
    3189+            "  \"stop_height\"      (number) The height of the last rescanned block. If omitted, rescan stops at the chain tip.\n"
    


    JeremyRubin commented at 3:30 pm on October 4, 2017:
    tense error s/stops/stopped

    JeremyRubin commented at 3:41 pm on October 4, 2017:
    This is not accurate AFAICT. The block at stop_height is not scanned?

    jonasschnelli commented at 5:33 pm on October 4, 2017:
    AFAIK the block defined with stop_height will be scanned.
  142. in src/wallet/rpcwallet.cpp:3242 in bdae58ebcd outdated
    3232+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    3233+        stopBlock = pindexStop ?: chainActive.Tip();
    3234+    }
    3235+
    3236+    UniValue response(UniValue::VOBJ);
    3237+    response.pushKV("start_height", pindexStart->nHeight);
    


    JeremyRubin commented at 3:34 pm on October 4, 2017:
    If no blocks are re scanned, I don’t think this is correct/is confusing.
  143. in src/wallet/rpcwallet.cpp:3243 in bdae58ebcd outdated
    3233+        stopBlock = pindexStop ?: chainActive.Tip();
    3234+    }
    3235+
    3236+    UniValue response(UniValue::VOBJ);
    3237+    response.pushKV("start_height", pindexStart->nHeight);
    3238+    response.pushKV("stop_height", stopBlock->nHeight);
    


    JeremyRubin commented at 3:36 pm on October 4, 2017:

    According to the ScanForWalletTransactions docs…

    * Returns null if scan was successful. Otherwise, if a complete rescan was not
    * possible (due to pruning or corruption), returns pointer to the most recent
    * block that could not be scanned.
    

    So with the current returned value it should be nHeight-1.

  144. JeremyRubin changes_requested
  145. JeremyRubin commented at 3:53 pm on October 4, 2017: contributor

    Concept Ack.

    However, the handling of the ranges is incorrect afaict and needs to be corrected (and better documented).

  146. jonasschnelli commented at 5:31 pm on October 4, 2017: contributor
    @JeremyRubin the current implementation does scan the block defined with the stop_height parameter. I’ll update the parameter documentation to make this more clear.
  147. jonasschnelli force-pushed on Oct 4, 2017
  148. jonasschnelli commented at 5:55 pm on October 4, 2017: contributor

    I think the range handling is correct but change the RPC help to \"stop_height\" (number, optional) the last block height that should be scanned.

    Reverted the conditional ?: op abbreviation due to the fact that this requires a GNU extension.

    The fix for the misleading return value of ScanForWalletTransaction and comment (#11450) should be handled outside of this PR.

  149. in src/wallet/wallet.cpp:1559 in 53e5d8a7f7 outdated
    1554@@ -1555,12 +1555,19 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
    1555  * Returns null if scan was successful. Otherwise, if a complete rescan was not
    1556  * possible (due to pruning or corruption), returns pointer to the most recent
    1557  * block that could not be scanned.
    1558+ *
    1559+ * If pindexStop is not a nullptr, the scan will stop one block after the block-index
    


    JeremyRubin commented at 7:55 pm on October 4, 2017:

    I think this is clearest to say:

    If pindexStop is not a nullptr, we attempt to scan up to and including pIndexStop.
    
  150. JeremyRubin changes_requested
  151. JeremyRubin commented at 8:05 pm on October 4, 2017: contributor

    Ok. Let’s say that we say run

     rescanblockchain { start_height: 10, stop_height: 20 }
    

    then in ScanForWalletTransactions, we fail at 20.

    We will return

    { start_height: 10, stop_height: 20 }
    

    which isn’t true, because we failed to scan 20.

    This is also true if we fail, at say, 15.

    We will return

    { start_height: 10, stop_height: 15 }
    

    Which is also not true because we didn’t scan 15.

  152. JeremyRubin commented at 8:07 pm on October 4, 2017: contributor
    Also, more generally, it seems we could fail to scan many blocks in the range and still return that we scanned the range.
  153. jonasschnelli commented at 8:15 pm on October 4, 2017: contributor
    @JeremyRubin: Why do you think rescanblockchain { start_height: 10, stop_height: 20 } would not scan block at height 20? I just re-checked, re-tested and it looks like it does scan block 20.
  154. jonasschnelli force-pushed on Oct 4, 2017
  155. jonasschnelli force-pushed on Oct 4, 2017
  156. jonasschnelli commented at 8:59 pm on October 4, 2017: contributor

    I understand @JeremyRubin concern now. It’s about corrupted blocks (when ReadBlockFromDisk fails). The current startup -rescans do sort of tolerate this.

    Added a fix that now leads to an error thrown when detecting a corrupted block (https://github.com/bitcoin/bitcoin/pull/7061/files#diff-df7d84ff2f53fcb2a0dc15a3a51e55ceR3237)

  157. jtimon commented at 2:22 am on October 5, 2017: contributor

    Concept ACK. This seem like moving in the right direction, even if in the long term we want to avoid the need for rescans completely.

    This now does replace the -rescan startup argument with a new RPC call rescanblockchain.

    I don’t see this in the code. Shouldn’t we at least deprecate the startup argument at the same time? (I would not oppose to directly remove it as an exception to the general policy instead of waiting for 0.17). Perhaps note in the release notes that this is also supposed to be temporary.

  158. jonasschnelli commented at 3:26 am on October 5, 2017: contributor

    This now does replace the -rescan startup argument with a new RPC call rescanblockchain.

    I don’t see this in the code. Shouldn’t we at least deprecate the startup argument at the same time? (I would not oppose to directly remove it as an exception to the general policy instead of waiting for 0.17). Perhaps note in the release notes that this is also supposed to be temporary.

    This was removed from the PRs description (but not from a later comment, now added a strike-through attr.)

  159. promag commented at 9:17 am on October 5, 2017: member

    IMO this is ready to merge even though there are some concerns that need to be addressed in follow ups:

    • Rescan continues even if a corrupted block is detected but the RPC fails to the caller;
    • rescanblockchain can be refactored a little to avoid the cs_main and cs_wallet locks;

    I also would like to discuss the option to make this RPC asynchronous so the caller doesn’t wait for the rescan to complete, it only asks for a rescan. There is a big chance the caller interrupts the call, but I believe in server side the rescan continues.

    utACK 559542a.

  160. in src/wallet/rpcwallet.cpp:3238 in 559542a57b outdated
    3233+        }
    3234+        // if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
    3235+        stopBlock = pindexStop ? pindexStop : chainActive.Tip();
    3236+    }
    3237+    else {
    3238+        throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corruputed data files.");
    


    meshcollider commented at 9:33 am on October 5, 2017:
    Typo corruputed -> corrupted
  161. in src/wallet/rpcwallet.cpp:3192 in 559542a57b outdated
    3187+            "{\n"
    3188+            "  \"start_height\"     (number) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
    3189+            "  \"stop_height\"      (number) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
    3190+            "}\n"
    3191+            "\nExamples:\n"
    3192+            + HelpExampleCli("rescanblockchain", "\"100000 120000\"")
    


    meshcollider commented at 9:40 am on October 5, 2017:
    These quotes look wrong, should both start and stop height be surrounded in the same string? As numbers should they even have quotes around them? HelpExampleRpc should also have commas between the arguments I believe Small nit, number -> numeric in the lines above to be consistent with other calls
  162. meshcollider commented at 9:44 am on October 5, 2017: contributor
  163. jonasschnelli force-pushed on Oct 9, 2017
  164. jonasschnelli added the label Needs release notes on Oct 9, 2017
  165. jonasschnelli commented at 7:51 pm on October 9, 2017: contributor
    Fixed @MeshCollider nits.
  166. JeremyRubin commented at 10:07 pm on October 9, 2017: contributor

    I still think it’s worth it to handle

    1. Invalid Start Height: no negative heights
    2. Invalid Stop Height: No negative heights

    and

    1. Invalid Start Height: Beyond what’s been synced
    2. Invalid Stop Height: Beyond what’s been synced

    differently. Specifically, the latter calls could still be handled and processed.

  167. jnewbery commented at 2:19 pm on October 10, 2017: member

    Tested ACK 35e7fd1147c64a286f778c7740fa735a16d448c5

    I still think it’s worth it to handle … differently.

    These already fail with Invalid start_height and Invalid stop_height. Yes, we can always provide more detailed error messages or logging, but lets not hold this PR up on that. It’s already been very heavily reviewed.

    I’ll happily review follow-up PRs if you want to change error logging.

  168. in src/wallet/rpcwallet.cpp:3193 in 35e7fd1147 outdated
    3188+            "  \"start_height\"     (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
    3189+            "  \"stop_height\"      (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
    3190+            "}\n"
    3191+            "\nExamples:\n"
    3192+            + HelpExampleCli("rescanblockchain", "100000 120000")
    3193+            + HelpExampleRpc("rescanblockchain", "100000 120000")
    


    meshcollider commented at 6:13 pm on October 10, 2017:
    I think the HelpExampleRpc should have a comma between the arguments, i.e. a comma after 100000 Yeah would be good to get this merged, sorry for yet another nit :)
  169. in src/wallet/rpcwallet.cpp:3312 in 35e7fd1147 outdated
    3308@@ -3233,6 +3309,7 @@ static const CRPCCommand commands[] =
    3309     { "wallet",             "walletpassphrasechange",   &walletpassphrasechange,   {"oldpassphrase","newpassphrase"} },
    3310     { "wallet",             "walletpassphrase",         &walletpassphrase,         {"passphrase","timeout"} },
    3311     { "wallet",             "removeprunedfunds",        &removeprunedfunds,        {"txid"} },
    3312+    { "wallet",             "rescanblockchain",         &rescanblockchain,         {"start_height", "stop_height"} },
    


    kallewoof commented at 1:31 am on October 11, 2017:
    Very tiny nit, but every other place skips the space between words in argument list. I.e. {"start_height","stop_height"}.
  170. kallewoof approved
  171. kallewoof commented at 1:31 am on October 11, 2017: member
    re-utACK 35e7fd1147c64a286f778c7740fa735a16d448c5
  172. JeremyRubin commented at 7:32 am on October 12, 2017: contributor

    @jnewbery to be clear

    1. I don’t think it’s fair to say it was heavily reviewed and I’m needlessly holding it up, I found a major bug in the implementation which required a (imo) pretty significant change to the semantics of the return value.

    2. I’m not suggesting a change in error reporting, I am suggesting a functional change to the ranges which are handled by this call. Specifically, I would like for the cases where

      1. Invalid Start Height: Beyond what’s been synced
      2. Invalid Stop Height: Beyond what’s been synced

    to not throw an error and return a successful scan range (if possible).

  173. jnewbery commented at 12:26 pm on October 12, 2017: member

    @JeremyRubin - sorry if that came off as a personal criticism. That’s not what I meant. This PR was re-opened in December last year and has been reviewed by 9 people so far. It’s very useful functionality and it’d be great to see it merged. And yes - you did catch a subtle bug in your review which the rest of us missed. Thank you!

    re: your suggested change to the interface - if start_height is beyond what’s been sync’ed, then there’s nothing to rescan and we should return an error to make it clear to the user that the call was a no-op. If stop_height is beyond the sync height, then it’s safer to return an error and let the user call the method again with a valid stop_height. If the call succeeded then a user who’s not paying close attention to the return value may incorrectly assume that the wallet is rescanned up to the requested stop_height.

  174. in src/wallet/rpcwallet.cpp:3221 in 35e7fd1147 outdated
    3216+    }
    3217+
    3218+    // We can't rescan beyond non-pruned blocks, stop and throw an error
    3219+    if (fPruneMode) {
    3220+        CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
    3221+        while (block && block->nHeight > pindexStart->nHeight) {
    


    ryanofsky commented at 3:43 pm on October 12, 2017:
    Should this be >=? Otherwise it won’t check the start block. Maybe add comment if there’s a special reason for skipping the start block.
  175. ryanofsky commented at 3:56 pm on October 12, 2017: member

    I haven’t followed most of the review conversation, but would give light conditional utACK for 35e7fd1147c64a286f778c7740fa735a16d448c5 if >= comment below is addressed.

    I like @JeremyRubin’s suggestion of avoiding errors when rescans are requested beyond the synced range, but it seems like that could easily be added in a followup.

  176. [Wallet] add rescanblockchain <start_height> <stop_height> RPC command c77170fbdb
  177. [QA] Add RPC based rescan test 7a91ceb5e0
  178. jonasschnelli force-pushed on Oct 12, 2017
  179. jonasschnelli commented at 7:00 pm on October 12, 2017: contributor
    Fixed @ryanofsky points with the >= check. Lets merge this now,… I think the ranges cleanup (if we want to do this) could be PRed by @JeremyRubin after this PR.
  180. ryanofsky commented at 7:59 pm on October 12, 2017: member
    utACK 7a91ceb5e0c9d29dddf7b6ae4cbba802b790924c. Only change since last review was >= fix
  181. jonasschnelli merged this on Oct 13, 2017
  182. jonasschnelli closed this on Oct 13, 2017

  183. jonasschnelli referenced this in commit 8c2de827e9 on Oct 13, 2017
  184. jnewbery commented at 11:01 pm on October 13, 2017: member
    🎉
  185. jonasschnelli referenced this in commit 2c66cea2d1 on Oct 16, 2017
  186. luke-jr referenced this in commit c5ceb0ded7 on Nov 6, 2017
  187. luke-jr referenced this in commit 3855eed9f5 on Nov 6, 2017
  188. luke-jr referenced this in commit 4377f2da4e on Nov 6, 2017
  189. MarcoFalke removed the label Needs release notes on Mar 23, 2018
  190. MarcoFalke referenced this in commit 04226f8706 on Jan 30, 2019
  191. PastaPastaPasta referenced this in commit 9e3481d8b0 on Dec 22, 2019
  192. PastaPastaPasta referenced this in commit 8c900b0ac4 on Dec 22, 2019
  193. PastaPastaPasta referenced this in commit 715a755779 on Jan 2, 2020
  194. PastaPastaPasta referenced this in commit db2ad507f8 on Jan 2, 2020
  195. PastaPastaPasta referenced this in commit aa58ba9895 on Jan 4, 2020
  196. PastaPastaPasta referenced this in commit 9a909c6136 on Jan 4, 2020
  197. PastaPastaPasta referenced this in commit 24be16b484 on Jan 12, 2020
  198. PastaPastaPasta referenced this in commit 5c5edcae19 on Jan 12, 2020
  199. PastaPastaPasta referenced this in commit 4f220fcaa5 on Jan 12, 2020
  200. PastaPastaPasta referenced this in commit ec551312fc on Jan 12, 2020
  201. PastaPastaPasta referenced this in commit b917b2e9e5 on Jan 12, 2020
  202. PastaPastaPasta referenced this in commit 7105357126 on Jan 12, 2020
  203. PastaPastaPasta referenced this in commit 2dce4e531a on Jan 12, 2020
  204. PastaPastaPasta referenced this in commit 3245c28778 on Jan 12, 2020
  205. PastaPastaPasta referenced this in commit f5e4d80dc2 on Jan 12, 2020
  206. PastaPastaPasta referenced this in commit a6057dfece on Jan 12, 2020
  207. PastaPastaPasta referenced this in commit d044efa394 on Jan 12, 2020
  208. PastaPastaPasta referenced this in commit 4b700ae329 on Jan 12, 2020
  209. PastaPastaPasta referenced this in commit 93ebbc866e on Jan 16, 2020
  210. PastaPastaPasta referenced this in commit 4b200baf35 on Jan 16, 2020
  211. ckti referenced this in commit 4febea7142 on Mar 28, 2021
  212. ckti referenced this in commit 59c595fa58 on Mar 28, 2021
  213. random-zebra referenced this in commit db2057e5ee on Apr 4, 2021
  214. gades referenced this in commit c4078f96da on Jun 30, 2021
  215. Munkybooty referenced this in commit ad34d67319 on Aug 21, 2021
  216. Munkybooty referenced this in commit 8e2a2aac53 on Aug 23, 2021
  217. Munkybooty referenced this in commit 5367671054 on Aug 24, 2021
  218. Munkybooty referenced this in commit 68c722f867 on Aug 24, 2021
  219. Munkybooty referenced this in commit fcd4c15ad6 on Aug 24, 2021
  220. UdjinM6 referenced this in commit 6cc03c0e81 on Aug 24, 2021
  221. Munkybooty referenced this in commit 9b233fbc4c on Aug 24, 2021
  222. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-10-30 00:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me