bitcoin-inquisition #16: Activation logic for testing consensus changes (consensus)

Host: ajtowns  -  PR author: ajtowns

The PR branch HEAD was 3e8074faa3 at the time of this review club meeting.


  • Bitcoin Inquisition is a fork of the Bitcoin Core codebase intended for testing consensus and relay policy changes. (Related mailing list posts: [0] [1] [2]). Bitcoin Inquisition nodes run on a signet test network (signet has been discussed in a previous review club meeting).

  • Because the idea is to test consensus changes and we can expect them to potentially be buggy, we want the option to undo a consensus change when we find out it’s buggy so that we can fix the bug. Adding this ability is a major departure from how consensus changes are handled on mainnet, where network coordination is required.

    • This bitcoin-dev post by David Harding discusses automatically reverting soft forks on mainnet.
  • This PR does a few things:

    • It buries the Taproot deployment, replacing the activation logic with hard-coded heights for its deployment status. We have discussed deploymentstatus and burying deployments in previous review club meetings.

    • It replaces BIP 9 versionbits with Heretical Deployments, designed to better suit the goal of testing consensus rules.

    • It updates the getdeploymentinfo RPC to return activation and abandonment signals observed in blocks.

    • It adds a -renounce config option to manually disable a Heretical Deployment.

  • A comment in the PR includes some notes about how the code is structured. The previous version of the PR (bitcoin-inquisition/bitcoin#2), against Core/Inquisition version 23.0 is also available.


  1. Did you review the PR? Concept ACK, approach ACK, tested ACK, or NACK?

  2. Why do we want to deploy consensus changes that aren’t merged into Bitcoin Core? What problems (if any) are there with merging the code into Bitcoin Core, and then testing it on signet afterwards?

  3. When have ANYPREVOUT and CHECKTEMPLATEVERIFY been activated on signet according to this logic? If we found a bug and needed to make substantial changes, how would we do that? Would that result in a signet hard fork?

  4. What is the point of the DEACTIVATING state?

  5. Why is min_activation_height removed?

  6. Were you able to compile and run the code?

  7. Were you able to test the code? What tests did you run?

  8. Why is Taproot buried?

  9. What is the purpose of AbstractThresholdConditionChecker and ThresholdConditionCache in versionbits.h?

  10. Could/should the large commit be split up further? If so, how? If not, why not?

  11. Do any of the changes here make sense to include in Bitcoin Core?

Meeting Log

  117:00 <_aj_> #startmeeting
  217:00 <glozow> hi
  317:00 <_aj_> aww, no bot
  417:00 <pablomartin_> hello
  517:00 <_aj_> hi all!
  617:00 <svav> Hi
  717:00 <codo> hi
  817:00 <theStack> hi
  917:00 <roze_paul> hi
 1017:00 <neha> hi
 1117:00 <kevkevin> hi
 1217:00 <michaelfolkson> hi
 1317:00 <_aj_> feel free to say hi everybody, just like classic dr nick. anybody's first time?
 1417:01 <lightlike> hi
 1517:01 <_aj_> today we're in a fork repo, -- bitcoin inquisition
 1617:01 <LarryRuane> hi
 1717:02 <_aj_> did anyone get a chance to look at the pr/repo/etc? y/n
 1817:02 <glozow> y
 1917:02 <codo> n
 2017:02 <lightlike> y (0.5)
 2117:02 <kevkevin> y (0.3)
 2217:02 <neha> n
 2317:02 <theStack> n
 2417:02 <svav> The notes yes
 2517:02 <roze_paul> y
 2617:02 <michaelfolkson> Also 0.5y
 2717:02 <pablomartin_> y
 2817:02 <LarryRuane> 0.2y
 2917:03 <dzxzg> n
 3017:03 <hernanmarino> Hi ! Only the notes and related links, i find it super interesting
 3117:04 <_aj_> so, i guess "ask questions any time" is probably a given, but in case it's not - ask questions any time! going through the questions from the notes...
 3217:04 <_aj_> Did you review the PR? Concept ACK, approach ACK, tested ACK, or NACK?
 3317:05 <LarryRuane> concept ack, running the branch now, haven't really tested anything (not super clear on how to do that)
 3417:05 <michaelfolkson> Concept ACK, unsure on Approach ACK
 3517:06 <roze_paul> C-ack -> I find michaelfolkson's point [iiuc] on custom signets per softfork interesting. Played with the fork, but not the specific pr
 3617:06 <_aj_> well, the next question is concept-y, the one after is test-y
 3717:06 <_aj_> Why do we want to deploy consensus changes that aren’t merged into Bitcoin Core? What problems (if any) are there with merging the code into Bitcoin Core, and then testing it on signet afterwards?
 3817:07 <roze_paul> finding bugs in the consensus code is immeasurably better to do on signet than mainnet?
 3917:07 <roze_paul> and we want to test and build on top of them as well
 4017:07 <glozow> I imagine if we find a bug, fix it in Core, then later activate the soft fork, there could be a few unupgraded nodes enforcing a different set of rules
 4117:08 <LarryRuane> merging even unactivated consensus changes can break existing functionality as a side-effect
 4217:09 <_aj_> roze_paul: yep -- finding consensus bugs in mainnet is pretty painful, and can shut down your lightning nodes while you mess around with upgrading, eg
 4317:10 <_aj_> i guess another question is why do it on signet, rather than just on regtest?
 4417:10 <LarryRuane> glozow: +1 good point ... do we have to assume all nodes (or nearly all) are running actual releases? many of us run master branch, but not for long usually
 4517:11 <LarryRuane> maybe it isn't possible (or easy) to test LN on regtest?
 4617:11 <glozow> LarryRuane: well, if we add something to Core it would eventually go into a release
 4717:12 <lightlike> Also it's extremely hard to get consensus changes merged into core without overwhelming consensus, the threshold here is much lower
 4817:12 <_aj_> you can point multiple nodes at a signel regtest -- we do that ourselves in the functional tests; so i think LN testing is okay
 4917:12 <hernanmarino> _aj_ : is it because signet is a more "open" network ?
 5017:13 <michaelfolkson> glozow: Unless it was reversed (not that I'm recommending adding consensus changes to Core only to reverse them prior to a release)
 5117:13 <neha> regtest is pretty uniform -- on signet you might have different versions of code, different hardware, etc
 5217:14 <_aj_> hernanmarino: so there's two reasons i think matter (not everybody agrees!) -- one is that if you throw test vectors onto signet, it's much easier to actually validate them. we have lots of test vectors for taproot into core's internal tests, but actually making them available to other people to test their software isn't that easy; arguably that's part of why btcd had bugs recently
 5317:14 <LarryRuane> "why do it on signet, rather than just on regtest?" -- don't all softforks activate at block 1 on regtest, so we couldn't test that softfork upgrades go smoothly?
 5417:14 <_aj_> hernanmarino: another is that maybe it's interesting to do integration tests with different software, rather than running the entire environment yourself (since you can't make regtest available publicly without getting random reorgs)
 5517:14 <michaelfolkson> You don't ever see the activity on someone's regtest if we are interested in how a potential consensus change is being used to build things
 5617:14 <glozow> signet is more suitable for integration testing - you can have lots of companies, applications, different implementations/versions of LN nodes, etc. doing stuff on there at the same time
 5717:15 <hernanmarino> _aj_ : I agree on both, my original comment was referring to your second reason
 5817:17 <_aj_> LarryRuane: you can use -vbparams to change when forks activate on regtest, if you want to test how upgrades go. but maybe that doesn't really test "smoothness" since it's all a very labratory environemnt
 5917:17 <_aj_> okay, before we go on, does anyone have any questions about how the heretical deployment idea works that they'd like to ask now?
 6017:18 <michaelfolkson> Why bother with signaling if every mined block needs to get signed by the block signer?
 6117:18 <_aj_> that's a good question!
 6217:19 <neha> i imagine because signaling is a very important thing to test...
 6317:19 <michaelfolkson> It is kinda testing signaling but in a completely different environment to what it would be on mainnet. No block signers on mainnet for one
 6417:19 <_aj_> the point of signalling is to be able to deal with custom signets -- if i'm pointing my inquistion node at one signet, how do i know when to enforce APO on it? you can't hardcode a time or height, because the signer might not have upgraded to enforce the rules at any particular time or height
 6517:20 <_aj_> neha: the signalling for heretical deployments is mostly different code to that used for mainnet, so it's not a super useful test in that sense :(
 6617:20 <LarryRuane> curious why `timeout` is a timestamp instead of block height? ... oh i think your last comment answers that question
 6717:20 <lightlike> since the deployment mechanism is differerent (Heretical Deployment), I don't see much point in testing this.
 6817:21 <neha> _aj_: then i don't understand why you couldn't just go with "whenever the block signer says to enforce APO"
 6917:21 <_aj_> right -- so if you hardcoded signet's blockheight of 129000 to activate, then a custom signet would have to waste time mining 120k blocks just to catch up
 7017:21 <_aj_> neha: that's what's being signalled!
 7117:21 <neha> ah, ok
 7217:21 <glozow> so the reason is we have a method of communicating when to activate despite not everyone running the exact same software
 7317:22 <_aj_> neha: you just mine a single block with a particular version to signal activation or deactivation
 7417:22 <_aj_> which is a perfect lead in to...
 7517:22 <michaelfolkson> A custom signet is a totally different chain? What is its relevance to the default signet?
 7617:22 <_aj_> When have ANYPREVOUT and CHECKTEMPLATEVERIFY been activated on signet according to this logic? If we found a bug and needed to make substantial changes, how would we do that? Would that result in a signet hard fork?
 7717:22 <glozow> My node says CTV activated at height 106704
 7817:23 <_aj_> michaelfolkson: every signet shares the same genesis block, but every block after that is distinct due to the signet signature committing to the signet signing key
 7917:23 <glozow> no APO yet, I assume that'll be after PR #18?
 8017:23 <michaelfolkson> If I set up a custom signet with me as a block signer I control the block heights, times of when things are activated on my custom signet. But I don't care when things are activated on the default signet?
 8117:23 <_aj_> glozow: yes; or in the 23.0 branch
 8217:23 <lightlike> i found this quite confusing: it seems that in the PR branch neither have activated, in the 23 branch both have activated and in the 24.0 branch only CTV but not APO has activated. Is there a logic to this?
 8317:24 <glozow> My answer is from running my node on signet and calling getdeploymentinfo
 8417:24 <_aj_> lightlike: the 24.0 branch has [this PR] [CTV] merged, but [APO] unmerged, so the 24.0 branch is unable to tell you anything about APO
 8517:24 <glozow> ahhhh
 8617:25 <lightlike> _aj_: but why is [APO] only merged in 23 but not in 24?
 8717:25 <_aj_> -- is the commit that sets APO up as an heretical deployment
 8817:26 <_aj_> lightlike: 24.0 is branched directly from core so doesn't include anything that inquisition merged for 23.0 until a PR gets merged. i'm trying to give a little time for people to review PR's before merging them
 8917:28 <roze_paul> @glozow, to be sure, your APO is also activated at 106704? My 23-node has both apo & ctv activated at 106704
 9017:28 <_aj_> so if you run `bitcoin-cli -signet getdeploymentinfo $(bitcoin-cli -signet getblockhash 106271)` you'll see CTV was signalled for activation at block height 105942
 9117:29 <_aj_> -- which has the magic 0x60007700 version; 0x77 being 119, CTV's bip number
 9217:29 <_aj_> What is the point of the DEACTIVATING state?
 9317:30 <michaelfolkson> Phasing out a soft fork proposal (after a bug or just not being used)
 9417:30 <_aj_> why phase it out though? if there's a bug, why not just stop immediately?
 9517:31 <glozow> Is the question why we don't go directly from ACTIVE to ABANDONED, and have 432 blocks of DEACTIVATING isntead?
 9617:31 <_aj_> yep, that was the intent of the question
 9717:31 <roze_paul> +1.intermediate annulation of a softfork...waits until next period to be abandoned [inactive]
 9817:31 <michaelfolkson> I still don't understand the custom signet point. They share a genesis block. So what? :)
 9917:31 <neha> is it because of the interaction with timeout?
10017:31 <glozow> I assumed it would have something to do with reorgs but I'm not sure :(
10117:32 <michaelfolkson> But it seems like because of the custom signet point you want to coordinate phasing in and out of soft fork proposals
10217:32 <d33r_gee> noob question: how do you compile a version of bitcoind (bitcoin-Inquisition) that's different from the regular main repo? More specifically can both instance run on the same machine?
10317:32 <michaelfolkson> Rather than just having AJ announcing block heights, times of activations or deactivations
10417:32 <_aj_> michaelfolkson: (there's no "so what" -- they share a genesis because that made it easier for wallets that wanted to hardcode the genesis and would have found it hard to deal with a different genesis for each custom signet)
10517:33 <michaelfolkson> _aj_: Ok but after the genesis block they can be totally different chains? No?
10617:33 <michaelfolkson> Totally independent other than the genesis block?
10717:33 <_aj_> so it's an easier answer than that -- it's just to give people a chance to withdraw funds they might have locked into the soft fork. once the fork is deactivated or replaced, they might not be able to spend the funds at all (even if it's anyonecanspend that doesn't work if your tx gets rejected for not being standard)
10817:33 <LarryRuane> d33r_gee: "can both instance run on the same machine?" -- yes
10917:33 <_aj_> michaelfolkson: (they will always be totally different chains)
11017:34 <roze_paul> @d33r_gee I've almost forgotten, but dm me comes down to following the build directions and ensuring your data-dir isnt the same, IIRC
11117:35 <LarryRuane> _aj_: that's interesting! to make sure I get it, funds on signet are somewhat precious (even tho of course no monetary value)?
11217:35 <glozow> oh, duh
11317:35 <roze_paul> (there are build directions on the bitcoin github page per mac/linux/win)
11417:35 <_aj_> LarryRuane: well, not so much precious, as we'd like to not have useless entries sitting in the utxo set forever
11517:35 <LarryRuane> oh right, +1
11617:35 <d33r_gee> LarryRuane ah thanks!
11717:35 <d33r_gee> roze_paul will do! Thank you!
11817:35 <glozow> I had a question about abandoning, i.e. how it doesn't cause a hard fork. Is it because we are assuming everybody who followed the activation also followed the deactivation signaling? So there's nobody out there who activated the soft fork but won't also deactivate it?
11917:36 <glozow> Well I guess it's signet so it's the same miner anyway
12017:36 <_aj_> glozow: exactly -- the soft fork includes both the activation and deactivation as a bundle.
12117:36 <glozow> gotcha
12217:36 <michaelfolkson> glozow: It is a hard fork for those running an old version of bitcoin-inquisition not knowing about the attempt to phase it out
12317:37 <instagibbs> it would be an end of "censorship" for those who don't know about the activation/deactivation
12417:37 <glozow> there isn't a bitcoin-inquisition version that doesn't have both activation and deactivation logic tho
12517:37 <_aj_> michaelfolkson: it's only a hardfork for people who've modified their inquisition software to not know about the deactivation signalling
12617:38 <_aj_> Why is min_activation_height removed?
12717:38 <michaelfolkson> _aj_: The deactivation signaling is included in the bitcoin-inquisition release with the activation signaling?
12817:38 <LarryRuane> I remember luke-dashjr made this point about reducing the max block size -- it should be auto-expiring (deactivating) right from the start, so that the block size limit can be increased later without a hardfork, I though that was cool
12917:38 <lightlike> because we don't need a configurable period between lock-in and activation in the new state model anymore - with heretical deployments, it activates automatically in the next period
13017:38 <michaelfolkson> I thought for some soft fork proposals you wouldn't ever want to deactivate it
13117:38 <_aj_> LarryRuane: yes; can you find where he wrote that? i looked the other day and couldn't remember
13217:39 <glozow> michaelfolkson: observe that they are implemented in 1 commit
13317:39 <_aj_> michaelfolkson: for mainnet activations you probably don't (or we haven't in the past anyway), but for signet-only activations, probably we always do
13417:40 <_aj_> michaelfolkson: the signet miner can always choose not to signal for deactivation, of course
13517:40 <LarryRuane> _aj_: not sure if I saw it written down, but it's in this presentation (which is really excellent in general, by the way)
13617:40 <_aj_> LarryRuane: oh! that would explain why i couldn't find it
13717:41 <neha>
13817:41 <_aj_> >> Why is min_activation_height removed? << -- anyone know the answer?
13917:41 <glozow> I think lightlike said answered, there's no need to wait between lock in and activation?
14017:42 <_aj_> oh, i'm blind, great!
14117:42 <lightlike> that was my guess
14217:42 <glozow> Also, just to clarify, even if no abandonment is signaled, the soft fork still eventually deactivates at the timeout right?
14317:42 <michaelfolkson> Definitely no deactivations for mainnet activations. Unless complete disastrous emergency. That would not be fun
14417:42 <_aj_> also, because of the same problem above -- heights on signet in general don't work if you care about custom signets
14517:43 <_aj_> glozow: yes, but i think the timeouts i put in for APO and CTV are in 2031, so...
14617:43 <glozow> oh, haha
14717:44 <_aj_> Why is Taproot buried?
14817:44 <LarryRuane> because it was activated "long enough" ago?
14917:45 <_aj_> that's a good reason, but not the reason!
15017:45 <glozow> I think it's effectively buried already, but rpc/blockchain.cpp needs code that's going to be deleted to add Heretical Deployments?
15117:45 <lightlike> because it' incompatible with the new heretical deployment scheme?
15217:46 <_aj_> if you didn't bury it, you'd have to make it an heretical deployment; and that would (at least at one point) then mean that it would timeout eventually, but we don't want taproot to timeout
15317:47 <michaelfolkson> You might want to sync up bitcoin-inquisition with the consensus rules of Core (and deactivate before 2031). Say if a opcode was given a different OP_NOP on bitcoin-inquisition to the one it ended up with in an actual soft fork activation in Core
15417:47 <LarryRuane> can't you make timeout maxint? (0x7fff...)?
15517:47 <_aj_> i think in the current code you could just make it be SetupDeployment({.always = true}) or so though...
15617:47 <michaelfolkson> I guess we're not thinking particularly long term with default signet, bitcoin-inquisition. Happy to do resets
15717:47 <_aj_> LarryRuane: yeah, exactly
15817:48 <_aj_> michaelfolkson: presumably you'd want to test the OP_NOP/OP_SUCCESS in signet before activating it in core, so you'd deactivate the conflicting thing before that even
15917:48 <_aj_> What is the purpose of AbstractThresholdConditionChecker and ThresholdConditionCache in versionbits.h?
16017:50 <glozow> Abstract class for telling us the deployment status of a soft fork is, which can either be implemented through a version bits checker applying BIP9 / Heretical Deployment logic to blocks, a cache that just looks up the values, or something else.
16117:50 <roze_paul> so the burying commit is by changing the timeout to maxint, or the bury is done in another way?
16217:51 <_aj_> roze_paul: the burying is done by changing the activation method from BIP9 to just "it's active as of this height". for taproot and signet, the height has always been 0, so this is easy, even despite the custom signet problem we might have elsewhere. (taproot got merged into core just before signet did)
16317:52 <_aj_> glozow: yep, pretty much; though i personally think the "abstract" is false advertising
16417:52 <_aj_> Could/should the large commit be split up further? If so, how? If not, why not?
16517:52 <theStack> is there any reason why taproot hasn't been buried yet in core?
16617:52 <glozow> if anybody's interested, we've done a review club on burying deployments and deploymentstatus in the past
16717:53 <_aj_> theStack: see #23505 and other PRs
16817:53 <_aj_> theStack: there's reasons, but no particularly profound ones?
16917:54 <_aj_> (it did get split up further after those notes got written and gleb made some suggestions! maybe it could be more split up for next time?)
17017:54 <michaelfolkson> It was buried, no? In #23536
17117:54 <theStack> _aj_: oh interesting, apparently i even reviewed that one and can't remember :X
17217:55 <theStack> the latest try seems to be
17317:55 <lightlike> There's also #26201 (open)
17417:55 <michaelfolkson> Oh ok
17517:55 <_aj_> Do any of the changes here make sense to include in Bitcoin Core?
17617:56 <glozow> probably not?
17717:57 <glozow> -renounce seems like it would be a footgun
17817:57 <_aj_> Final questions that I skipped over are: "Were you able to compile and run the code?" "Were you able to test the code? What tests did you run?" -- happy to hang around if people want to discuss that beyond a y/n
17917:57 <_aj_> glozow: i think some of the little bits of versionbits can be included -- removing the `params` arguments for AbstractThrCC
18017:58 <michaelfolkson> I'm a bit scared running Bitcoin Core signet and bitcoin-inquisition on the same machine. Experienced any problems _aj_ switching between them on the same machine?
18117:58 <roze_paul> I ran the code, not this pr specifically, just the main branch. Didn't run any tests iirc
18217:58 <_aj_> michaelfolkson: i run them both with separate datadirs?
18317:59 <roze_paul> +1 _aj_
18417:59 <_aj_> glozow: has two commits i've been thinking about
18518:00 <_aj_> michaelfolkson: if you want to meaningfully switch between them, running -rescan or -reindex is probably worthwhile, i guess?
18618:00 <_aj_> okay, that's time!
18718:00 <_aj_> #endmeeting>>)