-
Notifications
You must be signed in to change notification settings - Fork 45
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
Add Wallet list_unspent method #158
Conversation
Hey thanks for your contribution! I think the bug you're uncovering is described in #155 and will be fixed once we use bdk Once that's done we'll try and release a new version of bdk-ffi right away. Not sure if we'll try and add new features in or just bump to bdk |
This looks like great stuff. As for the next |
} | ||
} | ||
|
||
pub struct LocalUtxo { |
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.
The BDK version of this struct has a boolean is_spent
. I assume you didn't include it here because LocalUtxo
will only be returned from the list_unspent()
method, which means that boolean will only ever been set to false
. In this case, however, I think the naming could lead to confusion if some developers are familiar with the Rust version of BDK.
I propose we either:
- Rename the struct
UnspentLocalUtxo
to make explicit the fact that it is unspent, or - Add the
is_spent
boolean to it, which for now will only ever be false
I suggest we go with (2) because to me that feels more forward-compatible. If ever we implement other features that use the LocalUtxo
struct we'll have it in its entirety already. I also feel like it might allow you to simplify some of the mapping between the LocalUtxo
struct you have here and the one defined in BDK. Finally, we've been discussing how we want to try and keep the API in the bindings as close as we can to the BDK API. It's not always possible, but in this case I think it is.
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 also feel that (2) is a better choice here so just added the field
src/lib.rs
Outdated
address: String, | ||
} | ||
|
||
pub enum KeychainKind { |
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'm not sure we need the 0 and 1 here but maybe there is something I'm missing. Can you tell me why you added them and not just use the enum defined in BDK directly? (i.e. no need to define it here in Rust and you could simply have it in the UDL file I think)
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.
Follow-up: my tests pass when refactoring the KeychainKind out of the lib.rs file like so:
// pub enum KeychainKind {
// External = 0,
// Internal = 1,
// }
// impl From<bdk::KeychainKind> for KeychainKind {
// fn from(x: bdk::KeychainKind) -> KeychainKind {
// match x {
// bdk::KeychainKind::External => KeychainKind::External,
// bdk::KeychainKind::Internal => KeychainKind::Internal,
// }
// }
// }
impl NetworkLocalUtxo for LocalUtxo {
fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo {
LocalUtxo {
outpoint: OutPoint {
txid: x.outpoint.txid.to_string(),
vout: x.outpoint.vout,
},
txout: TxOut {
value: x.txout.value,
address: bdk::bitcoin::util::address::Address::from_script(
&x.txout.script_pubkey, network).unwrap().to_string(),
},
keychain: x.keychain,
}
}
}
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.
Sorry, my mistake. I initially assumed that was a requirement of uniFFI but then forgot to try without. Thanks for the suggestion!
|
||
pub struct TxOut { | ||
value: u64, | ||
address: String, |
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.
At first glance it looks good to me, but it's still something I want to bring to the attention of other reviewers (@notmandatory, @artfuldev). The TxOut
in BDK contains a Script
instead of an address of type String
. I don't think we need the Script
at the moment, but it does change the shape of the API, so something to note.
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 a bunch for tackling this @zoedberg! Coin selection is an important feature and this is the first step.
I left a few comments there for you; let me know if they all make sense.
src/lib.rs
Outdated
trait NetworkLocalUtxo: { | ||
fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo; | ||
} | ||
|
||
impl NetworkLocalUtxo for LocalUtxo { | ||
fn from_utxo(x: &bdk::LocalUtxo, network: Network) -> LocalUtxo { |
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'd love it if we started commenting our codebase more (the FFI layer can be quite opaque and I want to make sure we make it easy on new contributors), and I think this is a perfect place to start.
It took me a few minutes to understand what this NetworkLocalUtxo
trait was for, and if I understand correctly, you added this trait because the TxOut
struct now contains an address
(String
), and for that you need the Address::from_script() which requires a network. That's great stuff and let me know if I didn't understand correctly. Long-winded way to say... I think we should just add a small comment explaining what this NetworkLocalUtxo
is used for 🤣.
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 had some hard times finding a fitting and self-explanatory name for this trait, so I agree a comment could be useful here. For next contributions I will keep in mind that comments are welcome 😄
@thunderbiscuit A big thanks to you and everybody who participated to this project, it's a pleasure to contribute to such a well designed and written project. I agree with all the comments, working on in it right now, will push the changes soon :) |
Rebased the PR branch and added the suggested changes. Tested them on Android where they seem to work fine :) |
This is ready for merge IMO. I'll wait for one more reviewer to chime in and will squash your commits into one + merge. |
@notmandatory would love your review on this. I'm not sure if we should merge before #154, as this is an easier and ready to go change, 154 might be still WIP a bit (but maybe not? happy to do it the other way too). In any case merging this will allow us to start reviewing #164, which I'd love to start working on this week. |
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 fad5e3c
Here is my attempt at implementing the
list_unspent
method.In order to test this I've updated the
bdk-ffi
submodule in thebdk-kotlin
project, ran commands to build and publish the android library to a local maven repository and finally imported the library on an Android project written in Kotlin.The list seems to work fine, except for a strange behaviour I've noticed when calling the method multiple times.
So, in order to exclude bugs from my side, I've wrote a minimal Rust project that directly uses bdk 0.18 to list the unspents of an existing wallet.
From this test I've understood that creating a wallet using a
bdk::database::SqliteDatabase
database and calling the walletsync
method leads to each UTXO getting re-inserted in the database even if already present.Here's a minimal piece of code that shows how to reproduce the bug:
Inspecting the sqlite database shows that the UTXO actually gets re-inserted at each sync.
The error does not arise when the database is defined as
MemoryDatabase::default()
.