-
Notifications
You must be signed in to change notification settings - Fork 383
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
Bitcoin RPC Blockchain #22
Conversation
src/blockchain/bitcoin_rpc.rs
Outdated
} | ||
false | ||
}) | ||
.any(|x| x); |
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 trying to determine if Bitcoin Core knows about this script.
The only method of determining this that I know of is getaddressinfo
, which requires we actually turn the script into an address. Since this module has not notion of "network", I try each one.
src/blockchain/bitcoin_rpc.rs
Outdated
}) | ||
.collect::<Vec<_>>(), | ||
Some(&ImportMultiOptions { rescan }), | ||
)?; |
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.
Here I export all our scripts. It would be better if we could, say, export our last 100 scripts. Then check if the previous 100 scripts need exporting, etc.
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 still isn't ideal, but I think we can iterate on this.
This comment has been minimized.
This comment has been minimized.
src/blockchain/bitcoin_rpc.rs
Outdated
.0 | ||
.as_mut() | ||
.unwrap() | ||
.get_block_info(<x.info.blockhash.unwrap()) // FIXME: don't unwrap |
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 doing this because until now listtransactions
doesn't include block heights.
Well Bitcoin 20.0 added this field. So we only need to call getblock
if their node version is lower than 20.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.
Once this is merged we can skip this if we find the height (it won't be there for pre-20.0 nodes)
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 using a rust-bitcoincore-rpc fork until ^^ gets added. This fork hacks around this issue which breaks getaddressinfo
on 0.20.0 :/
I should probably swap out the fork before we merge this.
src/blockchain/bitcoin_rpc.rs
Outdated
vec![].into_iter().collect() | ||
} | ||
|
||
async fn setup<D: BatchDatabase + DatabaseUtils, P: Progress>( |
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.
It would also be nice if this could create watch-only wallets in Bitcoin Core. Otherwise the caller needs it's own "setup" logic.
To do this Magical would need to know the watch-only wallet name:
pub struct BitcoinRpcBlockchain(Option<Client>, Option<String>);
Where the string is the watch-only wallet name. None
would just use default wallet. Or we could not use an Option
to force people to use a watch-only wallet, which seems like a better idea. Then the BitcoinRpcBlockchain.setup
could:
- Call
loadwallet
- If it succeeds, check if the node recognizes our addresses.
- If yes, we're done.
- If no, export addresses.
- If it fails, call
createwallet
to create a new watch-only wallet.- If this succeeds, export addresses
- If it succeeds, check if the node recognizes our addresses.
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 implemented this, but didn't use loadwallet
because this RPC call isn't supported yet
- Create feature - Make sync algorithm more batch-friendly - Improve error handling - Add more fields to the RpcBlockchain struct: `wallet_name`, `network`, and `rescan_since` - Create and load watch-only wallets
This is ready for review.
In normal usage once we add batching,
I think this is pretty good. I wonder if that will be fast enough over Tor? In my limited experience doing RPC over Tor, it seems to take a few seconds sometimes. This is where it would be nice to move the import logic to a separate and paralleliz-able call ... |
@@ -19,6 +19,7 @@ reqwest = { version = "0.10", optional = true, features = ["json"] } | |||
futures = { version = "0.3", optional = true } | |||
clap = { version = "2.33", optional = true } | |||
base64 = { version = "^0.11", optional = true } | |||
bitcoincore-rpc = { git = "https://github.com/justinmoon/rust-bitcoincore-rpc", branch = "magical", optional = true } | |||
|
|||
# Platform-specific dependencies | |||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] |
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 I do something like this? Bitcoin RPC doesn't work in the browser ...
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 it's fine leaving it in the normal dependencies for now, even the electrum-client doesn't work but it's still up there...
load_wallet_err | ||
{ | ||
if load_wallet_err.message == format!("Wallet file verification failed: Error loading wallet {}. Duplicate -wallet filename specified.", config.wallet_name) { | ||
info!("Watch-only wallet already loaded: \"{}\"", &config.wallet_name); |
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.
Once listwallets support is added to rust-bitcoincore-rpc, then we can remove this ugly hack!
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 here you could use the raw call()
method to make the listwallets
call. Still kinda hacky but less than having to try I guess
panic!( | ||
"couldn't create watch-only bitcoin core wallet: {}", | ||
error.to_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.
Don't know what to do here.
wallet_name
doesn't exist- can't create
wallet_name
Maybe return a Error::BitcoinRpcCreateWalletFailed
error or something?
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.
Yeah, i think it makes sense to have a specific error for this
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.
Overall I really like this, thanks!
I would wait a little bit and see if they merge your fix for the getaddressinfo labels so that we can point the dependency to their git repo. If that starts taking a long time, I can just fork it in this org and we can use that fork temporarily.
I will make a little list of things that are kinda suboptimal now and that could be improved by a future pull request, so that we don't forget. Let me know if you think there's more to add:
- Implement RPC batching (waiting for library support)
- Use of
listwallets
(again, waiting for library support or alternative methods, see comment below) - Support pruned nodes by just rescanning the utxo set (or offer this as an option for users who don't care about the full history)
- Advertise
GetAnyTx
on nodes that havetxindex
enabled. (I'm not sure if this can be checked with an RPC call, maybe we could just add an option and if the user knows that the node is configured correctly, he can enable it)
let db_tip_height = database.iter_txs(false)?.iter().fold(0, |acc, tx| { | ||
if let Some(height) = tx.height { | ||
std::cmp::max(acc, height) | ||
} else { | ||
acc | ||
} | ||
}); |
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.
Just a suggestion based on my own personal preference, feel free to keep it the way it is if you like it more:
let db_top_height = database.iter_txs(false)?.iter().filter_map(|tx| tx.height).max().unwrap_or(0);
I haven't tested it but I think they should be equivalent. I personally like it more this way because I think the methods used on the iterator express what you are trying to do better (find the maximum height). fold
is generally used when you want to squash together all the items of an iterator, so it might be a little more confusing to somebody reading it because that's not really what you are doing here.
panic!( | ||
"couldn't create watch-only bitcoin core wallet: {}", | ||
error.to_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.
Yeah, i think it makes sense to have a specific error for this
|
||
impl OnlineBlockchain for RpcBlockchain { | ||
fn get_capabilities(&self) -> HashSet<Capability> { | ||
vec![].into_iter().collect() |
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 the FullHistory
capability should be advertised. It basically means that you can get all the historical transactions of the wallet and not just the ones that have outputs in the UTXO set.
Eventually I think it will make sense to add more options (and sometimes just adapt to the node's configuration) and dinamically add/remove capabilities, like:
- If the node has txindex enabled, then it also supports the
GetAnyTx
capability - If somebody wants to speed up the sync of his wallet or if the node is pruned, instead of doing a full rescan it could just rescan the utxo set. In that case
FullHistory
should be removed.
Anyways, I think it's fine like this for now, all these improvements could be part of a follow-up pull request.
load_wallet_err | ||
{ | ||
if load_wallet_err.message == format!("Wallet file verification failed: Error loading wallet {}. Duplicate -wallet filename specified.", config.wallet_name) { | ||
info!("Watch-only wallet already loaded: \"{}\"", &config.wallet_name); |
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 here you could use the raw call()
method to make the listwallets
call. Still kinda hacky but less than having to try I guess
This is outdated. We can just track this as an issue for now: #79. |
Removed Ord/PartialOrd derive rules for types.
No description provided.