Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wallet TX count and time indexing #605

Closed
wants to merge 70 commits into from

Conversation

braydonf
Copy link
Contributor

@braydonf braydonf commented Sep 11, 2018

This resolves CPU and memory exhaustion issues when requesting transaction history for a wallet with many transactions. Transactions are now also able to be queried by time based on median-time-past (MTP) based on chain data.

Closes: #559

  • Indexes for confirmed txs
  • Handle reorganizations
  • Indexes for unconfirmed txs
  • Complete API and exposed methods and endpoints
  • Cleanup, refactoring and dependencies
  • Testing/review, documentation, upgrading

See TODO.md for a full list.

TODO.md Outdated Show resolved Hide resolved
Copy link
Contributor

@bucko13 bucko13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! Excited to see the progress on this.

lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/txdb.js Outdated Show resolved Hide resolved
lib/wallet/txdb.js Outdated Show resolved Hide resolved
lib/wallet/wallet.js Outdated Show resolved Hide resolved
test/util/regtest.js Outdated Show resolved Hide resolved
test/util/regtest.js Outdated Show resolved Hide resolved
test/util/regtest.js Outdated Show resolved Hide resolved
test/util/rimraf.js Outdated Show resolved Hide resolved
lib/wallet/txdb.js Outdated Show resolved Hide resolved
@codecov-io

This comment has been minimized.

@braydonf braydonf force-pushed the wallet-pagination branch 2 times, most recently from 160c365 to 75dbdcb Compare December 5, 2018 23:24
@braydonf braydonf force-pushed the wallet-pagination branch 4 times, most recently from f1aa81b to 6d6718e Compare December 20, 2018 10:42
@braydonf braydonf changed the title WIP: Wallet TX count and monotonic time indexing WIP: Wallet TX count and time indexing Dec 20, 2018
@braydonf braydonf force-pushed the wallet-pagination branch 4 times, most recently from 5361774 to 05f4898 Compare December 20, 2018 22:43
lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/rpc.js Outdated Show resolved Hide resolved
lib/wallet/rpc.js Outdated Show resolved Hide resolved
@braydonf braydonf force-pushed the wallet-pagination branch 2 times, most recently from 13b7d03 to adfd21b Compare December 21, 2018 19:16
@braydonf braydonf added the ready for review Ready to be reviewed label Jun 27, 2019
@braydonf braydonf removed the ready for review Ready to be reviewed label Oct 8, 2019
@braydonf
Copy link
Contributor Author

braydonf commented Oct 16, 2019

Closing this pull request for now, as I haven't worked on this in quite some time. This solves the issue with many transactions within a wallet, and I've added this branch at https://github.com/bcoin-org/bcoin/tree/wallet-pagination and will leave it as it is currently until this topic is visited again. There is also the topic of the ability to recover the wallet from a seed that is important.

@nodech
Copy link
Member

nodech commented Mar 2, 2024

Bug related to unconfirmed index

Bug is related to how unconfirmed count recovery happens. It may rewrite the existing last transaction details. Here's is the idea how it could happen:

Situation 1:
- insert unconfirmed tx1. (increments layout.z.UNCONFIRMED)
- confirm tx1. (this store count in layout.x) / decrements layout.z.UNCONFIRMED
- insert new unconfirmed tx2. unconfirmed count for this will be the SAME as tx1.
- reorganization undos tx1. - layout.x - will be the same.

this can happen on scale as well:
- Add N unconfirmed txs.
- Confirm N txs in a block.
- Add new N txs.
- Reorganize so they are unmined.

Solution

  • Solution 1: never ever decrement the unconfirmed count. This needs new entry in the txdb, that will track the max unconfirmed index. This could avoid all the issues related to recovery on disconnect/unconfirm. Downside is that it may hasten the overflow of U32 count.index. For huge wallets, this may become an issue at some point.

    • NOTE: When tx is first seen directly in block (insert \w block), we need to increment unconfirmed count as well, to make sure it has reserved index in the unconfirmed layout.
  • Solution 2: Never recover and put them always on top. This can be more flexible, does not suffer from the overflow issue. Increment/decrement always happens on top, behaves like a stack and we can drop layout.x altogether. Downside is that it will violate the cronology and old confirmed but disconnected txs, will become new txs. To not violate the time index, we could also drop layout.e that recovers time and treat them as new txs.

Test case

Apply to test/wallet-test.js

  describe('Pagination indexes', function() {
    let wdb;

    before(async () => {
      wdb = new WalletDB({ memory: true });
      await wdb.open();
    });

    after(async () => {
      await wdb.close();
    });

    it('should reindex newly unconfirmed txs after disconnect', async () => {
      const N = 2;

      const toConfirm = [];
      for (let i = 0; i < N; i++) {
        const address = await wdb.primary.receiveAddress();
        const mtx = new MTX();
        mtx.addInput(dummyInput());
        mtx.addOutput(address, 1);

        const tx = mtx.toTX();
        toConfirm.push(tx);
        await wdb.addTX(tx);
      }

      {
        const unconfirmed = await wdb.primary.listUnconfirmed(0, {
          limit: 100,
          reverse: false
        });

        assert.strictEqual(unconfirmed.length, N);
      }

      const entry = nextBlock(wdb);
      await wdb.addBlock(entry, toConfirm);

      {
        const unconfirmed = await wdb.primary.listUnconfirmed(0, {
          limit: 100,
          reverse: false
        });

        assert.strictEqual(unconfirmed.length, 0);
      }

      for (let i = 0; i < N; i++) {
        const address = await wdb.primary.receiveAddress();
        const mtx = new MTX();
        mtx.addInput(dummyInput());
        mtx.addOutput(address, 1);

        const tx = mtx.toTX();
        toConfirm.push(tx);
        await wdb.addTX(tx);
      }

      {
        const unconfirmed = await wdb.primary.listUnconfirmed(0, {
          limit: 100,
          reverse: false
        });

        const all = await wdb.primary.listHistory(0, {
          limit: 100,
          reverse: false
        })

        assert.strictEqual(unconfirmed.length, N);
        assert.strictEqual(all.length, N * 2);
      }

      console.log(await wdb.dump());

      await wdb.removeBlock(entry);

      {
        const unconfirmed = await wdb.primary.listUnconfirmed(0, {
          limit: 100,
          reverse: false
        });

        const all = await wdb.primary.listHistory(0, {
          limit: 100,
          reverse: false
        })

        console.log(await wdb.dump());
        assert.strictEqual(unconfirmed.length, N * 2);
        assert.strictEqual(all.length, N * 2);
      }
    });
  });

nodech added a commit to nodech/hsd that referenced this pull request Mar 20, 2024
HSD: handshake-org#888
BCOIN: bcoin-org/bcoin#605

Co-authored-by: Braydon Fuller <courier@braydon.com>
nodech added a commit to nodech/hsd that referenced this pull request Aug 29, 2024
HSD: handshake-org#888
BCOIN: bcoin-org/bcoin#605

Co-authored-by: Braydon Fuller <courier@braydon.com>
z: bdb.key('z', ['uint32', 'uint32']),
Z: bdb.key('Z', ['uint32', 'uint32', 'uint32']),
y: bdb.key('y', ['hash256']),
x: bdb.key('u', ['hash256']),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo here. Should be x: bdb.key('x') instead of bdb.key('u')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
advanced An in depth feature or topic, requires specific expertise enhancement Improving a current feature http memory Memory issues rpc stability / efficiency Denial of service, better resource usage tests Has tests for code change is just an addtional test wallet Wallet related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wallet TX history memory and CPU exhaustion
6 participants