Near-Bugfix: Optimization: Minimize the number of times it is checked that no money… #8498

pull jtimon wants to merge 4 commits into bitcoin:master from jtimon:0.13-consensus-inputs changing 4 files +69 −62
  1. jtimon commented at 3:44 am on August 11, 2016: contributor

    …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 https://github.com/jtimon/bitcoin/compare/0.13-consensus-inputs...jtimon:0.13-consensus-inputs-comments

    EDIT: partially replaces #6445

    Near-Bugfix as pointed out in #8498 (review)

  2. in src/main.cpp: in 03d0f762f2 outdated
    1932-        if (!inputs.HaveInputs(tx))
    1933-            return state.Invalid(false, 0, "", "Inputs unavailable");
    1934+    // are the actual inputs available?
    1935+    if (!inputs.HaveInputs(tx))
    1936+        return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
    1937+                         strprintf("%s: inputs missing/spent", __func__));
    


    dcousens commented at 4:48 am on August 11, 2016:
    nit: weird spacing here?

    jtimon commented at 6:55 pm on August 11, 2016:

    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?

    0        return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
    1            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

  3. laanwj added the label Consensus on Aug 11, 2016
  4. jtimon force-pushed on Sep 1, 2016
  5. jtimon commented at 4:47 pm on September 1, 2016: contributor
    Needed rebase. Besides, the previous version contained a bug.
  6. jtimon force-pushed on Dec 3, 2016
  7. jtimon commented at 6:26 am on December 3, 2016: contributor
    Needed rebase after renaming main.o, see #9260 (although needed, the rebase was clean in this case)
  8. in src/validation.cpp:461 in c93d1cf269 outdated
    645@@ -646,18 +646,20 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
    646             }
    647         }
    648 
    649-        // are the actual inputs available?
    650+        // This redundant check doesn't trigger the DoS code on purpose; if it did, it would make it easier
    651+        // for an attacker to attempt to split the network (Consensus::CheckTxInputs also checks this).
    


    sipa commented at 3:07 pm on April 9, 2017:
    I think you can change the view.HaveInputs(tx) below into a Consensus::CheckTxInputs call, doing some of the checks slightly earlier.

    jtimon commented at 7:43 pm on April 18, 2017:
    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.
  9. sipa commented at 3:11 pm on April 9, 2017: member
    Concept ACK
  10. in src/validation.cpp:1313 in c93d1cf269 outdated
    1317@@ -1318,16 +1318,14 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
    1318     return pindexPrev->nHeight + 1;
    1319 }
    1320 
    1321-namespace Consensus {
    1322-bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
    1323+bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& nFees)
    


    dcousens commented at 11:12 pm on April 9, 2017:

    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.


    jtimon commented at 8:00 pm on April 18, 2017:
    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.
  11. dcousens approved
  12. dcousens commented at 11:14 pm on April 9, 2017: contributor
    utACK, but see comment RE suggested change
  13. jtimon commented at 8:51 pm on April 18, 2017: contributor

    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.

  14. jtimon force-pushed on Apr 18, 2017
  15. jtimon force-pushed on Apr 19, 2017
  16. in src/validation.cpp:627 in dd733d06d8 outdated
    623@@ -624,7 +624,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
    624         CCoinsView dummy;
    625         CCoinsViewCache view(&dummy);
    626 
    627-        CAmount nValueIn = 0;
    628+        CAmount nFees = 0;
    


    ryanofsky commented at 8:03 pm on May 8, 2017:

    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.

  17. in src/validation.cpp:1818 in dd733d06d8 outdated
    1813@@ -1820,6 +1814,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
    1814     blockundo.vtxundo.reserve(block.vtx.size() - 1);
    1815     std::vector<PrecomputedTransactionData> txdata;
    1816     txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
    1817+    const int nHeight = pindex->pprev == NULL ? 0 : pindex->pprev->nHeight + 1;
    1818+    const int64_t nSpendHeight = block.vtx.size() > 1 ? GetSpendHeight(view) : nHeight;
    


    ryanofsky commented at 9:08 pm on May 8, 2017:

    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?


    jtimon commented at 7:04 pm on May 18, 2017:
    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.
  18. ryanofsky commented at 9:14 pm on May 8, 2017: member

    utACK 1590c19d3b4fa5d406cf2f91772960e11d0d2cb8

    PR was initially confusing to me, but here are my notes on what it does:

    • Changes CheckTxInputs to return DoS level 100 and code REJECT_INVALID instead of 0 and 0.
    • Adds CheckTxInputs nFees in/out argument
    • Removes CheckTxInputs call from CheckInputs. Avoids changing behavior by having the two callers of CheckInputs (AcceptToMemoryPoolWorker and ConnectBlock) call CheckTxInputs themselves.
    • Changes AcceptToMemoryPoolWorker and ConnectBlock to use fees returned by CheckTxInputs instead of computing fees themselves.
    • Updates calls to CheckTxInputs in CTxMemPool::check. No impact there because mempool code ignores returned validation state and fees.
  19. jtimon force-pushed on May 19, 2017
  20. jtimon commented at 4:36 am on May 19, 2017: contributor
    Needed rebase, hopefully fixed all nits.
  21. ryanofsky commented at 7:24 pm on May 23, 2017: member

    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.

  22. jtimon force-pushed on May 30, 2017
  23. jtimon commented at 6:11 pm on May 30, 2017: contributor
    Yes, the problem was in that change but not on stop using GetSpendHeight, just added +1 to the height by mistake. Updated.
  24. jtimon force-pushed on Jun 2, 2017
  25. jtimon commented at 1:06 am on June 2, 2017: contributor
    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).
  26. ryanofsky commented at 9:20 pm on June 8, 2017: member
  27. in src/validation.cpp:1622 in 48e308d208 outdated
    1618@@ -1622,9 +1619,8 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
    1619 
    1620         if (!tx.IsCoinBase())
    1621         {
    1622-            if (!view.HaveInputs(tx))
    1623-                return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
    1624-                                 REJECT_INVALID, "bad-txns-inputs-missingorspent");
    1625+            if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, nFees))
    


    ryanofsky commented at 6:54 pm on June 14, 2017:

    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.


    jtimon commented at 6:50 pm on June 17, 2017:

    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().


    ryanofsky commented at 6:14 pm on June 21, 2017:

    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.


    jtimon commented at 1:54 am on June 22, 2017:
    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

    sdaftuar commented at 3:34 pm on June 23, 2017:
    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!

    sdaftuar commented at 3:34 pm on June 23, 2017:
    style nit: curly braces for one-line if
  28. ryanofsky commented at 7:03 pm on June 14, 2017: member
    utACK 4d9e9a5b7cb3e65bcf96ea5090ab6abaeba27640. Only changes since last review were removing a stray comment and fixing the spendheight failures.
  29. ryanofsky commented at 6:16 pm on June 21, 2017: member
    Not sure if this needs more review. This PR has two utACKs from dcousens and me, and a concept ack from sipa.
  30. in src/consensus/tx_verify.h:29 in 4d9e9a5b7c outdated
    25@@ -24,7 +26,7 @@ namespace Consensus {
    26  * This does not modify the UTXO set. This does not check scripts and sigs.
    27  * Preconditions: tx.IsCoinBase() is false.
    28  */
    29-bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
    30+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& nFees);
    


    sdaftuar commented at 1:14 pm on June 23, 2017:

    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.


    jtimon commented at 0:23 am on June 25, 2017:

    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


    sipa commented at 1:39 am on June 27, 2017:
    @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.

    jtimon commented at 4:56 am on June 27, 2017:

    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:

    0CAmount tx_fee = 0; // You will initialize the variable even if the function starts setting it to zero
    1if (!CheckTxInputs(..., tx_fee))
    2   return false;
    3accumulated_fee += tx_fee;
    

    You would have something like:

    0struct CheckTxInputsReturn
    1{
    2   bool fValid;
    3   CAmount tx_fee;
    4}
    5
    6CheckTxInputsReturn ret = CheckTxInputs(...);
    7if (!ret.fValid)
    8   return false;
    9accumulated_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:

    0CAmount tx_fee = 0;
    1if (!CheckTxInputs(..., tx_fee))
    2   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.


    sipa commented at 5:00 am on June 27, 2017:
    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.

    jtimon commented at 5:17 am on June 27, 2017:

    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).

  31. in src/validation.cpp:530 in 4d9e9a5b7c outdated
    522@@ -526,7 +523,12 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
    523         // CoinsViewCache instead of create its own
    524         if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
    525             return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
    526-        }
    527+
    528+        } // end LOCK(pool.cs)
    529+
    530+        CAmount nFees = 0;
    531+        if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), nFees))
    


    sdaftuar commented at 1:16 pm on June 23, 2017:
    style nit: braces for one-line if
  32. in src/consensus/tx_verify.cpp:207 in 4d9e9a5b7c outdated
    207-        // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
    208-        // for an attacker to attempt to split the network.
    209-        if (!inputs.HaveInputs(tx))
    210-            return state.Invalid(false, 0, "", "Inputs unavailable");
    211+    // are the actual inputs available?
    212+    if (!inputs.HaveInputs(tx))
    


    sdaftuar commented at 3:26 pm on June 23, 2017:
    style nit: braces for one-line if
  33. sdaftuar changes_requested
  34. sdaftuar commented at 3:39 pm on June 23, 2017: member
    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.
  35. jtimon force-pushed on Jun 25, 2017
  36. jtimon commented at 2:19 am on June 25, 2017: contributor
    Hopefully fixed @sdaftuar ’s nits. Also add a third commit to properly indent CheckTxInputs and other minor style fixes like braces for one line ifs while at it.
  37. in src/consensus/tx_verify.h:27 in 47316266a6 outdated
    23@@ -22,9 +24,12 @@ namespace Consensus {
    24 /**
    25  * Check whether all inputs of this transaction are valid (no double spends and amounts)
    26  * This does not modify the UTXO set. This does not check scripts and sigs.
    27+ * @param[in,out] accumulated_fees this serves to get the fees of the tx as output. 
    


    TheBlueMatt commented at 5:26 pm on June 26, 2017:
    nit: extra space at EOL here.
  38. jtimon commented at 6:05 am on June 27, 2017: contributor

    Added a couple of commits to be squashed. I wouldn’t personally squash the latter but it seems @sdaftuar and @sipa would like it more this way and I don’t care. Before squashing I will also move the indentation commit to the first thing.

    EDIT: already squashed one, updated OP.

  39. jtimon force-pushed on Jun 27, 2017
  40. in src/consensus/tx_verify.h:30 in 7b78d8b7e0 outdated
    23@@ -22,9 +24,10 @@ namespace Consensus {
    24 /**
    25  * Check whether all inputs of this transaction are valid (no double spends and amounts)
    26  * This does not modify the UTXO set. This does not check scripts and sigs.
    27+ * @param[out] nTxFee this serves to get the fees of the tx as output. 
    28  * Preconditions: tx.IsCoinBase() is false.
    29  */
    30-bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight);
    31+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& accumulated_fees);
    


    TheBlueMatt commented at 4:51 pm on June 27, 2017:
    Need to change var name here, too.
  41. in src/validation.cpp:1640 in 7b78d8b7e0 outdated
    1638-                                 REJECT_INVALID, "bad-txns-inputs-missingorspent");
    1639+            CAmount tx_fees = 0;
    1640+            if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, tx_fees)) {
    1641+                return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
    1642+            }
    1643+            nFees += tx_fees;
    


    TheBlueMatt commented at 5:44 pm on June 27, 2017:
    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).

    TheBlueMatt commented at 6:53 pm on June 27, 2017:
    Specifically, commit 8d7849b6db5f54dc32fe4f8c6c7283068473cd21 broke the check at https://github.com/bitcoin/bitcoin/commit/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.
  42. TheBlueMatt commented at 5:59 pm on June 27, 2017: member
    Totally agree with @sipa and @sdaftuar, thanks for making it a non-accumulator. Generally looks good, obviously needs squash.
  43. jtimon force-pushed on Jul 4, 2017
  44. jtimon commented at 4:05 pm on July 4, 2017: contributor
    Squashed the non-accumulator commit. Hopefully fixed all @TheBlueMatt ’s nits, good catch. Also s/nTxFee/tx_fees/ to comply with the new style.
  45. jtimon force-pushed on Jul 4, 2017
  46. jtimon renamed this:
    Optimization: Minimize the number of times it is checked that no money...
    Near-Bugfix: Optimization: Minimize the number of times it is checked that no money...
    on Jul 4, 2017
  47. in src/validation.cpp:1643 in 3161a7c9ef outdated
    1641+                return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
    1642+            }
    1643+            nFees += tx_fees;
    1644+            if (!MoneyRange(nFees)) {
    1645+                 state.DoS(100, false, REJECT_INVALID, "bad-txns-accumulated-fee-outofrange");
    1646+                 return error("%s: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
    


    TheBlueMatt commented at 7:25 pm on July 11, 2017:
    Why not use the normal formatting here of return state.DoS(100, error(), …)?

    jtimon commented at 0:23 am on July 13, 2017:
    No reason, will change
  48. TheBlueMatt commented at 7:25 pm on July 11, 2017: member
    utACK 3161a7c9ef6e19696a79776b38e3e5e4b6a67940
  49. jtimon force-pushed on Jul 13, 2017
  50. jtimon commented at 0:29 am on July 13, 2017: contributor
    Fixed latest nit.
  51. jtimon force-pushed on Jul 13, 2017
  52. laanwj added this to the "Blockers" column in a project

  53. in src/consensus/tx_verify.cpp:246 in 736cf73ab3 outdated
    278-        nFees += nTxFee;
    279-        if (!MoneyRange(nFees))
    280-            return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
    281+    // Tally transaction fees
    282+    tx_fees = nValueIn - value_out;
    283+    if (tx_fees < 0) {
    


    jimpo commented at 7:33 pm on August 17, 2017:
    Isn’t this redundant given the check on line 239?

    jtimon commented at 7:42 am on August 18, 2017:
    Yes, I think so, unless I’m missing something about some weird overflow. Besides it is also included in MoneyRange, so actually both checks are redundant, but at some point IIRC someone asked to not unify in bad-txns-fee-outofrange. But I think we can choose to ditch either bad-txns-in-belowout or bad-txns-fee-negative. I don’t have a strong preference.
  54. jtimon commented at 9:19 pm on August 24, 2017: contributor
    Hopefully fixed @jimpo ’s nit. Didn’t squashed yet just in case, but it seems pretty obviously correct in removing a redundancy that cannot be tested and thus is not being tested.
  55. in src/consensus/tx_verify.h:27 in 434f86b0bb outdated
    23@@ -22,9 +24,10 @@ namespace Consensus {
    24 /**
    25  * Check whether all inputs of this transaction are valid (no double spends and amounts)
    26  * This does not modify the UTXO set. This does not check scripts and sigs.
    27+ * @param[out] tx_fees this serves to get the fees of the tx as output. 
    


    promag commented at 11:16 pm on September 1, 2017:
    * [@params](/bitcoin-bitcoin/contributor/params/)[out] tx_fees Set to the transaction fee if successful.
  56. in src/consensus/tx_verify.cpp:245 in 434f86b0bb outdated
    277+        return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
    278+            strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
    279+    }
    280+
    281+    // Tally transaction fees
    282+    tx_fees = nValueIn - value_out;
    


    promag commented at 11:24 pm on September 1, 2017:
    Why was/is plural?

    jtimon commented at 10:48 pm on September 5, 2017:
    no good reason, let’s make it singular
  57. in src/txmempool.cpp:614 in 434f86b0bb outdated
    610@@ -611,6 +611,15 @@ void CTxMemPool::clear()
    611     _clear();
    612 }
    613 
    614+static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t nSpendHeight)
    


    promag commented at 11:24 pm on September 1, 2017:
    Use snake_case on new code.
  58. in src/validation.cpp:534 in 434f86b0bb outdated
    527@@ -531,6 +528,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
    528         // CoinsViewCache instead of create its own
    529         if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
    530             return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final");
    531+
    532+        } // end LOCK(pool.cs)
    533+
    534+        CAmount nFees = 0;
    


    promag commented at 11:31 pm on September 1, 2017:
    tx_fees or just fees?

    jtimon commented at 10:54 pm on September 5, 2017:
    That would be more extra disruption only for style. We can do that at any time. Including potentially more rebase work fixing conflicts with other things touching AcceptToMemoryPoolWorker. Can we leave that for later? Note we’re not creating a new variable but just moving its declaration here.
  59. promag commented at 11:33 pm on September 1, 2017: member
    Some nits.
  60. danra commented at 6:29 pm on September 4, 2017: contributor
  61. jtimon force-pushed on Sep 5, 2017
  62. jtimon commented at 11:47 pm on September 5, 2017: contributor
    Fixed @promag ’s nits (except one to avoid further disruption, in this case only for style). Fixed @danra ’s nit by crossing the broken list in the OP (too lazy to look after some concept and ut acks, sorry. I believe there’s enough motivation without the broken link, which I don’t remember what was about right now).
  63. in src/consensus/tx_verify.cpp:217 in cac4df7ca3 outdated
    237+    if (!inputs.HaveInputs(tx))
    238+        return state.Invalid(false, 0, "", "Inputs unavailable");
    239+
    240+    CAmount nValueIn = 0;
    241+    CAmount nFees = 0;
    242+    for (unsigned int i = 0; i < tx.vin.size(); i++) {
    


    promag commented at 1:26 am on September 6, 2017:
    ++i.
  64. in src/consensus/tx_verify.cpp:210 in a97f07af78 outdated
    210 {
    211-    // This doesn't trigger the DoS code on purpose; if it did, it would make it easier
    212-    // for an attacker to attempt to split the network.
    213-    if (!inputs.HaveInputs(tx))
    214-        return state.Invalid(false, 0, "", "Inputs unavailable");
    215+    txfee = 0; // Initialize output value
    


    promag commented at 1:30 am on September 6, 2017:
    Why? Update only if successfully?

    jtimon commented at 4:28 pm on September 6, 2017:
    And if not set to to 0? I think this was discussed already…
  65. in src/consensus/tx_verify.cpp:245 in a97f07af78 outdated
    248-    if (nTxFee < 0) {
    249-        return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative");
    250-    }
    251-    nFees += nTxFee;
    252-    if (!MoneyRange(nFees)) {
    253+    txfee = nValueIn - value_out;
    


    promag commented at 1:31 am on September 6, 2017:
    Update before return true;.
  66. in src/consensus/tx_verify.cpp:246 in a97f07af78 outdated
    249-        return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative");
    250-    }
    251-    nFees += nTxFee;
    252-    if (!MoneyRange(nFees)) {
    253+    txfee = nValueIn - value_out;
    254+    if (!MoneyRange(txfee)) {
    


    promag commented at 1:32 am on September 6, 2017:
    0if (!MoneyRange(nValueIn - value_out)) {
    

    jtimon commented at 4:31 pm on September 6, 2017:
    Mhmm, right, that’s what we’re saying in the doxygen docs now…ok, I guess.
  67. Proper indentation for CheckTxInputs and other minor fixes 3f0ee3e501
  68. jtimon force-pushed on Sep 7, 2017
  69. jtimon commented at 0:48 am on September 7, 2017: contributor
    Fixed @promag ’s last round of nits, thanks again.
  70. in src/consensus/tx_verify.cpp:217 in b989b704d4 outdated
    238+        return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
    239+                         strprintf("%s: inputs missing/spent", __func__));
    240+    }
    241+
    242+    CAmount nValueIn = 0;
    243+    for (unsigned int i = 0; i < tx.vin.size(); ++i) {
    


    danra commented at 11:15 am on September 14, 2017:
    Suggest using const auto& to iterate over tx.vin. (This is already the case in other functions in this file)

    jtimon commented at 12:33 pm on September 14, 2017:
    This line wasn’t touched besides indentation until @promag asked s/i++/++i/ Not sure it’s worth it to make that change here, to be honest…

    danra commented at 8:39 pm on September 21, 2017:
    @jtimon IMHO it would fit nicely in the minor changes commit
  71. in src/consensus/tx_verify.cpp:212 in b989b704d4 outdated
    233-            nValueIn += coin.out.nValue;
    234-            if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn))
    235-                return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
    236+    // are the actual inputs available?
    237+    if (!inputs.HaveInputs(tx)) {
    238+        return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent", false,
    


    danra commented at 11:18 am on September 14, 2017:
    The current code has an explicit comment about not triggering the DoS code on purpose, did you remove it (and invoke the DoS code) intentionally?

    jtimon commented at 12:32 pm on September 14, 2017:
    The comment was moved to the separated HaveInputs call in AcceptToMemoryPoolWorker. Perhaps lost in rebase, I’ll look at it. Perhaps it’s fine since we now have: https://github.com/bitcoin/bitcoin/pull/8498/commits/c93ceb2dbde1c2474ee04946fb4594b668613dbe#diff-24efdb00bfbe56b140fb006b562cc70bR514

    danra commented at 2:36 pm on September 14, 2017:

    It’s not just the comment, as you can see in the diff previously the code used state.Invalid (and stated it does so on purpose), and now both the comment is gone and the code uses state.DoS

    I don’t know to say on my own whether that change is valid, but it definitely requires explanation due to the fact that previously there was a specific comment suggesting using state.DoS there is bad.


    TheBlueMatt commented at 9:26 pm on September 14, 2017:
    It should be OK, the DoS from ConnectBlock is important, but the DoS shouldn’t be trigger’able in ATMP - we should have already returned false int he pfMissingInputs branch further up.

    danra commented at 8:38 pm on September 21, 2017:

    @TheBlueMatt

    It should be OK, the DoS from ConnectBlock is important

    Which DoS? The one previously returned from CheckTxInputs in case of missing inputs? If so, IIUC it wouldn’t trigger after this change, there would just be an error returned, since it replaced the previous DoS in ConnectBlock https://github.com/bitcoin/bitcoin/commit/c93ceb2dbde1c2474ee04946fb4594b668613dbe#diff-24efdb00bfbe56b140fb006b562cc70bR1638


    TheBlueMatt commented at 8:53 pm on September 21, 2017:
    DoS values persist through the state object (and should only be set once through the entire call tree). Thus, when ConnectBlock calls CheckTxInputs, which sets DoS, ConnectBlock should return only error() and not call DoS again, but the DoS points will still be returned through the state object.

    danra commented at 8:55 pm on September 21, 2017:
    @TheBlueMatt Ah, I see. Thanks!
  72. in src/consensus/tx_verify.h:11 in b989b704d4 outdated
     7@@ -8,6 +8,8 @@
     8 #include <stdint.h>
     9 #include <vector>
    10 
    11+#include "amount.h"
    


    danra commented at 11:22 am on September 14, 2017:
    Local includes should come before system includes
  73. danra changes_requested
  74. in src/consensus/tx_verify.cpp:219 in b989b704d4 outdated
    240+    }
    241+
    242+    CAmount nValueIn = 0;
    243+    for (unsigned int i = 0; i < tx.vin.size(); ++i) {
    244+        const COutPoint &prevout = tx.vin[i].prevout;
    245+        const Coin& coin = inputs.AccessCoin(prevout);
    


    TheBlueMatt commented at 9:22 pm on September 14, 2017:
    Please dont add needless auto& unless you have to. If you’re saving 5 chars of typing it just makes things less readable.

    danra commented at 9:46 pm on September 14, 2017:
    @TheBlueMatt I disagree, and AFAIK so do most of the C++ gurus. The (character) typing isn’t the issue here, rather code flexibility. See https://softwareengineering.stackexchange.com/questions/180216/does-auto-make-c-code-harder-to-understand for an example of a discussion on the topic.

    TheBlueMatt commented at 6:57 pm on September 15, 2017:
    auto, here, AFAIU, is going to be slightly more likely to force you to change the line if you change AccessCoin’s return type (at least because its a const-ref type, so conversion should only be an inheritance thing). In consensus code, making sure you’re forced to change all the places something is used if you change a type strikes me as a very, very good idea. If you want to take Herb’s stance on it, I’d also be ok with his recommended auto coin = const Coin&{inputs.AccessCoin(prevout)}; to force it, though I find that somewhat unreadable (which is bias towards what I’m used to, I admit).

    danra commented at 9:10 pm on September 15, 2017:

    Consensus code seems hard enough to change as it is without adding extra hurdles.

    In consensus code, making sure you’re forced to change all the places something is used if you change a type strikes me as a very, very good idea.

    By that logic, instead of const COutPoint &prevout = tx.vin[i].prevout;

    it would be better to write

    0const CTxIn& txin = tx.vin[i];
    1const COutPoint &prevout = txin.prevout;
    

    Since in the first version, tx.vin[i] is used without specifying its type :)


    jtimon commented at 9:17 pm on September 20, 2017:
    Let’s please leave this for another PR

    danra commented at 8:40 pm on September 21, 2017:
    OK, deleting this comment.

    TheBlueMatt commented at 8:55 pm on September 21, 2017:
    Please dont delete comments. Just because a PR author decided against taking a suggestion doesnt mean review content should be deleted. Others may wish to agree with the suggestion or otherwise just view the history of what was discussed. Unless a comment is updated immediately afterwards, generally I’d prefer they not be edited.
  75. Optimization: Minimize the number of times it is checked that no money 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)
    832e0744cb
  76. Introduce CheckInputsAndUpdateCoins static wrapper in txmempool.cpp 3e8c91629e
  77. Near-Bugfix: Reestablish consensus check removed in 8d7849b
    in 8d7849b6db5f54dc32fe4f8c6c7283068473cd21
    
    This can potentially prevent an overflow that could at least in theory
    allow the creation of money.
    4e955c58e1
  78. jtimon force-pushed on Sep 20, 2017
  79. jtimon commented at 9:28 pm on September 20, 2017: contributor
    Fixed 1 commit by @danra
  80. danra commented at 8:56 pm on September 21, 2017: contributor
    utACK
  81. danra approved
  82. TheBlueMatt commented at 11:41 pm on October 3, 2017: member
    re-utACK 4e955c58e13cfe089208f6b23b195d395ad99baa
  83. laanwj merged this on Oct 11, 2017
  84. laanwj closed this on Oct 11, 2017

  85. laanwj referenced this in commit 0e3a411351 on Oct 11, 2017
  86. laanwj removed this from the "Blockers" column in a project

  87. domob1812 referenced this in commit da78eaee6a on Oct 15, 2017
  88. fanquake moved this from the "In progress" to the "Done" column in a project

  89. codablock referenced this in commit 142ccecf6a on Sep 30, 2019
  90. codablock referenced this in commit e48a86479b on Oct 2, 2019
  91. codablock referenced this in commit 56d28c5fb3 on Oct 2, 2019
  92. UdjinM6 referenced this in commit ee0858512b on Oct 2, 2019
  93. UdjinM6 referenced this in commit f230317796 on Oct 3, 2019
  94. codablock referenced this in commit ee34d2081c on Oct 3, 2019
  95. codablock referenced this in commit 8bcba5d4e1 on Oct 3, 2019
  96. charlesrocket referenced this in commit 146cf60fb2 on Dec 19, 2019
  97. barrystyle referenced this in commit baabcd2c6e on Jan 22, 2020
  98. MarcoFalke referenced this in commit 74a1152f25 on May 4, 2020
  99. ComputerCraftr referenced this in commit 04dcc6ec3e on Jun 10, 2020
  100. ComputerCraftr referenced this in commit 514b330e83 on Jun 10, 2020
  101. Fabcien referenced this in commit 96fc9f405d on Jan 27, 2021
  102. MarcoFalke locked this on Sep 8, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-11-17 09:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me