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
[chain] Change tx_last_seen to Option<u64>
#1416
base: master
Are you sure you want to change the base?
Conversation
23ffb41
to
fc090cb
Compare
fc090cb
to
59315f7
Compare
Option<u64>
Option<u64>
59315f7
to
15d9579
Compare
15d9579
to
007beaf
Compare
crates/chain/tests/test_tx_graph.rs
Outdated
@@ -959,10 +959,10 @@ fn test_chain_spends() { | |||
})) | |||
); | |||
|
|||
// Even if unconfirmed tx has a last_seen of 0, it can still be part of a chain spend. | |||
// Even if unconfirmed tx has a last_seen of None, it can still be part of a chain spend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a valid assumption?
If instead we were to filter unseen txs in try_get_chain_position
, it has the same desired effect on canonical txs, but then this assertion no longer holds. In other words, the above comment will say
// An unconfirmed and unseen tx cannot be part of a chain spend.
Experimenting with that approach in 03d0515. This might be preferable in that it applies the same reasoning (that an unseen tx does not have a chain position) to list_chain_spends
and filter_chain_txouts
.
Isn't |
03d0515
to
6fbd167
Compare
crates/chain/src/tx_graph.rs
Outdated
Some(val) => { | ||
let (_, anchors, last_seen) = val; | ||
if anchors.is_empty() && last_seen.is_none() { | ||
// We don't consider unanchored, unseen transactions | ||
// to have a chain position. | ||
return Ok(None); | ||
} | ||
val | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of moving this logic into try_get_chain_position
. However, for transactions with last_seen
as None
, but with an anchor that anchors the transaction in the best chain, wouldn't the transaction be in the best chain?
My understanding of last_seen
is that a value of None
signals that it has not been seen in the mempool. However, this fact shouldn't invalidate the fact that the transaction can be confirmed in the best chain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we rename this method to try_get_canonical_position
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having a chain position should imply the tx is canonical, so I think these are synonymous.
crates/chain/src/chain_data.rs
Outdated
@@ -10,7 +10,7 @@ pub enum ChainPosition<A> { | |||
/// The chain data is seen as confirmed, and in anchored by `A`. | |||
Confirmed(A), | |||
/// The chain data is not confirmed and last seen in the mempool at this timestamp. | |||
Unconfirmed(u64), | |||
Unconfirmed(Option<u64>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be fair to say that unconfirmed transactions without a last-seen will not have a ChainPosition
? Would it make sense to rename ChainPosition
to CanonicalPosition
?
crates/chain/src/chain_data.rs
Outdated
@@ -58,14 +58,16 @@ pub enum ConfirmationTime { | |||
/// The transaction is unconfirmed | |||
Unconfirmed { | |||
/// The last-seen timestamp in unix seconds. | |||
last_seen: u64, | |||
last_seen: Option<u64>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's not worth it to put an option here either? Assuming that we agree that unconfirmed txs without a last-seen are not worth returning? The ConfirmationTime
type is only used in bdk_wallet
as a field in LocalOutput
(which is a UTXO). There is no point showing a UTXO that is not part of the canonical chain right?
crates/chain/src/tx_graph.rs
Outdated
pub fn try_list_chain_txs<'a, C: ChainOracle + 'a>( | ||
/// [`full_txs`]: Self::full_txs | ||
/// [`canonical_transactions`]: Self::canonical_transactions | ||
pub fn try_canonical_transactions<'a, C: ChainOracle + 'a>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would try_list_canonical_transactions
be a better name?
if let Some(seen_at) = tx_tmp.last_seen { | ||
let _ = graph.insert_seen_at(tx.txid(), seen_at); | ||
} | ||
let _ = graph.insert_seen_at(tx.txid(), tx_tmp.last_seen.unwrap_or(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we force-inserting a last_seen
when the template last_seen
is None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a fix for the test test_tx_conflict_handling
. Because we're interested in testing tx conflicts, we have to control for the fact that txs without a last_seen would now be filtered out, so we just assume all txs are canonical.
@@ -784,13 +784,21 @@ mod test { | |||
|
|||
fn get_test_utxos() -> Vec<WeightedUtxo> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These aren't really useful UTXOs when they are not seen at all right?
summarizes the main usecase of these changes. With this context in mind, this PR description needs to highlight how we should handle non-broadcasted transactions in How can the caller list these non-broadcasted transactions? What if the caller would like to include UTXOs of non-broadcasted transactions when listing their UTXO set? What if the caller would NOT like to do so? What if the caller would like to replace non-broadcasted transactions? Currently, we do transaction-precedence based on last_seen. Wouldn't we need something like this for non-broadcasted transactions too? It seems that many things have not be thought through clearly. Let's have some more concrete discussion about how everything should look after these changes. |
6fbd167
to
7b00dca
Compare
since we'd be lacking context that should normally occur during sync with a chain source. The logic for inserting a graph anchor from a `ConfirmationTime` is moved to the wallet common test module in order to simulate receiving new txs and confirming them.
Also fixup `test_list_owned_txouts` to check that the right outputs, utxos, and balance are returned at different local chain heights. This fixes an issue where unbroadcast and otherwise non-canonical transactions were returned from methods `list_chain_txs` and `Wallet::transactions`, because transactions with unknown anchors were erroneously being given a `ChainPosition`. Note this commit changes the way `Balance` is calculated due to new logic in `try_get_chain_position` that no longer considers txs with non-canonical anchors. Before this change, a tx anchored to a block that is reorged out had a permanent effect on the pending Balance, and now only txs with a last_seen time or an anchor confirmed in the best chain will return a `ChainPosition`, and hence only these `TxOut`s will influence the `Balance` calculation.
and add a disclaimer about safety for `Wallet::tx_graph_mut`
c37abfa
to
c547aa4
Compare
fixes #1446
fixes #1396
Notes to the reviewers
Changelog notice
Checklists
All Submissions:
cargo fmt
andcargo clippy
before committingNew Features:
Bugfixes: