-
Notifications
You must be signed in to change notification settings - Fork 321
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
BlockId should not have a default and passing a chain tip should be an Option #1107 #1116
Conversation
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.
Do we really need to .clone()
all the Into<BlockId>
?
Can't we pass by reference in some of these?
crates/chain/src/local_chain.rs
Outdated
chain_tip: Option<B>, | ||
) -> Result<Option<bool>, Self::Error> { | ||
let chain_tip: BlockId = match chain_tip { | ||
Some(x) => x.into(), | ||
None => return Ok(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.
Wouldn't it better to return Result<bool, Self::Error>
?
Result<Option<bool>, Self::Error>
seems unnecessary
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.
There are three possibilities:
Some(true)
: The block is in the chainSome(false)
: The block is not in the chainNone
we don't know if the block is in the 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.
Maybe in the future, we can consider turning this into an enum?
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.
Not sure. Would just add documentation as far as I can see. Documenting the trait method seems clear enough. I could be wrong.
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.
Thanks for doing this tedious work @SpaghettiSats. General comments:
- No need to add specific tests for these. Try to avoid as much as possible changes to the test files in this PR. I think it's quite hard to implement these convenience methods incorrectly.
- Docs need to explain what a subchain is. Liberally refer to the other method e.g.
subchain_X is like [X] except it restricts the chain to a custom tip
. The tip doesn't even need to be in the same chain as the tip. You can use this to find information about a point in the past or on a fork (if your chain oracle supports that). - I think after looking at it we don't need to do the
Into<BlockId>
thing because it's already convenient enough now that we have all these variants. I'd just take aBlockId
. Should address @realeinherjar's complaint above. - Use the convenience methods wherever possible in
wallet/mod.rs
and in the tests etc
Thanks for the feedback. I'll work on these suggestions. |
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.
ACK be86650
Thanks @SpaghettiSats. I think another review from someone to confirm that these extra methods are worth maintaining for the convenience they offer.
crates/chain/src/tx_graph.rs
Outdated
@@ -644,6 +644,11 @@ impl<A: Anchor> TxGraph<A> { | |||
|
|||
/// Get the position of the transaction in `chain` with tip `chain_tip`. | |||
/// | |||
/// This method is like [`try_get_chain_position`] except it restricts the | |||
/// chain to a custom tip. The tip doesn't even need to be in the same chain as the tip. |
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.
/// chain to a custom tip. The tip doesn't even need to be in the same chain as the tip. | |
/// chain to a custom tip. The tip doesn't even need to be in the same chain as the current tip. |
I have rebased my branch and signed all the commits I have made, please if there are any other issues tell me and I will try to fix them. |
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.
Thank you so much for this! I agree that removing the Default
implementation on BlockId
and instead using Option
is much clearer, and I like the new methods that automatically fetch the chain tip from the chain oracle instead of requiring the user to provide one, they make the API way clearer.
However, I wonder whether it makes sense to have Option<BlockId>
in some places. I left two comments about this, there are many other places where I'm left wondering the same thing, but I didn't comment on those as I'm probably just missing something :)
@@ -469,5 +475,80 @@ fn test_list_owned_txouts() { | |||
confirmed: 80000 // tx1 + tx3 | |||
} | |||
); | |||
|
|||
// Test that not specifing the chain_tip return the same results |
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.
crates/chain/src/chain_oracle.rs
Outdated
@@ -17,7 +17,7 @@ pub trait ChainOracle { | |||
fn is_block_in_chain( | |||
&self, | |||
block: BlockId, | |||
chain_tip: BlockId, | |||
chain_tip: Option<&BlockId>, |
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.
Mh, wouldn't it be better if we just had BlockId
here? I can't really think of any case where someone would call is_block_in_chain(block, None)
, giving that it would always return None
&self, | ||
chain: &C, | ||
chain_tip: BlockId, | ||
chain_tip: Option<BlockId>, |
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.
Same as my comment above, why having an Option here?
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.
After a deeper look, I think we should keep this Option
for 2 reasons: for consistency between methods and because it is convenient to check if the chain_tip
is None
in just one place instead of having to check every time before calling the method (the ChainOracle
give an Option
). If you think that is still the case to just pass the BlockId
let me know and I will do it.
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.
for consistency between methods
My point was that most (all?) of these methods should have a BlockId
instead of an Option
, I just commented a couple of them for brevity.
I see that it's convenient to have an Option here, but at the same time it makes the API a bit more difficult to understand.
Eventually it all comes down to personal preference, if you want to keep an Option
here it's fine, but I think the decision should at least be documented properly
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 I agree with @danielabrozzoni here. It causes friction to call it with the output of get_chain_tip
but that friction is born by us with this PR mostly so +1.
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 get it, I'll fix the problem this weekend.
First of all thank you for your review @danielabrozzoni. I agree with you. I will try to fix everything today. |
…p` of the passed `chain` instead of specifying one. refactor: remove unnecessary tests
…ckId>` for `chain_tip`
Approach NACK Thank you for taking this on and communicating clearly. Overall, I agree that However, I think it is important that all
Additionally, now we have extra methods doing different but similar things. This increases the complexity of our API. An Alternative Proposal: I think we should require all fn get_chain_tip(&self) -> Result<BlockId, Self::Error>; So all The additional benefit to this, is if the caller accidentally updates Related: |
I don't understand. They don't currently take in So to be clear, @evanlinjin's concern can be shown clearly in this change: https://github.com/bitcoindevkit/bdk/pull/1116/files#diff-ba2cf4a27dd1b461a84dc49953334c1efe322887febbcbe6f928057c36e7f7ec The two calls should be using the same chain tip. They are because
I imagined it but couldn't see what exactly the problem is. What's the concern?
Convenience methods do add maintenance complexity but reduce complexity for the user. I think it depends on whether the convenience methods send the right message. If people are meant to use a method 90% of the time in one way then it makes sense to have a convenience method that simplifies that for them and reassures them that they are not "missing out" on the right way of doing something by always using it that way. I thought that's what my suggestion was doing but it actually was not. You're meant to pass in the the same block id over multiple calls to these methods to keep the answers consistent but the convenience methods stops you from doing that. Perhaps we could include more nuanced documentation on the methods to make this clearer.
I don't think this is really an alternative proposal -- it's compatible with this PR also. |
@LLFourn sorry I meant |
To be clear in conclusion, I think we should not take this PR's approach for now and instead just wait on implementing @evanlinjin's proposal. I guess we can leave Sorry for originally suggesting this direction @SpaghettiSats. At least we have a better direction going forward. I think the |
So since we are in fact going in the direction of #1079 let's close this. Once again sorry for the wasted work @SpaghettiSats. I wonder if BDK team can help prevent me from wasting other people's time like this. It seems I casually circumvented the issue validation and execution engine of the BDK team and it cost us. An obvious suggestion is that we have ways of labeling issues that have actually been groomed by the core team that are ready for others to pick up. Could you bring this up in the next dev meeting: @evanlinjin @notmandatory |
I think for grooming new issues we should use the project "Status" field and only mark issues as "Todo" we're sure are ready and should be worked on. |
Description
This pull request addresses the issue discussed in GitHub Issue #1107. The primary changes made in this PR are as follows:
BlockId Default Removal: Removed the default implementation for
BlockId
as it doesn't make sense for it to have a default value. Instead, we rely onOption<BlockId>
to semantically represent a null block.Chain Tip as Option: Changed the
chain_tip
parameter in various methods to accept anOption<BlockId>
instead of usingunwrap_or_default()
. This aligns with Rust conventions for handling null values.ChainOracle's
get_chain_tip
: While keepingget_chain_tip
, it is now made more meaningful by adding functionality to fetch the chain tip from thechain
argument when calling certain methods. This makes theget_chain_tip
method more useful and justified.API Improvement: Introduced a more convenient version of
filter_chain_unspents
that automatically fetches the chain tip from thechain
argument, simplifying usage. The original method is retained asfilter_subchain_unspents
to maintain backward compatibility. Similar improvements are made for the following methods:get_chain_position
,get_chain_spend
,list_chain_txs
,filter_chain_txouts
,balance
and of course also for their fallible versions.Notes to the reviewers
Checklists
All Submissions:
cargo fmt
andcargo clippy
before committing.New Features:
Bugfixes: