Skip to content

Instantly share code, notes, and snippets.

@nodech
Last active August 22, 2023 10:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nodech/c943e7c50b300b0505cc9dfcae243d48 to your computer and use it in GitHub Desktop.
Save nodech/c943e7c50b300b0505cc9dfcae243d48 to your computer and use it in GitHub Desktop.
TXDB State balance tracking

TXDB state/balance tracking

Transaction update sources.

  • insert
    • insert(pending): first sight of tx in mempool.
    • insert(block): first sight of tx in block.
  • confirm
    • confirm known transaction (from mempool, now in block)
  • unconfirm
    • chain reorg
    • rescan (consecutive reverts) - may change the behaviour.
  • erase(pending)/erase(block)
    • Saw in mempool, was double spent in block.
    • Reverted wallet, was double spent in block.
    • Reverted wallet, was zapped.

TXDB State tracking

Entries marked with * are not part of the first update.

  • insert (pending) - tx++

    • Input (detect using getCredit)
      • It is spending our credit (ub-, ulb-).
        • don't remove credit, but mark it as spent.
        • unconfirmed: -value.
        • unconfirmedLocked: -value.
        • coin--
        • add to spent credits for this tx.
      • *We have coinview information from the chain and we discovered it is ours. (b+, lb+) (Note 3)
        • Create credit
        • emit missed credit(block OR pending) -> pending(this) (Note 5)
        • mark it as spent.
        • confirmed: +value
        • confirmedLocked: +value
        • don't increase coins or unconfirmed balances as this tx is spending it.
        • add to spent credits for this tx.
      • Unknown, but it is actually ours. (Same as below)
        • We CAN'T do anything if don't have credit entry. (and even coinview did not help).
        • It could be either in the pendings and we missed it that time (layout.s)
        • It is already part of the block we wont get to see it anymore.
        • Can't detect missed credit.
      • Unknown - track for dbl spends.
        • track for dbl spends (writeInputs/layout.s)
        • do nothing.. (no value, cant create credit)
    • Output (detect using getPath)
      • Our output (ub+, ulb+).
        • Create credit.
        • save credit as unconfirmed (coin.height = -1).
        • unconfirmed: +value.
        • unconfirmedLocked: +value
        • coin++
      • NEW: Our output, but was already spent (missed on spend). (Note 5)
        • Create credit.
        • save credit as unconfirmed (coin.height = -1)
        • mark it as spent.
        • add to spent credits for the spending transaction.
        • emit missed credit(pending) -> pending
        • unconfirmed: -value.
        • unconfirmedLocked: -value.
        • coin--
      • Unknown
        • do nothing. (could be ours)
  • insert (block) - tx++ (no unconfirmed state for this)

    • Input (detect using getCredit)
      • It is spending our credit (b-, lb-, ub-, ulb-).
        • Remove credit.
        • confirmed: -value and unconfirmed: -value
        • confirmedLocked: -value and unconfirmedLocked: -value
        • coin--
        • add to spent coins for this tx.
      • *We have coinview information from the chain and we discovered it is ours. (Note 3)
        • emit missed credit(block) -> block
        • add to spent coins for this tx.
      • Unknown, but it is actually ours
        • we can't do anything if it was not added to the credit list even now. (So it is part of the current block or previous ones)
      • Unknown
        • do nothing (not even track), we know it wont get double spent.
        • no more opportunity to discover even if it was ours.
    • Output (detect using getPath)
      • Our output (b+, lb+, ub+, ulb+).
        • Create credit.
        • confirmed: +value and unconfirmed: +value
        • confirmedUnlocked: +value and unconfirmedLocked: +value
        • coin++
      • NEW: Our output, but was already spent (missed on spend). (b+, lb+) (Note 4)
        • Create credit.
        • confirmed: +value
        • confirmedLocked: +value
        • mark it as spent.
        • add to the spent credits for the spending transaction.
        • emit missed credit(block) -> pending or block
      • Unknown
        • we do nothing.
  • confirm (prev inserted with insert(pending) from the mempool)

    • Input (detect using getCredit)
      • It is spending our credit (b-, lb-), indexed in insert(block) or prev confirm
        • confirmed: -value
        • confirmedLocked: -value
        • Remove credit.
      • It is spending our credit (b-, lb-, ub-?, ulb-?), but it was discovered after insert(pending) in insert(block), insert(pending) or confirm.
        • confirmed: -value
        • confirmedLocked: -value
        • Resolve credit (insert(pending).out, insert(block).out, confirm.out)
          • coin--
          • unconfirmed: -value
          • unconfirmedLocked: -value
        • This resolve is step where unconfirmed balance gets FIXED and output spent tracking is not strictly necessary as it will recover.
      • *We have coinview information from the chain and we discovered it is ours. (b+, lb+) (Note 3)
        • emit missed credit(block) -> block
        • add to spent coins for this tx.
      • Unknown, could be ours.
        • do nothing.
    • Output (detect using getPath)
      • Our output (tracked) (b+, lb+):
        • confirmed: +value
        • confirmedLocked: +value
        • updateSpentCoin - if it was spent.
      • Our output (b+, lb+, ub+, ulb+), but was missed on insert(pending) NOT SPENT:
        • Create credit.
        • coin++
        • unconfirmed: +value
        • unconfirmedLocked: +value
        • confirmed: +value
        • confirmedLocked: +value
        • emit missed credit(block) -> null
      • NEW: Our output, but was already spent. (b+, lb+), was missed on insert(pending)
        • Create credit.
        • confirmed: +value
        • confirmedLocked: +value
        • mark it as spent.
        • add to the spent credits for the spending transaction.
        • emit missed credit(block) -> pending or block
      • Unknown, could be ours
        • we do nothing.
  • unconfirm

    • Input (detect using getSpentCredits)
      • Input is ours. (b+, lb+)
        • Grab spent credit.
        • mark it as spent.
        • confirmed: +value (because on chain we no longer have this deduced, only unconfirmed)
        • confirmedLocked: +value (same as above)
      • Unknown, can be ours.
        • do nothing (store for double spends)
    • Output (detect using getPath)
      • Output is ours (b-, lb-), we've got the credit.
        • Resave credit with updated height to the db.
        • confirmed: -value
        • confirmedLocked: -value
        • We already have this in unconfirmed/lockedUnconfirmed balances, no need to modify.
        • updateSpentCoin - if it was spent.
      • NEW: Output is ours, but we just discovered it (ub+, ulb+) and it's not spent.
        • Create credit for it.
        • unconfirmed: +value
        • unconfirmedLocked: +value
        • coin++
        • Don't add to confirmed/confirmedLocked because we just discovered and it's not confirmed.
        • emit missed credit(pending) -> null
      • NEW: Output is ours, but we just discovered it and it's spent.
        • Create credit for it.
        • mark it as spent.
        • add to the spent credits for the spending transaction.
        • emit missed credit(pending) -> pending
        • Don't touch balances, it's not part of confirmed because it's not confirmed and not part of unconfirmed because it is spent.
      • Output is not ours
        • Do nothing.
  • erase(pending) - tx--

    • Input (detect using getSpentCredits)

      • Input is ours. (ub+, ulb+)
        • Get spent credits and resave them as credits.
        • unmark it as spent if it was ever marked.
        • unconfirmed: +value
        • unconfirmedLocked: +value
        • coin++
        • updateSpentCoin
      • Input is not ours. (could be, we can't know)
        • Do nothing.
    • Output (detect using getPath)

      • Output is ours (ub-, ulb-).
        • Remove credit.
        • coin--
        • unconfirmed: -value
        • unconfirmedLocked: -value
      • Output is ours, we just discovered it (not spent)
        • Do nothing, as would have been discarded.
      • Output is ours, we just discover it and it is SPENT
        • If output is spent by us in pending, remove them recursively as they are now orphaned.
        • This is done by the remove method which is called in case of zap/abandon
      • Output is not ours.
        • Do nothing.
    • erase(block) - tx--

      • Input (detect using getSpentCredits)
        • Input is ours. (b+, lb+, ub+, ulb+)
          • Get spent credit and resave them as credits.
          • unconfirmed: +value
          • unconfirmedLocked: +value
          • confirmed: +value
          • confirmedLocked: +value
        • Input is not ours.
          • Do nothing.
      • Output (detect using getPath)
        • Output is ours (b-, lb-, ub-, ulb-)
          • Remove credit
          • coin--
          • confirmed: -value
          • confirmedLocked: -value
          • unconfirmed: -value
          • unconfirmedLocked: -value
        • Out is ours we just discovered it (not spent).
          • Do nothing, as would have been discarded.
        • Out is ours we just discovered it and it is SPENT.
          • If output is spent by us in pending, remove them recursively.
          • This is done by the remove method which is called in case of zap/abandon
        • Output is not ours.
          • Do nothing.

NOTE 1: Transactions where we have missed inputs and outputs, will not get tracked by the wallet. E.g. we should have received money, but we were not tracking it with filters, this transaction and coin will be lost in history until rescan.

NOTE 2: mempool wont send us Orphaned transactions (where tx inputs are not part of the chain or mempool). This does not miss wallet can't be missing input or coins, if the derivation order is messed up.

NOTE 3: Currently, information from the chain does not include coinview, even when it is running full node with coin information. We could potentially include coinview for the blocks with transactions to allow better discoveries.

NOTE 4: Spent pending credit discoveries currently are not tracked, but they only affect unconfirmed amount until they are confirmed. Confirmed balances are correct.

NOTE 5: emit missed credit(credit state) -> spender state if any

States store related above tracking.

State from lib/wallet/layout.js txdb layout:

  • layout.s :
    • key - outpoint({input.prevout.hash, input.prevout.index})
    • value - spender(input{txhash, inputIdx}) - double spend watch
  • layout.d : spender(input{txhash, inputIdx}) -> credit.coin
  • layout.c : coin(hash, index) -> credit
  • layout.C : coin(account.id, hash, index) -> null
  • layout.W : wid -> wallet balance
  • layout.r : account.id -> account balance.

Covenants

  • NONE
  • CLAIM
  • BID
  • REVEAL
  • REDEEM (linked)
  • REGISTER (linked)
  • UPDATE (linked)
  • RENEW (linked)
  • TRANSFER (linked)
  • FINALIZE (linked)

Abstract covenant actions

These are tied to the height after the coin got mined.

  • Name/Coin has expired (burned)
  • BID got burned (unrevealable)

TODO(s) next iteration

  • Add ability to send coinview with block data from chain to the wallet.
  • Add block height hooks, for expires and lost bids.
    • Track name expires.
    • Track lost bids.
  • For newly discovered names(missed reveals), emit event to rescan the auction to find the winner.
  • Fix bid/reveal listings for reopened auctions (older ones show up again).

Future balance trackings

  • Spendable balance
  • Spendable balance (unconfirmed)
  • Burned coins (that no longer can be unlocked) - Values burned in names. - Values burned in unrevealable bids. (lost?)
  • Burned coins unconfirmed - Values burned in names.
  • Active locked balance (w/o burned)
  • Actice unconfirmed balance (w/o burned)

Glossary

  • spent credits - Coins that are ours, but are tagged as spent.
  • spent coins - Basically already removed from the list of coins we track.
@nodech
Copy link
Author

nodech commented Dec 22, 2022

credit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment