Wrong `time` when importing transactions with `rescanblockchain ` RPC command #20181

issue ben-kaufman opened this issue on October 18, 2020
  1. ben-kaufman commented at 6:02 PM on October 18, 2020: contributor

    When using the rescanblockchain wallet RPC command, it seems like sometimes (though not always, and I couldn't find a specific pattern for when this does and doesn't happen) the time field of all transactions found is being set to the time of the most recent transaction detected. Besides that field, all data (including block and blocktime) return correctly. What's more, even in a node with txindex=1 this happens, despite that when calling the (non-wallet-specific) getrawtransaction command, it returns the correct time.

    Here's an example of a testnet transaction where I experienced this behaviour, and the output of Core where the same txid has. 2 different times - a correct one using getrawtransaction and an incorrect one using gettransaction:

    bitcoin-cli --testnet -rpcwallet=wallet getrawtransaction 8bacfc9c63d181e9d303f57f550fe72870afd640c961466829c6212bb23a72fe 1
    {
      "txid": "8bacfc9c63d181e9d303f57f550fe72870afd640c961466829c6212bb23a72fe",
      "hash": "3de22064b8fec52fb183a8ad46fd011e6c6cab9906a008afa3d649d11bd250f1",
      "version": 2,
      "size": 222,
      "vsize": 141,
      "weight": 561,
      "locktime": 0,
      "vin": [
        {
          "txid": "685571776adce2ac3332faf6ed125235366cc3cb464604c9234bf371f1ab4e02",
          "vout": 0,
          "scriptSig": {
            "asm": "",
            "hex": ""
          },
          "txinwitness": [
            "30440220516d0b313aae44f639a111dac8f27bc1fac446345aaad51852a784620ac62c690220433cb7fdeb78cd84574ec0ddd08789a248fe19b71759e1b3b448ff9c3f980be401",
            "03eca8ceb44c4d930ab89fb5d721d02a745e4aeb0f75993fa535e98fb6c7f6e16e"
          ],
          "sequence": 4294967294
        }
      ],
      "vout": [
        {
          "value": 0.53891045,
          "n": 0,
          "scriptPubKey": {
            "asm": "0 f3020d45a9ccf870ddf4176fde4420931ffd9af6",
            "hex": "0014f3020d45a9ccf870ddf4176fde4420931ffd9af6",
            "reqSigs": 1,
            "type": "witness_v0_keyhash",
            "addresses": [
              "tb1q7vpq63dfenu8ph05zahau3pqjv0lmxhk73dsjm"
            ]
          }
        },
        {
          "value": 0.10000000,
          "n": 1,
          "scriptPubKey": {
            "asm": "0 bf702bf755da860153e7b1043fea160c6dcd9f1a",
            "hex": "0014bf702bf755da860153e7b1043fea160c6dcd9f1a",
            "reqSigs": 1,
            "type": "witness_v0_keyhash",
            "addresses": [
              "tb1qhaczha64m2rqz5l8kyzrl6skp3kum8c6m0c2h4"
            ]
          }
        }
      ],
      "hex": "02000000000101024eabf171f34b23c9044646cbc36c36355212edf6fa3233ace2dc6a777155680000000000feffffff02e54f360300000000160014f3020d45a9ccf870ddf4176fde4420931ffd9af68096980000000000160014bf702bf755da860153e7b1043fea160c6dcd9f1a024730440220516d0b313aae44f639a111dac8f27bc1fac446345aaad51852a784620ac62c690220433cb7fdeb78cd84574ec0ddd08789a248fe19b71759e1b3b448ff9c3f980be4012103eca8ceb44c4d930ab89fb5d721d02a745e4aeb0f75993fa535e98fb6c7f6e16e00000000",
      "blockhash": "00000000000000bc3b97cbe323c4695f39a65cc1d73060dca8ad084fb0ce61b5",
      "confirmations": 27528,
      "time": 1600623861,
      "blocktime": 1600623861
    }
    
    bitcoin-cli --testnet -rpcwallet=wallet gettransaction 8bacfc9c63d181e9d303f57f550fe72870afd640c961466829c6212bb23a72fe
    {
      "amount": -0.10000000,
      "fee": -0.00000142,
      "confirmations": 27528,
      "blockhash": "00000000000000bc3b97cbe323c4695f39a65cc1d73060dca8ad084fb0ce61b5",
      "blockheight": 1835261,
      "blockindex": 24,
      "blocktime": 1600623861,
      "txid": "8bacfc9c63d181e9d303f57f550fe72870afd640c961466829c6212bb23a72fe",
      "walletconflicts": [
      ],
      "time": 1601486746,
      "timereceived": 1602570577,
      "bip125-replaceable": "no",
      "details": [
        {
          "involvesWatchonly": true,
          "address": "tb1q7vpq63dfenu8ph05zahau3pqjv0lmxhk73dsjm",
          "category": "send",
          "amount": -0.53891045,
          "label": "Change [#5](/bitcoin-bitcoin/5/)",
          "vout": 0,
          "fee": -0.00000142,
          "abandoned": false
        },
        {
          "involvesWatchonly": true,
          "address": "tb1qhaczha64m2rqz5l8kyzrl6skp3kum8c6m0c2h4",
          "category": "send",
          "amount": -0.10000000,
          "vout": 1,
          "fee": -0.00000142,
          "abandoned": false
        },
        {
          "involvesWatchonly": true,
          "address": "tb1q7vpq63dfenu8ph05zahau3pqjv0lmxhk73dsjm",
          "category": "receive",
          "amount": 0.53891045,
          "label": "Change [#5](/bitcoin-bitcoin/5/)",
          "vout": 0
        }
      ],
      "hex": "02000000000101024eabf171f34b23c9044646cbc36c36355212edf6fa3233ace2dc6a777155680000000000feffffff02e54f360300000000160014f3020d45a9ccf870ddf4176fde4420931ffd9af68096980000000000160014bf702bf755da860153e7b1043fea160c6dcd9f1a024730440220516d0b313aae44f639a111dac8f27bc1fac446345aaad51852a784620ac62c690220433cb7fdeb78cd84574ec0ddd08789a248fe19b71759e1b3b448ff9c3f980be4012103eca8ceb44c4d930ab89fb5d721d02a745e4aeb0f75993fa535e98fb6c7f6e16e00000000"
    }
    
  2. ben-kaufman added the label Bug on Oct 18, 2020
  3. ghost commented at 10:21 PM on October 18, 2020: none

    time in getrawtransaction is same as block time

    "blocktime" : xxx, (numeric) The block time expressed in UNIX epoch time "time" : n (numeric) Same as "blocktime"

    There are 3 different variables for time in results of gettransaction

    "blocktime" : xxx, (numeric) The block time expressed in UNIX epoch time. "txid" : "hex", (string) The transaction id. "walletconflicts" : [ (json array) Conflicting transaction ids. "hex", (string) The transaction id. ... ], "time" : xxx, (numeric) The transaction time expressed in UNIX epoch time. "timereceived" : xxx, (numeric) The time received expressed in UNIX epoch time.

  4. ben-kaufman commented at 3:38 PM on October 25, 2020: contributor

    Thanks, right, so I see this explains the getrawtransaction time. Still, this doesn't explain the issue that all imported transactions after rescan have the time of the most recent transaction detected.

  5. BitcoinTsunami commented at 5:22 PM on December 2, 2020: none

    As a specter user, I had the same problem with multiple incorrect date across several wallet.

    I've look at the Bitcoin Core code and the function ComputeSmartTime in wallet.cpp attire my attention. The algorithm try to search for the best time between the received one, the block time one and a smart one wich is produced by a lot of time corrections. This ComputeSmartTime method is conceived with a real time approach in mind. The technique used to determine the smart version of the time is based on the hypothesis that you can't discover transactions in the wrong order. And if you suppose that transcations can be discovered in the wrong order, the lastestEntry variable is going to be wrong for every transactions discovered after and be the exact same date. That's exactly what I saw in my Bitcoin Core wallet, a lot of transactions with the exact same date, which is incorrect.

    I've not found yet a simple example where transactions could be dicovered in the wrong order, but I'm looking for a case where you start with a small rescan and after a larger one. To be more precise : if you rescan only the latest part of the history (2020 year only), and proceed to a larger rescan after (full rescan), every transaction before 2020 will be noted in 2020 du to the lastEntry constraint in nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));

    When you think about it, in a rescanning scenario, the blocktime is the only exploitable time. The received one means nothing and you can't find a better value.

    That's why I've patched the problem like this :

    add a rescanning_old_block boolean to ComputeSmartTime In case of rescanning_old_block don't use anything else than blocktime. propagate this boolean in the methods hierarchy to differenciate realtime incoming transactions with rescanning case. I'm currently testing my patch. Tests cases stay all green. If everything is repaired in my wallets, I'll submit this little patch in another comment to get feedback on it.

  6. BitcoinTsunami commented at 8:37 AM on December 3, 2020: none

    I've test this approach on Bitcoin Core v0.21rc2. My transactions dates in my wallets are now correct with the attached patch. This won't fix transactions with previously incorrect date determination, but it prevent bad datation in the first place during a rescanning process. This patch as no impact on ComputeTimeSmart usage outside rescanning process: realtime flow are not affected.

    I'll now try to look at the way specter interract with Bitcoin Core API, because this bug is systematic in my wallet case with Specter v0.10.0 and Bitcoin Core (v0.20.1 or v0.21.0rc2).

    I'm pretty sure that the first rescan extecuted by specter is smaller that the next one. As I suggested in my first message, it may be a smaller timeframe first, then a bigger one. But it could also be a smaller address range first (100 first wallets adress), then a bigger range (1000 first). That way transactions may be discovered in wrong order too, because nothing impose to consume addresses in the naturel order of the HD wallet.

    Date: Thu, 3 Dec 2020 08:39:33 +0100
    Subject: [PATCH] fix incorrect transaction date during rescanning
    
    ---
     src/wallet/wallet.cpp | 22 +++++++++++++---------
     src/wallet/wallet.h   |  8 ++++----
     2 files changed, 17 insertions(+), 13 deletions(-)
    
    diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
    index ff8bfff87..1aa1b44df 100644
    --- a/src/wallet/wallet.cpp
    +++ b/src/wallet/wallet.cpp
    @@ -842,7 +842,7 @@ bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const
         return false;
     }
     
    -CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose)
    +CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx, bool fFlushOnClose, bool rescanning_old_block)
     {
         LOCK(cs_wallet);
     
    @@ -872,7 +872,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
             wtx.nTimeReceived = chain().getAdjustedTime();
             wtx.nOrderPos = IncOrderPosNext(&batch);
             wtx.m_it_wtxOrdered = wtxOrdered.insert(std::make_pair(wtx.nOrderPos, &wtx));
    -        wtx.nTimeSmart = ComputeTimeSmart(wtx);
    +        wtx.nTimeSmart = ComputeTimeSmart(wtx, rescanning_old_block);
             AddToSpends(hash);
         }
     
    @@ -980,7 +980,7 @@ bool CWallet::LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx
         return true;
     }
     
    -bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate)
    +bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool fUpdate, bool rescanning_old_block)
     {
         const CTransaction& tx = *ptx;
         {
    @@ -1018,7 +1018,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co
     
                 // Block disconnection override an abandoned tx as unconfirmed
                 // which means user may have to call abandontransaction again
    -            return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false);
    +            return AddToWallet(MakeTransactionRef(tx), confirm, /* update_wtx= */ nullptr, /* fFlushOnClose= */ false, rescanning_old_block);
             }
         }
         return false;
    @@ -1147,9 +1147,9 @@ void CWallet::MarkConflicted(const uint256& hashBlock, int conflicting_height, c
         }
     }
     
    -void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool update_tx)
    +void CWallet::SyncTransaction(const CTransactionRef& ptx, CWalletTx::Confirmation confirm, bool update_tx, bool rescanning_old_block)
     {
    -    if (!AddToWalletIfInvolvingMe(ptx, confirm, update_tx))
    +    if (!AddToWalletIfInvolvingMe(ptx, confirm, update_tx, rescanning_old_block))
             return; // Not one of ours
     
         // If a transaction changes 'conflicted' state, that changes the balance
    @@ -1788,7 +1788,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
                     break;
                 }
                 for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
    -                SyncTransaction(block.vtx[posInBlock], {CWalletTx::Status::CONFIRMED, block_height, block_hash, (int)posInBlock}, fUpdate);
    +                SyncTransaction(block.vtx[posInBlock], {CWalletTx::Status::CONFIRMED, block_height, block_hash, (int)posInBlock}, fUpdate, true /* rescanning_old_block */);
                 }
                 // scan succeeded, record block as most recent successfully scanned
                 result.last_scanned_block = block_hash;
    @@ -3679,7 +3679,7 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
      * https://bitcointalk.org/?topic=54527, or
      * [#1393](/bitcoin-bitcoin/1393/).
      */
    -unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
    +unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const
     {
         unsigned int nTimeSmart = wtx.nTimeReceived;
         if (!wtx.isUnconfirmed() && !wtx.isAbandoned()) {
    @@ -3710,7 +3710,11 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
                     }
                 }
     
    -            nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
    +            if(!rescanning_old_block) {
    +                nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
    +            } else {
    +                nTimeSmart = blocktime;
    +            }
             } else {
                 WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.m_confirm.hashBlock.ToString());
             }
    diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
    index 69cf6b66a..c1695e870 100644
    --- a/src/wallet/wallet.h
    +++ b/src/wallet/wallet.h
    @@ -664,7 +664,7 @@ private:
          * Abandoned state should probably be more carefully tracked via different
          * posInBlock signals or by checking mempool presence when necessary.
          */
    -    bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool fUpdate) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    +    bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool fUpdate, bool rescanning_old_block) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     
         /* Mark a transaction (and its in-wallet descendants) as conflicting with a particular block. */
         void MarkConflicted(const uint256& hashBlock, int conflicting_height, const uint256& hashTx);
    @@ -676,7 +676,7 @@ private:
     
         /* Used by TransactionAddedToMemorypool/BlockConnected/Disconnected/ScanForWalletTransactions.
          * Should be called with non-zero block_hash and posInBlock if this is for a transaction that is included in a block. */
    -    void SyncTransaction(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool update_tx = true) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    +    void SyncTransaction(const CTransactionRef& tx, CWalletTx::Confirmation confirm, bool update_tx = true, bool rescanning_old_block = false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
     
         std::atomic<uint64_t> m_wallet_flags{0};
     
    @@ -876,7 +876,7 @@ public:
         bool EncryptWallet(const SecureString& strWalletPassphrase);
     
         void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
    -    unsigned int ComputeTimeSmart(const CWalletTx& wtx) const;
    +    unsigned int ComputeTimeSmart(const CWalletTx& wtx, bool rescanning_old_block) const;
     
         /**
          * Increment the next transaction order id
    @@ -895,7 +895,7 @@ public:
         //! [@return](/bitcoin-bitcoin/contributor/return/) true if wtx is changed and needs to be saved to disk, otherwise false
         using UpdateWalletTxFn = std::function<bool(CWalletTx& wtx, bool new_tx)>;
     
    -    CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true);
    +    CWalletTx* AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation& confirm, const UpdateWalletTxFn& update_wtx=nullptr, bool fFlushOnClose=true, bool rescanning_old_block=false);
         bool LoadToWallet(const uint256& hash, const UpdateWalletTxFn& fill_wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
         void transactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override;
         void blockConnected(const CBlock& block, int height) override;
    -- 
    2.24.3 (Apple Git-128)
    
    
    
  7. BitcoinTsunami commented at 12:14 AM on December 5, 2020: none

    I've work on a functional test to show the problem. This test restore a watch only wallet with 3 pubkey and show the incorrect behavior of ComputeTimeSmart in case of a limited first rescan, and then a complete rescan. This test failed ont 0.21.0rc2 and pass after the patch I've posted previously.

    #!/usr/bin/env python3
    # Copyright (c) 2018-2019 The Bitcoin Core developers
    # Distributed under the MIT software license, see the accompanying
    # file COPYING or http://www.opensource.org/licenses/mit-license.php.
    """Test transaction time rescan.
    """
    
    from test_framework.test_framework import BitcoinTestFramework
    from test_framework.util import (
        assert_equal,
        assert_raises_rpc_error
    )
    
    
    class TransactionTimeRescanTest(BitcoinTestFramework):
        def set_test_params(self):
            self.setup_clean_chain = False
            self.num_nodes = 3
    
        def skip_test_if_missing_module(self):
            self.skip_if_no_wallet()
    
        def run_test(self):
            self.log.info('Prepare nodes and wallet')
    
            minernode = self.nodes[0] # node used to mine BTC and create transactions
            usernode = self.nodes[1] # reference node with correct time
            restorenode = self.nodes[2] # node used to restore reference wallet and demonstrate bug during time determination in ComputeSmartTime (wallet.cpp)
    
            #time constant
            mocktime = 1525107225
            ten_days = 10 * 24 * 60 * 60
    
            #synchronize nodes and time
            self.sync_all()
            minernode.setmocktime(mocktime)
            usernode.setmocktime(mocktime)
            restorenode.setmocktime(mocktime)
    
            #prepare miner wallet
            minernode.createwallet(wallet_name='default')
            miner_wallet = minernode.get_wallet_rpc('default')
            m1 = miner_wallet.getnewaddress()
    
            #prepare the reference wallet with 3 public key
            wo1 = 'bcrt1qqvs4h9g5kemwu8zdffv3c9tm3dm2qp9uzlxwzx'
            wo2 = 'bcrt1qnw7peeq89hwrg674zjf4phzzluld798p667q7q'
            wo3 = 'bcrt1qdr36v724uddf50jhnju3amzap2gmmt9tf4aac5'
    
            usernode.createwallet(wallet_name='wo', disable_private_keys=True)
            wo_wallet = usernode.get_wallet_rpc('wo')
    
            wo_wallet.importpubkey(pubkey='02f8802962c2ca756d8961c719f75bdfff2b6dbb775788ed54a68bcb182c0ea1ef')
            wo_wallet.importpubkey(pubkey='0330f4a96800a38fa0a49cde4b5f802e95a0c1044e5954389a8d00cecde01b842b')
            wo_wallet.importpubkey(pubkey='02f5ccbee49546e0b5bf2e76422ed959e983dafaa94c8abafc9c8f8b99ef23d16a')
    
            self.log.info('Start transactions')
            assert_equal(minernode.getblockcount(), 200)
    
            # generate some btc to create transactions and check blockcount
            minernode.generatetoaddress(300, m1)
            assert_equal(minernode.getblockcount(), 500)
    
            #synchronize nodes and time
            self.sync_all()
            minernode.setmocktime(mocktime + ten_days)
            usernode.setmocktime(mocktime + ten_days)
            restorenode.setmocktime(mocktime + ten_days)
            # send 10 btc to user first watch-only address
            self.log.info('Send 10 btc to user')
            txid1 = miner_wallet.sendtoaddress(wo1, 10)
            
            # generate blocks and check blockcount
            minernode.generatetoaddress(100, m1)
            assert_equal(minernode.getblockcount(), 600)
    
            #synchronize nodes and time
            self.sync_all()
            minernode.setmocktime(mocktime + ten_days + ten_days)
            usernode.setmocktime(mocktime + ten_days + ten_days)
            restorenode.setmocktime(mocktime + ten_days + ten_days)
            # send 5 btc to our second watch-only address
            self.log.info('Send 5 btc to user')
            txid2 = miner_wallet.sendtoaddress(wo2, 5)
            
            # generate blocks and check blockcount
            minernode.generatetoaddress(100, m1)
            assert_equal(minernode.getblockcount(), 700)
    
            #synchronize nodes and time
            self.sync_all()
            minernode.setmocktime(mocktime + ten_days + ten_days + ten_days)
            usernode.setmocktime(mocktime + ten_days + ten_days + ten_days)
            restorenode.setmocktime(mocktime + ten_days + ten_days + ten_days)
            # send 1 btc to our third watch-only address
            self.log.info('Send 1 btc to user')
            txid3 = miner_wallet.sendtoaddress(wo3, 1)
            
            # generate more blocks and check blockcount
            minernode.generatetoaddress(100, m1)
            assert_equal(minernode.getblockcount(), 800)
    
            # getbalance
            self.log.info('Check final user balance')
            assert_equal(wo_wallet.getbalance(), 16)
            assert_equal(len(wo_wallet.listtransactions()), 3)
    
            for tx in wo_wallet.listtransactions():
                if tx['address'] == 'bcrt1qqvs4h9g5kemwu8zdffv3c9tm3dm2qp9uzlxwzx':
                    assert_equal(tx['blocktime'], 1525971225)
                    assert_equal(tx['time'], 1525971225)
                elif tx['address'] == 'bcrt1qnw7peeq89hwrg674zjf4phzzluld798p667q7q':
                    assert_equal(tx['blocktime'], 1526835225)
                    assert_equal(tx['time'], 1526835225)
                elif tx['address'] == 'bcrt1qdr36v724uddf50jhnju3amzap2gmmt9tf4aac5':
                    assert_equal(tx['blocktime'], 1527699225)
                    assert_equal(tx['time'], 1527699225)
    
            self.log.info('Restore user wallet on another node without rescan')
            restorenode.createwallet(wallet_name='wo', disable_private_keys=True, )
            restorewo_wallet = restorenode.get_wallet_rpc('wo')
    
            restorewo_wallet.importpubkey(pubkey='02f8802962c2ca756d8961c719f75bdfff2b6dbb775788ed54a68bcb182c0ea1ef', rescan=False)
            restorewo_wallet.importpubkey(pubkey='0330f4a96800a38fa0a49cde4b5f802e95a0c1044e5954389a8d00cecde01b842b', rescan=False)
            restorewo_wallet.importpubkey(pubkey='02f5ccbee49546e0b5bf2e76422ed959e983dafaa94c8abafc9c8f8b99ef23d16a', rescan=False)
    
            assert_equal(restorewo_wallet.getbalance(), 0)
            assert_equal(len(restorewo_wallet.listtransactions()), 0)
    
            self.log.info('Rescan last history part')
            restorewo_wallet.rescanblockchain(650)
            self.log.info('Rescan all history')
            restorewo_wallet.rescanblockchain()
    
            self.log.info('Check final user balance after restoration')
            assert_equal(restorewo_wallet.getbalance(), 16)
            assert_equal(len(restorewo_wallet.listtransactions()), 3)
    
            for tx in restorewo_wallet.listtransactions():
                if tx['address'] == 'bcrt1qqvs4h9g5kemwu8zdffv3c9tm3dm2qp9uzlxwzx':
                    assert_equal(tx['blocktime'], 1525971225)
                    assert_equal(tx['time'], 1525971225) #current version return incorrect 1527699225
                elif tx['address'] == 'bcrt1qnw7peeq89hwrg674zjf4phzzluld798p667q7q':
                    assert_equal(tx['blocktime'], 1526835225)
                    assert_equal(tx['time'], 1526835225) #current version return incorrect 1527699225
                elif tx['address'] == 'bcrt1qdr36v724uddf50jhnju3amzap2gmmt9tf4aac5':
                    assert_equal(tx['blocktime'], 1527699225)
                    assert_equal(tx['time'], 1527699225)
    
    
    if __name__ == '__main__':
        TransactionTimeRescanTest().main()
    
    
  8. jonasschnelli commented at 8:34 AM on December 7, 2020: contributor

    @BitcoinTsunami: thanks for the investigation! Would you mind opening a pull request?

  9. BitcoinTsunami referenced this in commit 6622746ea9 on Dec 7, 2020
  10. BitcoinTsunami referenced this in commit 3efe74bfba on Dec 7, 2020
  11. BitcoinTsunami referenced this in commit 9946ec9a29 on Dec 7, 2020
  12. BitcoinTsunami referenced this in commit c663adf52d on Dec 7, 2020
  13. BitcoinTsunami commented at 3:32 PM on December 7, 2020: none

    @jonasschnelli : I'm nearly ready to open a pull request. Can I open it against v0.21.0rc2 or should I rebase it against another target ?

  14. jonatack commented at 3:38 PM on December 7, 2020: member

    I'm nearly ready to open a pull request. Can I open it against v0.21.0rc2 or should I rebase it against another target ?

    Unless it fixes an issue specific to 0.21 only, open it against master. If merged it can be backported to 0.21, if needed.

  15. BitcoinTsunami commented at 3:40 PM on December 7, 2020: none

    Thanks I'll do that.

  16. BitcoinTsunami referenced this in commit d5f05dab91 on Dec 7, 2020
  17. BitcoinTsunami referenced this in commit 4997a2ea5f on Dec 7, 2020
  18. meshcollider closed this on Sep 28, 2021

  19. sidhujag referenced this in commit 89faa29cfa on Sep 28, 2021
  20. DrahtBot locked this on Oct 30, 2022

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: 2026-04-21 18:14 UTC

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