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

Add RPC call 'getblockstats' #157

Merged
merged 6 commits into from
Mar 1, 2022
Merged

Add RPC call 'getblockstats' #157

merged 6 commits into from
Mar 1, 2022

Conversation

gcomte
Copy link
Contributor

@gcomte gcomte commented Jan 19, 2021

getblockstats is available in Bitcoin Core since version 0.17.0 .

It won't work for some heights with pruning.
It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.

More info (here)[https://bitcoincore.org/en/doc/0.17.0/rpc/blockchain/getblockstats/]

I'm completely new to Rust and this is my first Rust-PR ever, so please have mercy.

@stevenroose
Copy link
Collaborator

It seems that in 0.18 this call needs -txindex=1. You can add this to fix that:

diff --git a/integration_test/run.sh b/integration_test/run.sh
index b40aa78..97925fd 100755
--- a/integration_test/run.sh
+++ b/integration_test/run.sh
@@ -29,6 +29,7 @@ if bitcoind -version | grep -q "v0\.2"; then
 fi
 
 bitcoind -regtest $BLOCKFILTERARG $FALLBACKFEEARG \
+    -txindex=1 \
     -datadir=${TESTDIR}/2 \
     -connect=127.0.0.1:12348 \
     -rpcport=12349 \

@stevenroose
Copy link
Collaborator

The rest looks good to me!

@@ -439,6 +439,10 @@ pub trait RpcApi: Sized {
self.call("getblockhash", &[height.into()])
}

fn get_block_stats(&self, height: u64) -> Result<json::GetBlockStatsResult> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This can also accept the block hash instead of the height, maybe worth supporting it?

There's also an option for selecting which fields you want statistics for. Though this would require changing all the GetBlockStatsResult fields to be an Option<T>, which isn't great.

Copy link
Collaborator

Choose a reason for hiding this comment

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

All of them?

Copy link
Contributor

@shesek shesek Jan 25, 2021

Choose a reason for hiding this comment

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

If we want to support getting a specific list of fields from getblockstats, then I'm afraid yes...

Perhaps it could be a separate struct? So we have get_block_stats(height) -> GetBlockStatsResult and get_block_stats_fields(height, fields) -> GetBlockStatsResultPartial. Maintaining this would be annoying though, but perhaps not so bad with some macros?

Copy link
Contributor Author

@gcomte gcomte Jan 27, 2021

Choose a reason for hiding this comment

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

Okay, I proposed some code for this :-) Please check out this commit eb5cb8b @shesek

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good! Commented with two small nits

json/src/lib.rs Outdated
pub total_size: usize,
pub total_weight: usize,
#[serde(rename = "totalfee")]
pub total_fee: u64,
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a bitcoin::Amount (will also require with = "bitcoin::util::amount::serde::as_sat" in the derive).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh yeah, true, we're using those in this crate.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I understand, bitcoin::Amount should then also be used for: avg_fee, fee_rate_percentiles, max_fee, median_fee and min_fee, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When I try too define the fields as Option<Amount>, the compiler throws the follwoing error at me: the trait SerdeAmount is not implemented for std::option::Option<Amount>

Any idea how I should deal with this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, and also avg_fee_rate, max_fee_rate, min_fee_rate, total_fee, subsidy and total_out.

Note that unlike most other RPCs in bitcoind, the feerates here are represented in sat/vB rather than BTC/KB, while amounts are in satoshis rather than BTC.

json/src/lib.rs Outdated
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct GetBlockStatsResult {
#[serde(rename = "avgfee")]
pub avg_fee: u32,
Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC there's a preference by the folks here to use u64 over u32/usize. Maybe @stevenroose can explain more.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I suppose this can also be an Amount, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh right, this could. But I was referring to all the u32 fields, not just that one

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would appreciate some more info about 'using u64 over u32/usize for all fields'. @stevenroose ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just that we use 64-bit numbers for amounts. But in this crate, we are mostly using the dedicated Amount type. You can find some other usages of that type and the serde-tag you have to use with it.

@@ -443,6 +443,14 @@ pub trait RpcApi: Sized {
self.call("getblockstats", &[height.into()])
}

fn get_block_stats_fields(&self, height: u64, fields: &Vec<bitcoincore_rpc_json::BlockStatsFields>) -> Result<json::GetBlockStatsResultPartial> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can use fields: &[bitcoincore_rpc_json::BlockStatsFields] so it also accepts slices. And bitcoincore_rpc_json is also aliased as just json.

@gcomte
Copy link
Contributor Author

gcomte commented Feb 7, 2021

With commit 03b7fa9, I have now a version that works (with Amounts), but it has also added a ton of boilerplate code.

Still open is the question, about whether I should use u64 over u32 for the fields avg_tx_size, max_tx_sizemax_tx_size, median_time, median_tx_size, min_tx_size, time, and potentially i64 over i32 for the fields utxo_increase and utxo_size_inc.

@0xB10C
Copy link
Contributor

0xB10C commented Feb 12, 2021

I'd say

  • avg_tx_size, max_tx_size, median_tx_size and min_tx_size can be a u32 as single block will currently will always be smaller than 4_000_000 bytes (thus limiting the transaction size to something less)
  • time and median_time should be u64
  • utxo_increase can be i32 unless I'm missing something, if you really want to be safe then i64
  • utxo_size_inc maybe i64, also not sure here

@gcomte
Copy link
Contributor Author

gcomte commented Feb 22, 2021

Thanks for your input @0xB10C, I'll wait for more comments from @stevenroose and @shesek about your suggestion.

@stevenroose
Copy link
Collaborator

I agree with @0xB10C 's suggestions :)

@stevenroose
Copy link
Collaborator

Could you also rebase to make CI happy?

@gcomte
Copy link
Contributor Author

gcomte commented Mar 14, 2021

Rebased. Travis seems to have a problem still, concerning the -txindex enabled on Bitcoin Core versions 18.x .

I've update the data type for timestamps in commit 890c211.
Please note that this introduces inconsistencies about what data type is used for timestamps within this library: bbf0532

@0xB10C Here's my rationale for why i32 should do the job for both utxo_increase and utxo_size_inc:

Given a maximum block size of 4_000_000 bytes, there is no way how the UTXO set could increase or decrease beyond that number per-block ( = utxo_size_inc) in any way. Consequently, utxo_increase will also fit into a i32, as it is by definition always closer to 0 than utxo_size_inc.

i32 range: -2_147_483_648 - 2_147_483_647

@@ -9,6 +9,7 @@ mkdir -p ${TESTDIR}/1 ${TESTDIR}/2
killall -9 bitcoind

bitcoind -regtest \
-txindex=1 \
Copy link
Contributor

Choose a reason for hiding this comment

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

The txindex argument was added to the wrong bitcoind instance imo. There's another one started a few lines below (line 32, idk why), which is used for testing apparently as the RPC_URL env var is set to its port. That's probably why the 0.18.* tests fail, possibly because -blockfilterindex=1 is set for all other versions and works for stats too?

Copy link
Contributor Author

@gcomte gcomte Mar 15, 2021

Choose a reason for hiding this comment

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

You are right, the one below has the flag -server=1 set, while the one above has it set to 0.
I moved the flag in commit f7d1f3bce957be592b6f90d1f7667e2a008a1022.

@gcomte
Copy link
Contributor Author

gcomte commented Mar 14, 2021

Just to get a rough idea about the field utxo_increase I looked up the past 4500 blocks:

Lowest increase:
for i in $(seq 670000 674578); do bitcoin-cli getblockstats $i | jq -r ".utxo_size_inc"; done | sort -n | head -n 1
Result: -732_265

Highest increase:
for i in $(seq 670000 674578); do bitcoin-cli getblockstats $i | jq -r ".utxo_size_inc"; done | sort -n | tail -n 1
Result: 1_086_480

@sgeisler
Copy link
Contributor

Is this PR still active? Sorry for the wait. We are not good at keeping track of PRs, so pinging reviewers generally helps.

@gcomte
Copy link
Contributor Author

gcomte commented Jul 20, 2021

@sgeisler Yes it is still active. I just rebased it, so it should be ready to be merged.

Okay thank you for the information, will ping you guys every now and then :-)

@shesek
Copy link
Contributor

shesek commented Jul 20, 2021

All looks good to me, ACK 6af032a. Thanks for the contribution!

Edit: actually, one small last nit is that the get_rpc_keyword method could instead be an implementation for Display. But it's fine by me either way.

@gcomte
Copy link
Contributor Author

gcomte commented Jul 21, 2021

Hey @shesek, good input, thank you!

I tried to address this with the commit e0583c4 and then further simplified it with the commit fdef9f2.
What do you think?

@shesek
Copy link
Contributor

shesek commented Jul 21, 2021

@gcomte Looks good! re-ACK fdef9f2

@gcomte
Copy link
Contributor Author

gcomte commented Jul 22, 2021

@sgeisler @stevenroose Looks like this PR is ready to be reviewed/merged.

@gcomte
Copy link
Contributor Author

gcomte commented Aug 31, 2021

How is the progress on this guys? Is there something else I could provide you with, to assist you?

@gcomte
Copy link
Contributor Author

gcomte commented Nov 3, 2021

I rebased this again, so it is once again, ready to be merged.

@gcomte
Copy link
Contributor Author

gcomte commented Nov 30, 2021

I rebased this again, so it is once again, ready to be merged.

@RCasatta
Copy link
Collaborator

RCasatta commented Feb 3, 2022

ACK d83b8fe
tested with CI at https://github.com/RCasatta/rust-bitcoincore-rpc/actions/runs/1790852210

I am going to wait some days before merging, it would be great this rebase to master and squash some commits

@gcomte gcomte force-pushed the master branch 3 times, most recently from a1d803b to 14a1d36 Compare February 4, 2022 00:55
@gcomte
Copy link
Contributor Author

gcomte commented Feb 4, 2022

@RCasatta thanks for the review, rebased and squashed some commits.

Copy link
Collaborator

@RCasatta RCasatta left a comment

Choose a reason for hiding this comment

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

utACK 60b0dd7

will merge soon if there is no more feedback

@gcomte
Copy link
Contributor Author

gcomte commented Feb 28, 2022

Hey @RCasatta

Friendly reminder that 3 weeks have passed. Could you specify soon?

@RCasatta RCasatta merged commit 9bbca7f into rust-bitcoin:master Mar 1, 2022
@RCasatta
Copy link
Collaborator

RCasatta commented Mar 1, 2022

Sorry for the delay and thanks for the contribution

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.

6 participants