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

Check spend status in bitcoin poller #29

Merged
merged 8 commits into from
Oct 12, 2022

Conversation

edouardparis
Copy link
Member

Add two new columns:

  • blocktime: timestamp of the block containing the transaction funding the coin.
  • spent_at: timestamp of the block containing the transaction spending the coin.

Update the coin spent_at when the spend transaction is confirmed

Copy link
Contributor

@darosior darosior left a comment

Choose a reason for hiding this comment

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

Cool. I've found one "bug" (an edge case that isn't covered) in the poller, and the rest is mostly nits. Let me know if you prefer to ignore them. Though i do feel somewhat strongly about (in order of preference):

  1. Removing the arbitrary 6-confs rule. I added it in Revault since we had presigned transactions but here i think assuming it's confirmed with a single conf is fine for now.
  2. The interface for marking a spend as confirmed / the name of some of the trait methods introduced

src/bitcoin/mod.rs Outdated Show resolved Hide resolved
src/database/mod.rs Outdated Show resolved Hide resolved
src/database/sqlite/schema.rs Show resolved Hide resolved
src/bitcoin/mod.rs Show resolved Hide resolved
src/bitcoin/mod.rs Outdated Show resolved Hide resolved
src/database/sqlite/mod.rs Outdated Show resolved Hide resolved
src/testutils.rs Outdated Show resolved Hide resolved
src/database/sqlite/mod.rs Outdated Show resolved Hide resolved
// TODO: handle the case where new transaction which txid is not the
// coin spending_txid, spent the coin.
} else if !tx.conflicting_txs.is_empty() {
for txid in tx.conflicting_txs.clone() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need to clone()? Can't you just as_ref()?

Copy link
Member Author

Choose a reason for hiding this comment

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

There is an immutable borrow on the cache.get, but you are right that it is a certainly better way to do it

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm responding just to clarify, but no need to address this

I don't understand. Why not just iterate over the vector and copy the txid only if it happens to be necessary, instead of always reallocate the entire vector?
Like:

diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs
index 0c0f9c1..b171054 100644
--- a/src/bitcoin/mod.rs
+++ b/src/bitcoin/mod.rs
@@ -176,12 +176,12 @@ impl BitcoinInterface for d::BitcoinD {
                         spent.push((*op, *txid, tx.block_time.expect("Spend is confirmed")))
                     }
                 } else if !tx.conflicting_txs.is_empty() {
-                    for txid in tx.conflicting_txs.clone() {
-                        let tx: Option<&d::GetTxRes> = match cache.get(&txid) {
+                    for txid in &tx.conflicting_txs {
+                        let tx: Option<&d::GetTxRes> = match cache.get(txid) {
                             Some(tx) => tx.as_ref(),
                             None => {
                                 let tx = self.get_transaction(&txid);
-                                txs_to_cache.push((txid, tx));
+                                txs_to_cache.push((*txid, tx));
                                 txs_to_cache.last().unwrap().1.as_ref()
                             }
                         };
@@ -190,7 +190,7 @@ impl BitcoinInterface for d::BitcoinD {
                                 if block_height > 1 {
                                     spent.push((
                                         *op,
-                                        txid,
+                                        *txid,
                                         tx.block_time.expect("Spend is confirmed"),
                                     ))
                                 }

src/bitcoin/mod.rs Outdated Show resolved Hide resolved
@edouardparis edouardparis force-pushed the add-spent-coins-pull branch 4 times, most recently from 09dbbb4 to 37d16d1 Compare October 5, 2022 15:38
Copy link
Contributor

@darosior darosior left a comment

Choose a reason for hiding this comment

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

Almost ACK. I'm just confused by the check that the block_height of the spending transaction be higher than 1. Feel free to ignore the rest.

src/bitcoin/d/mod.rs Show resolved Hide resolved
src/bitcoin/mod.rs Outdated Show resolved Hide resolved
src/database/mod.rs Outdated Show resolved Hide resolved
src/bitcoin/poller/looper.rs Outdated Show resolved Hide resolved
src/bitcoin/d/mod.rs Outdated Show resolved Hide resolved
// TODO: handle the case where new transaction which txid is not the
// coin spending_txid, spent the coin.
} else if !tx.conflicting_txs.is_empty() {
for txid in tx.conflicting_txs.clone() {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm responding just to clarify, but no need to address this

I don't understand. Why not just iterate over the vector and copy the txid only if it happens to be necessary, instead of always reallocate the entire vector?
Like:

diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs
index 0c0f9c1..b171054 100644
--- a/src/bitcoin/mod.rs
+++ b/src/bitcoin/mod.rs
@@ -176,12 +176,12 @@ impl BitcoinInterface for d::BitcoinD {
                         spent.push((*op, *txid, tx.block_time.expect("Spend is confirmed")))
                     }
                 } else if !tx.conflicting_txs.is_empty() {
-                    for txid in tx.conflicting_txs.clone() {
-                        let tx: Option<&d::GetTxRes> = match cache.get(&txid) {
+                    for txid in &tx.conflicting_txs {
+                        let tx: Option<&d::GetTxRes> = match cache.get(txid) {
                             Some(tx) => tx.as_ref(),
                             None => {
                                 let tx = self.get_transaction(&txid);
-                                txs_to_cache.push((txid, tx));
+                                txs_to_cache.push((*txid, tx));
                                 txs_to_cache.last().unwrap().1.as_ref()
                             }
                         };
@@ -190,7 +190,7 @@ impl BitcoinInterface for d::BitcoinD {
                                 if block_height > 1 {
                                     spent.push((
                                         *op,
-                                        txid,
+                                        *txid,
                                         tx.block_time.expect("Spend is confirmed"),
                                     ))
                                 }

src/bitcoin/mod.rs Outdated Show resolved Hide resolved
src/database/mod.rs Show resolved Hide resolved
@darosior
Copy link
Contributor

ACK 172cda1

@darosior darosior merged commit 2a32144 into wizardsardine:master Oct 12, 2022
This was referenced Oct 12, 2022
darosior added a commit that referenced this pull request Oct 18, 2022
e75637d jsonrpc: fixup two typos in error messages (Antoine Poinsot)
a9b0e5e qa: functional tests for block chain reorganization (Antoine Poinsot)
e88bbbe poller: block chain reorganization handling (Antoine Poinsot)
d6f24e1 bitcoind: don't return spent coins with unfetchable spending tx as spent (Antoine Poinsot)
99ab0d7 commands: add a 'spend_info' field to the 'listcoins' entries (Antoine Poinsot)
57add1d commands: return the DB's block height in 'getinfo' (Antoine Poinsot)
92f7ef1 commands: make listcoins return all coins by default (Antoine Poinsot)
e9e4acd db: database interface to rollback to a previous best block (Antoine Poinsot)
972c8da db: require the spend block height from the DB interface (Antoine Poinsot)
6038843 database: rename coins' spent_at in spend_block_time (Antoine Poinsot)
cce227f bitcoin: interface to get the common block in our and the backend's chains (Antoine Poinsot)

Pull request description:

  This finally implements our reorganization handling. Like in revaultd, upon noticing a tip change that indicates a reorg happened in our Bitcoin backend we rollback our state to the common ancestor between our state and the new chain, then start rescanning from there. The logic is much more straightforward than in revaultd though, as there is no presigned transactions to care about.

  The PR grew a bit large as this needed a bit of preparatory work in order to be reasonably tested (and i noticed a few bugs and cleanups that slipped through review in #29). Please let me know if reviewers prefer that i split the prep work on the commands in another PR.

  Fixes #15.

ACKs for top commit:
  darosior:
    ACK e75637d

Tree-SHA512: 1ebb2a3e10b462b739e1d5cb831de946177436c8fad4dcb20eb575fd0f58bef98a86e25c5fe0ed07d946975f982a420940607a69e74f24a02ef16271c92eceba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants