Skip to content

Commit

Permalink
txdb: track newly discovered coins on unconfirm.
Browse files Browse the repository at this point in the history
  • Loading branch information
nodech committed Dec 1, 2022
1 parent 4767093 commit 77a57f8
Show file tree
Hide file tree
Showing 2 changed files with 466 additions and 190 deletions.
82 changes: 59 additions & 23 deletions lib/wallet/txdb.js
Original file line number Diff line number Diff line change
Expand Up @@ -1011,18 +1011,18 @@ class TXDB {
if (!path)
continue;

details.setOutput(i, path);

const credit = Credit.fromTX(tx, i, height);
credit.own = own;

// If the first time we see a TX is in a block
// (i.e. during a rescan) update the "unconfirmed" locked balance
// before updating the "confirmed" locked balance.
if (height !== -1)
this.lockBalances(state, output, path, -1);
this.lockBalances(state, credit, path, -1);

this.lockBalances(state, output, path, height);

details.setOutput(i, path);

const credit = Credit.fromTX(tx, i, height);
credit.own = own;
this.lockBalances(state, credit, path, height);

state.tx(path, 1);
state.coin(path, 1);
Expand Down Expand Up @@ -1196,8 +1196,6 @@ class TXDB {
if (!path)
continue;

this.lockBalances(state, output, path, height);

details.setOutput(i, path);

let credit = await this.getCredit(hash, i);
Expand All @@ -1217,9 +1215,11 @@ class TXDB {
state.unconfirmed(path, credit.coin.value);

// Add unconfirmed balances.
this.lockBalances(state, output, path, -1);
this.lockBalances(state, credit, path, -1);
}

this.lockBalances(state, credit, path, height);

// Credits spent in the mempool add an
// undo coin for ease. If this credit is
// spent in the mempool, we need to
Expand Down Expand Up @@ -1328,7 +1328,7 @@ class TXDB {
state.coin(path, 1);
state.unconfirmed(path, coin.value);

this.lockBalances(state, coin, path, height);
this.lockBalances(state, credit, path, height);

if (block)
state.confirmed(path, coin.value);
Expand Down Expand Up @@ -1515,7 +1515,7 @@ class TXDB {
/**
* Unconfirm a transaction. Necessary after a reorg.
* @param {TXRecord} wtx
* @returns {Promise}
* @returns {Promise<Details>}
*/

async disconnect(wtx, block) {
Expand All @@ -1528,6 +1528,8 @@ class TXDB {

wtx.unsetBlock();

let own = false;

if (!tx.isCoinbase()) {
// We need to reconnect the coins. Start
// by getting all of the undo coins we know
Expand All @@ -1549,7 +1551,7 @@ class TXDB {
const path = await this.getPath(coin);
assert(path);

this.lockBalances(state, coin, path, height);
this.lockBalances(state, credit, path, height);

details.setInput(i, path, coin);

Expand All @@ -1559,6 +1561,7 @@ class TXDB {
// as spent in the mempool instead.
credit.spent = true;
await this.saveCredit(b, credit, path);
own = true;
}
}

Expand All @@ -1571,12 +1574,42 @@ class TXDB {
if (!path)
continue;

const credit = await this.getCredit(hash, i);
let credit = await this.getCredit(hash, i);

// Potentially update undo coin height.
// We may not have credit because it was spent in some unconfirmed tx,
// not because we just discovered.
if (!credit) {
await this.updateSpentCoin(b, tx, i, height);
continue;
// If it is already spent and is ours, no need to add balances.
if (await this.updateSpentCoin(b, tx, i, height))
continue;

credit = Credit.fromTX(tx, i, -1);
credit.own = own;

// Is coin spent ? (tracking for double spends)
const spent = await this.getSpent(hash, i);

// If we were tracking coins as spent,
// it means it does not introduce any coin
// and does not affect the balance.
if (spent) {
credit.spent = true;
this.spendCredit(b, credit, tx, i);
details.setOutput(i, path);
continue;
}

// If it is not spent, then coin is in unconfirmed state.
state.coin(path, 1);
state.unconfirmed(path, output.value);

// will be subtracted below.
state.confirmed(path, output.value);

this.lockBalances(state, credit, path, -1);
// will be unlocked below
this.lockBalances(state, credit, path, height);
}

this.unlockBalances(state, credit, path, height);
Expand Down Expand Up @@ -1709,13 +1742,13 @@ class TXDB {
* Inserting or confirming: TX outputs.
* Removing or undoing: Coins spent by the wallet in tx inputs.
* @param {State} state
* @param {Coin|Output} coin
* @param {Credit} credit
* @param {Path} path
* @param {Number} height
*/

lockBalances(state, coin, path, height) {
const {value, covenant} = coin;
lockBalances(state, credit, path, height) {
const {value, covenant} = credit.coin;

switch (covenant.type) {
case types.CLAIM: // output is locked until REGISTER
Expand Down Expand Up @@ -3003,24 +3036,26 @@ class TXDB {
* @param {TX} tx - Sending transaction.
* @param {Number} index
* @param {Number} height
* @returns {Promise}
* @returns {Promise<Boolean>}
*/

async updateSpentCoin(b, tx, index, height) {
const prevout = Outpoint.fromTX(tx, index);
const spent = await this.getSpent(prevout.hash, prevout.index);

if (!spent)
return;
return false;

// Was spent coin ours or are we tracking it for double spends.
const coin = await this.getSpentCoin(spent, prevout);

if (!coin)
return;
return false;

coin.height = height;

b.put(layout.d.encode(spent.hash, spent.index), coin.encode());
return true;
}

/**
Expand Down Expand Up @@ -3327,14 +3362,15 @@ class BalanceDelta {
* @alias module:wallet.Credit
* @property {Coin} coin
* @property {Boolean} spent
* @property {Boolean} own
*/

class Credit extends bio.Struct {
/**
* Create a credit.
* @constructor
* @param {Coin} coin
* @param {Boolean?} spent
* @param {Boolean} [spent = false]
*/

constructor(coin, spent) {
Expand Down
Loading

0 comments on commit 77a57f8

Please sign in to comment.