Change setKeyPool to hold flexible entries #10238

pull jonasschnelli wants to merge 1 commits into bitcoin:master from jonasschnelli:2017/04/keypool_fix_a changing 2 files +35 −24
  1. jonasschnelli commented at 1:41 pm on April 20, 2017: contributor

    Currently, we keep only keypool indexes (a int64_t) in memory. If we need the CKeyID of a keypool key (or if we need to know if it’s an internal key), we need to load the whole CKeyPool entry from the database.

    This PR will change the in-memory set entries from int64_t to KeypoolCache. This essentially allows us to efficiently scan the CKeyIDs of our keypool which is almost a pre-requirement if we want to have an efficient HD rescan (otherwise we would have to load the complete key pool each time we found an IsMine or IsFromMe tx).

    There are no direct performance optimisations implemented in this PR.

  2. jonasschnelli added the label Wallet on Apr 20, 2017
  3. jonasschnelli force-pushed on Apr 20, 2017
  4. in src/wallet/wallet.h:699 in a4ed0d712b outdated
    699@@ -700,7 +700,16 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
    700 
    701     bool fFileBacked;
    702 
    703-    std::set<int64_t> setKeyPool;
    


    ryanofsky commented at 5:24 pm on May 1, 2017:
    I think it would be more straightforward to replace setKeyPool with a std::map<int64_t, CKeyID> instead of taking this approach which basically emulates a map using set entries with a custom < operator.

    jonasschnelli commented at 12:42 pm on May 4, 2017:
    Yes. But IMO holding a flexible data-structure (KeypoolCache) allows us to be more flexible in future. Though no strong opinion.

    ryanofsky commented at 7:28 pm on May 4, 2017:

    holding a flexible data-structure (KeypoolCache) allows us to be more flexible in future

    I don’t have any problem with keeping KeypoolCache if it will be useful later.

    What seems bad to me is using std::set with a custom comparison function to emulate a map. Would suggest removing nIndex and operator< from KeypoolCache and using std::map<int64_t, KeypoolCache>


    jonasschnelli commented at 7:37 pm on May 4, 2017:
    Fair point. The question is should we do it in this PR or later. But since we significant change the set’s content, It should be changed now (which I will do soon).
  5. in src/wallet/wallet.h:704 in a4ed0d712b outdated
    699@@ -700,7 +700,16 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
    700 
    701     bool fFileBacked;
    702 
    703-    std::set<int64_t> setKeyPool;
    704+    // class for holding a keypool-key-entry in memory
    705+    class KeypoolCache {
    706+    public:
    707+        int64_t nIndex;
    708+        CKeyID keyId;
    


    ryanofsky commented at 5:37 pm on May 1, 2017:
    Note: keyId member is not actually used anywhere in this PR. (Fine, just pointing out to help review).

    jonasschnelli commented at 12:35 pm on May 4, 2017:
    Yes. This is true, though, the keyId is relatively important for future performance improvements. We could add it later,.. but I guess it doesn’t hurt to already have it there in this PR.
  6. paveljanik commented at 6:35 am on May 4, 2017: contributor
    Rebase needed.
  7. jonasschnelli force-pushed on May 4, 2017
  8. jonasschnelli commented at 12:42 pm on May 4, 2017: contributor
    Rebased.
  9. in src/wallet/wallet.h:699 in 2e614359d5 outdated
    695@@ -696,7 +696,18 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
    696     /* HD derive new child key (on internal or external chain) */
    697     void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
    698 
    699-    std::set<int64_t> setKeyPool;
    700+    bool fFileBacked;
    


    NicolasDorier commented at 1:04 pm on May 4, 2017:
    why is it added ? where is it used ?

    jonasschnelli commented at 1:09 pm on May 4, 2017:
    Oh. That’s a rebase issue. fFileBackand was removed in the meantime, Will remove it here.

    jonasschnelli commented at 1:13 pm on May 4, 2017:
    Removed.
  10. in src/wallet/wallet.cpp:3331 in 2e614359d5 outdated
    3324@@ -3324,10 +3325,10 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
    3325     CWalletDB walletdb(*dbw);
    3326 
    3327     LOCK2(cs_main, cs_wallet);
    3328-    BOOST_FOREACH(const int64_t& id, setKeyPool)
    3329+    for (const KeypoolCache &poolPair : setKeyPool)
    3330     {
    3331         CKeyPool keypool;
    3332-        if (!walletdb.ReadPool(id, keypool))
    3333+        if (!walletdb.ReadPool(poolPair.nIndex, keypool))
    


    NicolasDorier commented at 1:05 pm on May 4, 2017:
    I am wondering if it is not better (minimum diff) to just change ReadPool signature to take KeyPoolCache instead of index.
  11. Change setKeyPool from pure int64_t to a custom class for more flexible in-mem storage af1c4ec53a
  12. in src/wallet/wallet.h:970 in 2e614359d5 outdated
    967@@ -957,7 +968,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
    968     bool TopUpKeyPool(unsigned int kpSize = 0);
    969     void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal);
    970     void KeepKey(int64_t nIndex);
    971-    void ReturnKey(int64_t nIndex);
    972+    void ReturnKey(int64_t nIndex, const CKeyID &keyid);
    


    NicolasDorier commented at 1:06 pm on May 4, 2017:
    why not just take KeypoolCache ?

    jonasschnelli commented at 1:09 pm on May 4, 2017:
    Hmm.. then CReserveKey::Return key would have to create a KeypoolCache()?

    NicolasDorier commented at 1:21 pm on May 4, 2017:
    why ? I mean KeypoolCache is (int, KeyId) anyway. It is just strange to pass them as two distinct parameters here.
  13. jonasschnelli force-pushed on May 4, 2017
  14. ryanofsky commented at 5:55 pm on July 25, 2017: member

    In #10882 it seems like looking up keypool index using key id is more useful than looking up key id using key index, so I’m not sure if there is a direct use for this PR and maybe it should be reconsidered.

    If the goal is to avoid reading all the unused keys from disk each time an IsMine transaction is encountered, I think there are three ways it could be done:

    1. Easiest way is probably just to just cache the result of GetAllReserveKeys during the rescan so it doesn’t get called multiple times in the same scan.
    2. Another way could be update this PR so GetAllReserveKeys() could work from memory without touching the database. This optimization is not exclusive with (1) above and both could be done together.
    3. Another way could be to update this PR to store a bidirectional mapping from key id <-> key index instead of just forward mapping so GetAllReserveKeys() wouldn’t have to do any work and could just return a reference to the reverse map. This could be done with boost multindex or just two plain maps.
  15. jonasschnelli commented at 3:37 am on October 5, 2017: contributor
    No longer really useful, closing for now.
  16. jonasschnelli closed this on Oct 5, 2017

  17. TheBlueMatt commented at 9:23 pm on October 5, 2017: member
    Hmm, I actually think this was a really nice change, though I guess it hits at the broader specifically-define-what-we-cache-from-db issue that has persisted for some time.
  18. DrahtBot 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-05 01:12 UTC

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