Repository navigation
Consensus: Batched extended coinbase maturity temporary softfork /w hash based random maturity instead of deterministic height based - #409
Conversation
…ts#402 Use bitcoinknots#402's MTP binary search (lo+1) so getdeploymentinfo reports activation height when the tip MTP first crosses the start time. Keep window [start, expiry) after RDTS so in-window coinbases stay locked. Functional test uses exact init-error strings, mines the post-expiry coinbase to MiniWallet, and covers short-tranche maturity plus lock-sticks-after-expiry.
Do not default a missing creating-block hash to residue 5 (8064). txmempool check() and the fuzz harness still pass disabled bounds and never hit the Assert.
|
1cc6d53 Fix to issue that could arise after later code changes suggested by Pleb Miner on discord. |
Create run-ci.yml
|
Tested 2ece5d6 on Ubuntu 24.04, gcc, wallet on since the functional test needs it. The residue source is the part I checked hardest, because getting it wrong would be silent rather than loud. The neighboring word cannot produce residues 4 or 5 at all at this difficulty, so half the schedule would never be assigned and nobody would see an error. It is worth a comment in the code saying which end of the hash this is and why. The The commit message says "txmempool check() and the fuzz harness still pass disabled bounds and never hit the Assert". // src/test/fuzz/coins_view.cpp:259
if (Consensus::CheckTxInputs(transaction, state, coins_view_cache,
fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()),
tx_fee_out, CheckTxInputsRules::OutputSizeLimit,
fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()),
fuzzed_data_provider.ConsumeIntegralInRange<int>(0, std::numeric_limits<int>::max()))) {
I did not run the fuzzer for this; I put the same call shape in a unit test, which is enough to show what happens: The test file is in the gist. As it stands the harness will abort instead of fuzzing, so The narrow fix is to pass a tip in the harness. The one I would rather see is dropping the default argument, so that Two questions rather than claims: Does anything guarantee that Second, the same lookup returns whatever block is at that height on the active chain, which after a reorg is not the block that created the coin. For a coin that still exists it is the same block, so I think this only ever produces a wrong maturity for a wallet entry that is about to be reorged away. Is that how you read it too? @Kilombino's point on #404 about nit: The calendar-basis finding in my #404 comment applies to this branch unchanged: 2016/4032/8064 are 3.9/7.9/15.8 days at the spacing the chain has actually run, not 14/28/56. So does the incidence question I raised there about which pools' coins these locks land on. Repro and scripts: https://gist.github.com/jasonsopko/75e2f3e69cefcfa19911378aa4c5a54d |
|
Fix needed for hash generation. Converting to draft proposal until we can validate functionality. |
|
I think I misread jasonsopko. I think he said the code works correctly already. Converting back to review ready proposal. |
|
The distribution on this branch is already uniform. The second column of my hash-residue table was a counterfactual rather than a measurement of your code, and I labeled it badly enough to be read the other way. That one is mine.
Residue 3 at 15.7 % is 1.2 standard deviations below the expected 333.3, and the row as a whole fits uniform at p = 0.55. There is nothing in it to correct. The 0.0 % on residues 4 and 5 belongs to So no PR from me here, because the only change it could make is the one that breaks it: moving the residue to the top word puts half the schedule out of reach and reports no error, which is why I checked the source in the first place. On converting to draft, that is not needed for this. Draft reads as "do not review yet", and an ordinary revision is better served by pushing and saying in a comment what changed. Nothing on this branch is waiting on validation. I have relabeled the columns in the gist so the counterfactual cannot be read as a measurement, and added |
GetUint64(0) is the displayed-hash tail; the high word is unusable at this difficulty. CheckTxInputs no longer defaults hash_tip, so coins_view and CTxMemPool::check() pass nullptr next to disabled bounds. Wallet coinbaseMaturity returns 100 if ActiveChain()[h] is missing (disconnect race) instead of Asserting.
|
@jasonsopko I think my last commit addressed concerns from your first comment, and here are the answers to the questions. Let me know if there is anything I missed. First question: Nothing guarantees the height is still on ActiveChain. A shortening reorg can make ActiveChain()[h] null while the wallet still has that TxStateConfirmed. Assert would abort RPC. The commit returns 100 instead. Display glitch on a coin that is about to be disconnected. Second question: Yes, that is how I read it. Same-length reorg: ActiveChain()[h] exists but is the new block, not the one that created the wallet's coin. Wrong tranche on a row that is about to be marked conflicted. Consensus does not use this function; ConnectBlock looks up the hash on the chain that contains the coin. |
|
Re-tested on ba78673, same setup as before (Ubuntu 24.04, gcc, wallet on). The wallet path, the include cleanup, and the low-word comment all do what your reply says, and dropping the default argument on The fuzz harness Assert is still there. The commit message says coins_view passes Same unit-test repro as before, updated for the new signature: Last time I said I had not run the harness itself. This time I built it ( The third is a 146-byte input built by hand ( The green fuzz jobs on your fork are not evidence either way: The one-line fix is Repro test, both inputs, and the logs are in the gist: https://gist.github.com/jasonsopko/75e2f3e69cefcfa19911378aa4c5a54d |
Pass INT_MAX bounds with nullptr, same as CTxMemPool::check(), so the harness cannot reach Assert(hash_tip).
|
Ok should be fixed @jasonsopko . I figured out how to get clang18 onto my bookworm (some reason its not in repo) to reproduce your build. Got the build working but the python seems to be looking for files in a .reorg-watch folder in my user directory now. |
|
Verified at e639c02. The one-line change in
That closes the last code-level item from my two comments. The calendar-basis point and the incidence question from #404 still stand, and those are about the schedule rather than the code. On the
|
|
Reviewing There are some details but what I would say the main flaw is that a hasher can submit only blocks which hash leads to a lower maturity. Also this constraint on miners revenue, which could lead small miners to join pools with the most steady payouts, they will end up joining the pools who trick the hash based maturity, ending up exactly in the situation we are trying to avoid.
|
|
@f4u57ox Yes they will join pools. This PR will almost guarantee that they will join pools. Datum will do the work of evening out the vesting for the miner so that they get consistent pay according to vesting schedule. The growth in hashrate is already forcing them into using datum anyway, and this PR will accelerate that phenomenon somewhat more, but the datum is maturing and despite knowing this before i started working on 404 that it would have this effect, I still determined that it was an acceptable outcome. Every design has tradeoffs, and that is probably the biggest tradeoff of this design in comparison to the other proposals. If we did not have datum or another similar technology, I would not have made this proposal in this manner, I would have made it as multiple coinbase outputs for each recipient. In the presence of datum and pools, the multiple outputs thing would make the coinbase transactions enormous. Consequences that you are noting were intentional and selected instead of selecting the consequences of doing it the other way.
|
|
I agree this is a more dynamic maturation selection, I don't know if it's complexity is needed. Just some personal notes: I don't see why this is less likely to stall the network than the flat 45 days (or whatever # of blocks we agree). I might have got something wrong, but when I say pools I'm including sv1 ones, the growth in hashrate hasn't forced them into using Datum otherwise we wouldn't have this alphapool situation. 5/6 it's the maximum they could waste in theory, never underestimate short term profit seekers. Blocks competing at the last tip will now get preference towards the low maturity one. Any pool will even out the payment and vesting for miners, not only DATUM. And you could even argue you will get more evened out vesting payments using the largest pool, which as today is Alpha (and his future variants). |
Same as pr #404 except the maturation length is based upon the block hash.
Maturity is attached to the block hash, not the spend. Coins created inside the window keep their assigned lock after RDTS expiry. New coinbases after expiry go back to 100. This is Kyle's note on #402: otherwise an opportunistic miner can work the tail of the window and pay almost nothing.
Depth is batched by (block hash) % 6 so a six-week cliff does not mature on one day:
1/6 of window blocks: 2016 confirmations (~14 days at 10 min)
2/6 of window blocks: 4032 confirmations (~28 days)
1/2 of window blocks: 8064 confirmations (~56 days)
Assignment is by block height. Coinbase transaction size does not change (no extra outputs, DATUM-safe).
#404 is the height based variant of this.
#403 is the MTP-duration variant of #402; this branch stays on block-count maturity like #402 and only changes the schedule and the expiry rule.
Regtest: -extendedcoinbasematurity= requires -rdtsexpiry and the start time must be less than the expiry time.