-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Add and use satToBtc
and btcToSat
util functions
#31356
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31356. ReviewsSee the guideline for information on the review process. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
2dff8fa
to
8ef6811
Compare
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
8ef6811
to
632766a
Compare
Concept -0, it seems like a huge change to factor out what is just a multiply/division. imo this only makes sense if the intent is to add extra validity checks to the functions. Could at least make sure that the return value from |
@@ -234,6 +234,14 @@ def from_binary(cls, stream): | |||
return obj | |||
|
|||
|
|||
def satToBtc(sat_value): | |||
return sat_value / COIN |
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.
so something like
def satToBtc(sat_value: int) -> Decimal:
return Decimal(sat_value) / COIN
def btcToSat(btc_value: Decimal) -> int:
return int(btc_value * COIN)
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.
Yes, I think this might be better. I've updated the PR.
632766a
to
42c0623
Compare
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
32a5b18
to
8aaa4ad
Compare
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.
Instead of repeating the diff in the pull request description (if someone was interested in the changes in detail, they could just look at the diff themselves), it would be better to mention the benefits/goals and how they are expected to be achieved for new code written after this was merged.
Possibly there is a case to have feerate conversion helpers, or a class to hold feerates. However, any "global" change here would need a solid motivation and long-term upside.
@@ -1159,18 +1159,18 @@ def run_test(self): | |||
self.log.info("Test transaction resurrection during a re-org") | |||
self.move_tip(76) | |||
self.next_block(77) | |||
tx77 = self.create_and_sign_transaction(out[24], 10 * COIN) | |||
tx77 = self.create_and_sign_transaction(out[24], btcToSat(10)) |
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 about this. I think writing 10 * COIN
with the meaning of "10 bitcoins" is self-explanatory and couldn't be clearer. btcToSat(10)
just seems like an extra step and extra complexity without a benefit?
Also, the "new" style isn't enforced, so you'll end up with both styles being used in the future, increasing the confusing further.
Finally, I had the impression that python code is using snake_case
, so btcToSat
would be confusing in that regard as well.
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.
While 10 * COIN
seems self-explanatory, I find the util function usage in the following diff more readable and easier on the eyes. Instead of having to process 3 things in one go, namely int conversion, sum() with an argument that's being calculated, multiplication with COIN, I have to process only one function call with the said argument.
- input_amount = int(sum([utxo['value'] for utxo in utxos_to_spend]) * COIN)
+ input_amount = btcToSat(sum([utxo['value'] for utxo in utxos_to_spend]))
Introduce utility functions `satToBtc` and `btcToSat` to simplify and standardize conversions between satoshis and bitcoins in functional tests
8aaa4ad
to
a15e9ae
Compare
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 picking this up! Left few suggestions.
Can the PR be split into 2 commits for each util function that will make it easier to process piece by piece?
def satToBtc(sat_value: int) -> Decimal: | ||
return Decimal(sat_value) / COIN | ||
|
||
|
||
def btcToSat(btc_value: Decimal) -> int: | ||
return int(btc_value * COIN) |
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 see that COIN
is defined in this file but not sure if this is the right file to put these functions in, maybe util.py
?
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 for using camelCase in the issue description, snake_case is preferred in functional tests.
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 is definitely the wrong file, I couldn't even find this change
tx_val = 0.001 | ||
tx.vout = [CTxOut(int(Decimal(tx_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))] | ||
tx.vout = [CTxOut(btcToSat(Decimal(tx_val)), CScript([OP_RETURN] + [OP_FALSE] * 30))] |
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 this utility function can become more useful if it accepts float too, thereby getting rid of explicit conversion while calling?
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.
Python float to decimal conversion via string: https://stackoverflow.com/questions/316238/python-float-to-decimal-conversion#comment107437133_316253
def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.00001 * COIN, _total_txs=None): | ||
def branch(prevout, initial_value, max_txs, tree_width=5, fee=None, _total_txs=None): | ||
if fee is None: | ||
fee = btcToSat(0.00001) |
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.
- def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.00001 * COIN, _total_txs=None):
+ def branch(prevout, initial_value, max_txs, tree_width=5, fee=btcToSat(0.00001), _total_txs=None):
Seems to work.
@@ -1159,18 +1159,18 @@ def run_test(self): | |||
self.log.info("Test transaction resurrection during a re-org") | |||
self.move_tip(76) | |||
self.next_block(77) | |||
tx77 = self.create_and_sign_transaction(out[24], 10 * COIN) | |||
tx77 = self.create_and_sign_transaction(out[24], btcToSat(10)) |
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.
While 10 * COIN
seems self-explanatory, I find the util function usage in the following diff more readable and easier on the eyes. Instead of having to process 3 things in one go, namely int conversion, sum() with an argument that's being calculated, multiplication with COIN, I have to process only one function call with the said argument.
- input_amount = int(sum([utxo['value'] for utxo in utxos_to_spend]) * COIN)
+ input_amount = btcToSat(sum([utxo['value'] for utxo in utxos_to_spend]))
# Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output | ||
tx_size = len(tx.serialize().hex())//2 + 120*num_inputs + 50 | ||
tx.vout.append(CTxOut(int(value - self.relayfee * tx_size * COIN / 1000), SCRIPT_W0_SH_OP_TRUE)) |
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.
Possibly there is a case to have feerate conversion helpers, or a class to hold feerates.
Agree, a fee rate conversion helper here would make reading this far easier.
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 conversion was not intuitive to me in the first glance: #30079 (comment)
tx2_val = '20.99' | ||
tx2.vout = [CTxOut(int(Decimal(tx2_val) * COIN), CScript([OP_RETURN] + [OP_FALSE] * 30))] | ||
tx2.vout = [CTxOut(btcToSat(Decimal(tx2_val)), CScript([OP_RETURN] + [OP_FALSE] * 30))] |
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 accepting a string with internal string to decimal checking and conversion would also make it more flexible? The explicit Decimal
conversion could be removed here then.
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.
An alternative idea would be to add a btcStringToSat
function, instead of overloading btcToSat
on type, as this makes type checking harder.
fee_delta_b = satToBtc(Decimal(9999)) | ||
fee_delta_c_1 = satToBtc(Decimal(-1234)) | ||
fee_delta_c_2 = satToBtc(Decimal(8888)) |
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.
Doesn't satToBtc
accept an int
?
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.
Yes, passing sats as a decimal should never be necessary.
🐙 This pull request conflicts with the target branch and needs rebase. |
Closing, given the author has said in #31345 that someone else can take it over. |
Introduce utility functions
satToBtc
andbtcToSat
to simplify and standardize conversions between satoshis and bitcoins in functional tests#closes #31345
This PR implements the solution proposed in the issue. The goal is to simplify conversions between satoshis and bitcoins in the functional tests by using utility functions. For example, code like
fee_rate=Decimal(feerate * 1000) / COIN
could becomefee_rate=satToBtc(feerate * 1000)
in the proposed solution.An additional benefit of satToBtc() is that it ensures the use of Decimal.
This issue was briefly mentioned in this discussion, where the conversion
Decimal(value) / COIN
was noted to be repetitive.While some may prefer to continue using the
/ COIN
and* COIN
conversions, I don’t have a strong preference either way. I’d like to hear your opinions and, if needed, implement the approach that works best.