-
Notifications
You must be signed in to change notification settings - Fork 36.2k
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
Near-Bugfix: Optimization: Minimize the number of times it is checked that no money... #8498
Conversation
src/main.cpp
Outdated
// are the actual inputs available? | ||
if (!inputs.HaveInputs(tx)) | ||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false, | ||
strprintf("%s: inputs missing/spent", __func__)); |
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.
nit: weird spacing 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.
Oh, that's how the editor indented by default. That's actually what we have in some other places, but having a glance searching for strprintf in main.cpp I see we're not being consistent with indentation of function calls broken into several lines
Example from the opening parenthesis position:
https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1354
Example 4 spaces from the beginning:
https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1110
Example freestyle:
https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1436
I'm happy to change it for something else, this maybe?
return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
strprintf("%s: inputs missing/spent", __func__));
EDIT: Actually the indentation is the same as from the place it's taken from: https://github.com/bitcoin/bitcoin/pull/8498/files#diff-7ec3c68a81efff79b6ca22ac1f1eabbaL2417
03d0f76
to
2569f80
Compare
Needed rebase. Besides, the previous version contained a bug. |
2569f80
to
c93d1cf
Compare
Needed rebase after renaming main.o, see #9260 (although needed, the rebase was clean in this case) |
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.
Concept ACK
src/validation.cpp
Outdated
@@ -646,18 +646,20 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C | |||
} | |||
} | |||
|
|||
// are the actual inputs available? | |||
// This redundant check doesn't trigger the DoS code on purpose; if it did, it would make it easier | |||
// for an attacker to attempt to split the network (Consensus::CheckTxInputs also checks 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.
I think you can change the view.HaveInputs(tx)
below into a Consensus::CheckTxInputs
call, doing some of the checks slightly earlier.
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.
Perhaps the new comment could be clearer, but the view.HaveInputs(tx)
check below sets state.DoS(0, ...)
instead of state.DoS(100, ...)
like Consensus::CheckTxInputs
would do.
Feel more than free to rephrase it in a way that would have been more clear to you.
src/validation.cpp
Outdated
@@ -1318,16 +1318,14 @@ int GetSpendHeight(const CCoinsViewCache& inputs) | |||
return pindexPrev->nHeight + 1; | |||
} | |||
|
|||
namespace Consensus { | |||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight) | |||
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& nFees) |
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.
Rather than forcing a bogus nFees
(or unused) everywhere, just wrap this function with an overload containing an unused nFees
stack variable.
Simpler. Less diff.
Also means anyone reviewing at some later date won't get confused as to whether nFees
is actually used or not.
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 only place where this makes sense is in txmempool.cpp. There you can do a much nicer wrapper there. The diff won't be smaller in total but there will be more lines in red (which people tend to like). I considered this before and I rembember @sipa said it would be fine to just remove the check in txmempool.cpp but I can't find the comment and he changed his mind about it. I will rewrite this for you to see and I'm happy to squash 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.
utACK, but see comment RE suggested change
Added a commit that may make @dcousens happier or not, thanks for making me remember. EDIT: I would be also be happy to take the function out of the consensus namespace "for free" here. That was a mistake on my part. |
7a17ce7
to
1590c19
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.
utACK 1590c19d3b4fa5d406cf2f91772960e11d0d2cb8
PR was initially confusing to me, but here are my notes on what it does:
- Changes
CheckTxInputs
to return DoS level100
and codeREJECT_INVALID
instead of0
and0
. - Adds
CheckTxInputs
nFees
in/out argument - Removes
CheckTxInputs
call fromCheckInputs
. Avoids changing behavior by having the two callers ofCheckInputs
(AcceptToMemoryPoolWorker
andConnectBlock
) callCheckTxInputs
themselves. - Changes
AcceptToMemoryPoolWorker
andConnectBlock
to use fees returned byCheckTxInputs
instead of computing fees themselves. - Updates calls to
CheckTxInputs
inCTxMemPool::check
. No impact there because mempool code ignores returned validation state and fees.
src/validation.cpp
Outdated
@@ -624,7 +624,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C | |||
CCoinsView dummy; | |||
CCoinsViewCache view(&dummy); | |||
|
|||
CAmount nValueIn = 0; | |||
CAmount nFees = 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.
In commit "Optimization: Minimize the number of times it is checked"
Would be good to declare nFees below close to where it is actually used.
src/validation.cpp
Outdated
@@ -1820,6 +1814,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd | |||
blockundo.vtxundo.reserve(block.vtx.size() - 1); | |||
std::vector<PrecomputedTransactionData> txdata; | |||
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated | |||
const int nHeight = pindex->pprev == NULL ? 0 : pindex->pprev->nHeight + 1; | |||
const int64_t nSpendHeight = block.vtx.size() > 1 ? GetSpendHeight(view) : nHeight; |
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.
In commit "Optimization: Minimize the number of times it is checked"
Can you add a comment explaining this line? Why do transactions in a block with vtx.size() of >= 2 have a different spend height than transactions in a block with vtx.size() == 1? Is nSpendHeight even used in a block with vtx.size() == 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.
If the block only has the coinbase tx before GetSpendHeight(view) would have not been called at all and starting doing so seems unnecessarily costly, see https://github.com/bitcoin/bitcoin/blob/master/src/validation.cpp#L1306
I was actually hoping that someone suggested to just remove this local variable directly and just use nHeight directly for the coinbase maturity check, assuming that is safe. I think so but would like others to confirm before trying it.
1590c19
to
edbb3f7
Compare
Needed rebase, hopefully fixed all nits. |
Tests for this PR seem to be failing currently, maybe due to the SpendHeight change? Only changes since my previous review were rebasing post-#8329 and the nFees and nSpendHeight changes commented on above. |
edbb3f7
to
7650b8a
Compare
Yes, the problem was in that change but not on stop using GetSpendHeight, just added +1 to the height by mistake. Updated. |
7650b8a
to
4d9e9a5
Compare
Needed rebase after #10195, it also needs more review now (AcceptToMemoryPoolWorker may return different DoS pnctuation [100 instead of 0] now, happy to fix if that's a problem). |
Some discussion of this in IRC https://botbot.me/freenode/bitcoin-core-dev/msg/87002756/ |
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.
utACK 4d9e9a5b7cb3e65bcf96ea5090ab6abaeba27640. Only changes since last review were removing a stray comment and fixing the spendheight failures.
src/validation.cpp
Outdated
if (!view.HaveInputs(tx)) | ||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), | ||
REJECT_INVALID, "bad-txns-inputs-missingorspent"); | ||
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, nFees)) |
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.
In commit "Optimization: Minimize the number of times"
If I understand correctly, it would be more correct to pass SpendHeight(view)
instead of pindex->nHeight
as the nSpendHeight argument, but in this case it doesn't matter because the value is only used for coinbase transactions, and this isn't a coinbase transaction? Or maybe there are other reasons why pindex->nHeight
is ok to pass?
Either way, I think this is confusing, and that there should be a comment here explaining the pindex->nHeight
value. Or maybe you could delete the nSpendHeight
argument and have CheckTxInputs
call GetSpendHeight(inputs)
when needed. This seems like it would be a simplification and I don't think there should be a performance cost because CheckTxInputs
seems to be skipped for coinbase transactions in all cases except for one call that invokes GetSpendHeight
anyway.
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 don't think it would be more correct (but I'm glad to be corrected) and performance would sufffer.
I think pindex->nHeight because that's actually what we want to validate here. In acceptToMemPool and CTxMemPool::check you don't know the height. Here, nSpendHeight should always be lower or equal to pindex->nHeight.
I'm happy to add a comment but not sure what it should be. Peharps the comment should be in GetSpendHeight instead of ConnectBlock().
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 happy to add a comment but not sure what it should be.
Comment could just say why it is better to pass pindex->nHeight as nSpendHeight here instead of GetSpendHeight(view). If the two values are always equal, or have some other relation, comment could just say what that relationship is. If this is too in the weeds, definitely feel free to skip this. I'm just suggesting what I think would make the code clearer for me.
Alternately, I don't know what you think of my suggestion to eliminate the nSpendHeight
argument and just call GetSpendHeight
in CheckTxInputs
. It does look to me like this would be logically equivalent and not effect performance, though maybe there's another reason not to 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.
Part of the optimization here is not calling GetSpendHeight for every tx in the block, and your suggestion would eliminate that part of the optimization.
For the comment, what about "We know the height, so we don't need to GetSpendHeight"?
it if more people agree.
I'm really not sure that comment would add that much value, but I don't mind adding
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 agree with @jtimon that it makes more sense for ConnectBlock to pass in pindex->nHeight, rather than get the spend height from the view, even though those are the same. We could add an assert that the view's best block has the same hash as pindex->pprev if that makes the code clearer -- but we have bigger problems than just coinbase maturity if the view is out of sync with our 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.
Not sure if this needs more review. This PR has two utACKs from dcousens and me, and a concept ack from sipa.
src/validation.cpp
Outdated
if (!view.HaveInputs(tx)) | ||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), | ||
REJECT_INVALID, "bad-txns-inputs-missingorspent"); | ||
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, nFees)) |
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 happy to add a comment but not sure what it should be.
Comment could just say why it is better to pass pindex->nHeight as nSpendHeight here instead of GetSpendHeight(view). If the two values are always equal, or have some other relation, comment could just say what that relationship is. If this is too in the weeds, definitely feel free to skip this. I'm just suggesting what I think would make the code clearer for me.
Alternately, I don't know what you think of my suggestion to eliminate the nSpendHeight
argument and just call GetSpendHeight
in CheckTxInputs
. It does look to me like this would be logically equivalent and not effect performance, though maybe there's another reason not to 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.
Concept ACK. I think this will slightly speed up validation time; I'm doing a benchmark to see if this is observable. Left one request and some style nits below.
src/consensus/tx_verify.h
Outdated
@@ -24,7 +26,7 @@ namespace Consensus { | |||
* This does not modify the UTXO set. This does not check scripts and sigs. | |||
* Preconditions: tx.IsCoinBase() is false. | |||
*/ | |||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight); | |||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& nFees); |
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 somewhat confusing that CheckTxInputs()
will be doing calculations on accumulated fee values, and not just the particular transaction passed in.
Can we just have CheckTxInputs
return the fee of the transaction passed in, and then the caller can decide what additional checks should happen? It would make more sense to me that the MoneyRange()
check on total block fees happen in ConnectBlock()
, rather than here (though I do think conceptually that is a reasonable check for us to add).
Alternatively, if we decide to go with the accumulated fees being checked here, I'd strongly prefer to rename this variable to something like "accumulated_fees" to make it clear what this is, and update the documentation to explain it. But I'd prefer to move the accumulation to the caller, and leave this function as operating on a single transaction.
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.
If the fee is returned, then we can't also return a bool, and we would need to duplicate the check in ConnectBlock, AcceptToMemeoryPool and CTxMemPool::check. And at that point the additional complexity wouldn't be worth it IMO.
We could also pass a fees input/output parameter that doesn't accumulate (although you can already enjoy that functionality by simply passing 0 to the variable). In that case, the duplication would only need to duplicateMoneyrange check in ConnectBlock, but I don't really see it as an improvement over this.
Agreed, accumulated_fees would be more readable with only 2 more lines needing to change
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.
@jtimon You can 'return' the fee in a tuple, or as a pass-by-reference value. So for example CheckTxInputs
would have CAmount& return_fee
field, and return_fee
would just be assigned that transaction's fee. The caller can then do the accumulated_fee += return_fee
logic. This involves no duplication, and still makes CheckTxInputs
purely operate on data for a single transaction.
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.
If the concern is that the addition with other fees is not done within the function, as documented the caller can set the in/out argument to zero before calling. I could also always return only the value for the single transaction without accumulating anything (although I don't see the gain, it's just more code), at that point the argument would be out only, not in/out.
From there, to return the output argument as a tuple or pair I think it's just making things uglier and unnecessarily complicated.
instead of:
CAmount tx_fee = 0; // You will initialize the variable even if the function starts setting it to zero
if (!CheckTxInputs(..., tx_fee))
return false;
accumulated_fee += tx_fee;
You would have something like:
struct CheckTxInputsReturn
{
bool fValid;
CAmount tx_fee;
}
CheckTxInputsReturn ret = CheckTxInputs(...);
if (!ret.fValid)
return false;
accumulated_fee += ret.tx_fee;
I think that's incredibly ugly. Specially since I don't see the problem with how it is currently used when you don't want to accumulate any fees:
CAmount tx_fee = 0;
if (!CheckTxInputs(..., tx_fee))
return false;
Please, I invite you to write your suggestions on top of this and see for yourselves that they are not an improvement but actually the contrary.
If people agree that those IMO much uglier solutions are better, I will squash your suggestions, no problem.
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 was just clarifying that @sdaftuar's suggestion does not imply duplication of logic. I personally think that it's a bit cleaner to do the summing of fees outside of the validation of a single function, but it's an unimportant nit for sure.
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.
Oh, sorry, the duplication comment was a mistake. Before I was checking the moneyRange for the accumulated fees and not just for the single tx fees, and I thought that check would need to be duplicated outside, but that was a change in functionality that I shouldn't be doing (and btw was missed in review).
Pedantically adding that check would be a softfork, but it should be impossible that the MoneyRange check on the accumulated fees fails anyway.
I can not accumulate anything if you guys prefer that, that's a simple change (even though I still can't understand why would you prefer that), reading your previous comment again better, you were also considering the pass by reference (what is done now), not necessarily the tuple (which is what I would be against in principle because of its ugliness).
src/validation.cpp
Outdated
} // end LOCK(pool.cs) | ||
|
||
CAmount nFees = 0; | ||
if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees)) |
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.
style nit: braces for one-line if
src/consensus/tx_verify.cpp
Outdated
if (!inputs.HaveInputs(tx)) | ||
return state.Invalid(false, 0, "", "Inputs unavailable"); | ||
// are the actual inputs available? | ||
if (!inputs.HaveInputs(tx)) |
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.
style nit: braces for one-line if
src/validation.cpp
Outdated
if (!view.HaveInputs(tx)) | ||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), | ||
REJECT_INVALID, "bad-txns-inputs-missingorspent"); | ||
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, nFees)) |
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 agree with @jtimon that it makes more sense for ConnectBlock to pass in pindex->nHeight, rather than get the spend height from the view, even though those are the same. We could add an assert that the view's best block has the same hash as pindex->pprev if that makes the code clearer -- but we have bigger problems than just coinbase maturity if the view is out of sync with our chain!
src/validation.cpp
Outdated
if (!view.HaveInputs(tx)) | ||
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), | ||
REJECT_INVALID, "bad-txns-inputs-missingorspent"); | ||
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, nFees)) |
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.
style nit: curly braces for one-line if
4d9e9a5
to
4731626
Compare
Hopefully fixed @sdaftuar 's nits. |
c154f59
to
7b78d8b
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.
src/consensus/tx_verify.h
Outdated
@@ -22,9 +24,12 @@ namespace Consensus { | |||
/** | |||
* Check whether all inputs of this transaction are valid (no double spends and amounts) | |||
* This does not modify the UTXO set. This does not check scripts and sigs. | |||
* @param[in,out] accumulated_fees this serves to get the fees of the tx as output. |
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.
nit: extra space at EOL here.
src/consensus/tx_verify.h
Outdated
* Preconditions: tx.IsCoinBase() is false. | ||
*/ | ||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight); | ||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& accumulated_fees); |
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.
Need to change var name here, too.
src/validation.cpp
Outdated
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, tx_fees)) { | ||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state)); | ||
} | ||
nFees += tx_fees; |
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 you're at it, can you please re-add the MoneyRange checks here that Gavin removed years ago (and maybe update the PR title to indicate that you're fixing Gavin's near-bug while also decreasing the number of CCoinsView map lookups).
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.
Specifically, commit 8d7849b broke the check at 8d7849b6db#diff-7ec3c68a81efff79b6ca22ac1f1eabbaR1110 and made it useless, which very narrowly didn't cause a major consensus failure and re-introduction of the original bitcoin-printing overflow bug.
…y is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2)
in 8d7849b This can potentially prevent an overflow that could at least in theory allow the creation of money.
b989b70
to
4e955c5
Compare
Fixed 1 commit by @danra |
utACK |
re-utACK 4e955c5 |
…it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces #6445 Near-Bugfix as pointed out in #8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
Rename assert_raises_jsonrpc to assert_raises_rpc_error in Namecoin tests for upstream refactoring. Adapt verification of names for bitcoin/bitcoin#8498. Conflicts: src/consensus/tx_verify.cpp src/consensus/tx_verify.h src/txmempool.cpp src/validation.cpp src/wallet/rpcdump.cpp test/functional/bumpfee.py test/util/data/txcreatemultisig1.json
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
…umber of times it is checked that no money..." This reverts commit 56d28c5.
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
…it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces #6445 Near-Bugfix as pointed out in bitcoin/bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
… times it is checked that no money... 4e955c5 Near-Bugfix: Reestablish consensus check removed in 8d7849b (Jorge Timón) 3e8c916 Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp (Jorge Timón) 832e074 Optimization: Minimize the number of times it is checked that no money is created (Jorge Timón) 3f0ee3e Proper indentation for CheckTxInputs and other minor fixes (Jorge Timón) Pull request description: ...is created by individual transactions to 2 places (but call only once in each): - ConnectBlock ( before calculated fees per txs twice ) - AcceptToMemoryPoolWorker ( before called CheckTxInputs 4 times and calculated fees per tx one extra time ) Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2) For more motivation: ~~https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493~~ jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments EDIT: partially replaces bitcoin#6445 Near-Bugfix as pointed out in bitcoin#8498 (comment) Tree-SHA512: c71188e7c7c2425c9170ed7b803896755a92fd22f43b136eedaa6e554106696f0b10271d0ef0d0127c1eaafbc31d12eb19143df4f1b6882feecedf6ef05ea346
b56607a Remove CCoinsViewCache::GetValueIn(...) (practicalswift) Pull request description: Remove `CCoinsViewCache::GetValueIn(...)`. Fixes #18858. It seems like `GetValueIn` was added in #748 ("Pay-to-script-hash (OP_EVAL replacement)", merged in 2012) and the last use in validation code was removed in #8498 ("Near-Bugfix: Optimization: Minimize the number of times it is checked that no money...", merged in 2017). `CCoinsViewCache::GetValueIn(…)` performs money summation like this: ```c++ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += AccessCoin(tx.vin[i].prevout).out.nValue; return nResult; } ``` Note that no check is done to make sure that the resulting `nResult` is such that it stays within the money bounds (`MoneyRange(nResult)`), or that the summation does not trigger a signed integer overflow. Proof of concept output: ``` coins.cpp:243:17: runtime error: signed integer overflow: 9223200000000000000 + 2100000000000000 cannot be represented in type 'long' GetValueIn = -9221444073709551616 ``` Proof of concept code: ```c++ CMutableTransaction mutable_transaction; mutable_transaction.vin.resize(4393); Coin coin; coin.out.nValue = MAX_MONEY; assert(MoneyRange(coin.out.nValue)); CCoinsCacheEntry coins_cache_entry; coins_cache_entry.coin = coin; coins_cache_entry.flags = CCoinsCacheEntry::DIRTY; CCoinsView backend_coins_view; CCoinsViewCache coins_view_cache{&backend_coins_view}; CCoinsMap coins_map; coins_map.emplace(COutPoint{}, std::move(coins_cache_entry)); coins_view_cache.BatchWrite(coins_map, {}); const CAmount total_value_in = coins_view_cache.GetValueIn(CTransaction{mutable_transaction}); std::cout << "GetValueIn = " << total_value_in << std::endl; ``` ACKs for top commit: MarcoFalke: ACK b56607a promag: Code review ACK b56607a. jb55: ACK b56607a hebasto: ACK b56607a, I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged. Tree-SHA512: 2c8402b5753ec96703d12c57c3eda8eccf999ed3519134a87faaf0838cfe44b94ef384296af2a524c06c8756c0245418d181af9083548e360905fac9d79215e6
b56607a Remove CCoinsViewCache::GetValueIn(...) (practicalswift) Pull request description: Remove `CCoinsViewCache::GetValueIn(...)`. Fixes bitcoin#18858. It seems like `GetValueIn` was added in bitcoin#748 ("Pay-to-script-hash (OP_EVAL replacement)", merged in 2012) and the last use in validation code was removed in bitcoin#8498 ("Near-Bugfix: Optimization: Minimize the number of times it is checked that no money...", merged in 2017). `CCoinsViewCache::GetValueIn(…)` performs money summation like this: ```c++ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += AccessCoin(tx.vin[i].prevout).out.nValue; return nResult; } ``` Note that no check is done to make sure that the resulting `nResult` is such that it stays within the money bounds (`MoneyRange(nResult)`), or that the summation does not trigger a signed integer overflow. Proof of concept output: ``` coins.cpp:243:17: runtime error: signed integer overflow: 9223200000000000000 + 2100000000000000 cannot be represented in type 'long' GetValueIn = -9221444073709551616 ``` Proof of concept code: ```c++ CMutableTransaction mutable_transaction; mutable_transaction.vin.resize(4393); Coin coin; coin.out.nValue = MAX_MONEY; assert(MoneyRange(coin.out.nValue)); CCoinsCacheEntry coins_cache_entry; coins_cache_entry.coin = coin; coins_cache_entry.flags = CCoinsCacheEntry::DIRTY; CCoinsView backend_coins_view; CCoinsViewCache coins_view_cache{&backend_coins_view}; CCoinsMap coins_map; coins_map.emplace(COutPoint{}, std::move(coins_cache_entry)); coins_view_cache.BatchWrite(coins_map, {}); const CAmount total_value_in = coins_view_cache.GetValueIn(CTransaction{mutable_transaction}); std::cout << "GetValueIn = " << total_value_in << std::endl; ``` ACKs for top commit: MarcoFalke: ACK b56607a promag: Code review ACK b56607a. jb55: ACK b56607a hebasto: ACK b56607a, I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged. Tree-SHA512: 2c8402b5753ec96703d12c57c3eda8eccf999ed3519134a87faaf0838cfe44b94ef384296af2a524c06c8756c0245418d181af9083548e360905fac9d79215e6
b56607a Remove CCoinsViewCache::GetValueIn(...) (practicalswift) Pull request description: Remove `CCoinsViewCache::GetValueIn(...)`. Fixes bitcoin#18858. It seems like `GetValueIn` was added in bitcoin#748 ("Pay-to-script-hash (OP_EVAL replacement)", merged in 2012) and the last use in validation code was removed in bitcoin#8498 ("Near-Bugfix: Optimization: Minimize the number of times it is checked that no money...", merged in 2017). `CCoinsViewCache::GetValueIn(…)` performs money summation like this: ```c++ CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += AccessCoin(tx.vin[i].prevout).out.nValue; return nResult; } ``` Note that no check is done to make sure that the resulting `nResult` is such that it stays within the money bounds (`MoneyRange(nResult)`), or that the summation does not trigger a signed integer overflow. Proof of concept output: ``` coins.cpp:243:17: runtime error: signed integer overflow: 9223200000000000000 + 2100000000000000 cannot be represented in type 'long' GetValueIn = -9221444073709551616 ``` Proof of concept code: ```c++ CMutableTransaction mutable_transaction; mutable_transaction.vin.resize(4393); Coin coin; coin.out.nValue = MAX_MONEY; assert(MoneyRange(coin.out.nValue)); CCoinsCacheEntry coins_cache_entry; coins_cache_entry.coin = coin; coins_cache_entry.flags = CCoinsCacheEntry::DIRTY; CCoinsView backend_coins_view; CCoinsViewCache coins_view_cache{&backend_coins_view}; CCoinsMap coins_map; coins_map.emplace(COutPoint{}, std::move(coins_cache_entry)); coins_view_cache.BatchWrite(coins_map, {}); const CAmount total_value_in = coins_view_cache.GetValueIn(CTransaction{mutable_transaction}); std::cout << "GetValueIn = " << total_value_in << std::endl; ``` ACKs for top commit: MarcoFalke: ACK b56607a promag: Code review ACK b56607a. jb55: ACK b56607a hebasto: ACK b56607a, I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged. Tree-SHA512: 2c8402b5753ec96703d12c57c3eda8eccf999ed3519134a87faaf0838cfe44b94ef384296af2a524c06c8756c0245418d181af9083548e360905fac9d79215e6
Summary: > Fixes #18858. > > It seems like `GetValueIn` was added in PR748 ("Pay-to-script-hash (OP_EVAL replacement)", merged in 2012) and the last use in validation code was removed in [[bitcoin/bitcoin#8498 | PR8498]] ("Near-Bugfix: Optimization: Minimize the number of times it is checked that no money...", merged in 2017). This is a backport of Core [[bitcoin/bitcoin#18859 | PR18859]] Test Plan: nja all check-all` Reviewers: #bitcoin_abc, majcosta Reviewed By: #bitcoin_abc, majcosta Differential Revision: https://reviews.bitcoinabc.org/D9071
...is created by individual transactions to 2 places (but call only once in each):
fees per tx one extra time )
Also call tx.GetValueOut() only once per call of CheckTxInputs (instead of 2)
For more motivation:
https://github.com/bitcoin/bitcoin/blob/master/src/main.cpp#L1493jtimon/bitcoin@0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments
EDIT: partially replaces #6445
Near-Bugfix as pointed out in #8498 (comment)