blockchain: Add basic historical agenda support. - #3791
Open
davecgh wants to merge 13 commits into
Open
Conversation
Determining agendas requires taking the chain lock for write since it can mutate the threshold state cache. Strictly speaking, there is not actually a race with the current code despite not taking the expected lock and locking mode in the updated cases due to the interaction of other locks and semantics. However, it is both safer and more accurate to take the expected lock as required versus relying on what is essentially invisible behavior of other locking preventing a race. While here, update various function comments to call out the required locking behavior.
Currently, deployments are overloaded with different concerns that are actually conceptually distinct as they relate to consensus changes. This overloading obscures the different concepts and, more importantly, makes it difficult to cleanly handle changes that only affect one of them. Concretely, the first distinct concept is the specific mechanism used to decide on whether or not the consensus change should be applied. It involves tallying votes and making a decision based on those votes. The second distinct concept is the existence of a consensus rule that can change depending on its status at a given point in the chain. With the goal of cleanly separating the distinct concerns, this is the first in a series of commits that will eventually make agendas a separate entity that reference deployments instead of using a single entity for both. This commit moves all methods related to querying the state of an agenda to a separate file along with supporting code. It also moves various code related to deployments to the new file and the associated deployment validation test to match and updates a couple of comments while here. It is done first to avoid cluttering diffs.
This consolidates the logic that determines if an agenda with a single winning choice is active. That applies to all current agendas and will likely apply to the majority of future agendas too. A separate function can be added in the future if any agendas with more than one possible winning choice are introduced. The primary motivation is to help pave the way for splitting agendas and deployments into separate entities, but it is also useful on its own because a single source for the primary determination logic is more convenient, less error prone, and less overall code. This is part of a series of commits to make agendas a separate entity that references deployments instead of using a single entity for both.
This modifies the code that chooses the stake difficulty algorithm based on the state of the agenda to be consistent with the way almost all of the other agendas are handled and to make use of the new consolidated agenda status determination approach. Since the agenda state query now returns an error, the methods that use it are updated to propagate the error up the call chain. This is part of a series of commits to make agendas a separate entity that references deployments instead of using a single entity for both.
This modifies the code that chooses the maximum block size based on the state of the agenda to be more consistent with the way the other agendas are handled and to make use of the new consolidated agenda status determination approach. Since the agenda state query now returns an error, the methods that use it are updated to propagate the error up the call chain. It also corrects the comment on maxBlockSize to accurately note that it requires the chain lock held for write as opposed to reads. The result for this particular agenda is used differently than the others, so the status determination retains the slight semantic difference in order to keep the existing semantics. A more generalized approach for all agendas is needed in the future to remove the final remaining inconsistency. This is part of a series of commits to make agendas a separate entity that references deployments instead of using a single entity for both.
This adds tests for the updated max block size selection logic.
This updates the threshold state tuple that identifies a winning choice to use an ID instead of a pointer to the winning choice within the deployment and updates all consumers and tests accordingly. This is part of a series of commits to make agendas a separate entity that references deployments instead of using a single entity for both.
davecgh
force-pushed
the
blockchain_historical_agendas
branch
from
September 9, 2026 02:09
c7d154b to
74a376b
Compare
This is the final commit in the series to make agendas a separate entity that references deployments instead of using a single entity for both. First, it introduces a new struct to house agenda information which consists of an optional forced state and an optional associated deployment and removes the forced state from the deployment info. The fact that the deployment is now optional is one of the most important conceptual changes. Next, it replaces the deployments map with an agendas map that is constructed by creating new agendas for each deployment defined in the provided chain parameters and renames various instances of deployment IDs to indicate they are now agenda IDs. While the IDs are currently the same, and likely will be for the foreseeable future, they are conceptually different, so the rename aims to make that fact more obvious. Finally, since the associated deployment information for an agenda is no longer required in all cases, the functions related to determining when the state last changed add an additional check to ensure the agenda has the necessary deployment data. These functions, in particular, highlight part of the conceptual difference. Namely, they are related to querying details about the deployment process as opposed to the status of the agenda itself.
The current code requires all behavior that is based on the result of a consensus change vote to include deployment and voting information in the chain parameters for all networks because the available agendas are dynamically built from them. There is nothing functionally wrong with that, but it does have some limitations. One notable limitation is that the deployments can never be removed even when their historical activation points are already known because the code requires their presence to determine the status. Another notable limitation is related to non-main networks, such as newer versions of testnet and the simulation network. They both need to grandfather in previous agendas so that all of the latest rules are applied by default. That currently requires all of those older deployments to be manually specified in multiple chain params and given a forced choice to make them active. This provides an incremental improvement to the handling by adding a map of all required IDs for agendas that influence consensus behavior and modifies the agenda initialization logic to create a default agenda entry for all required agendas that do not already have an associated deployment in the network chain parameters. The default agendas will always be inactive for the main network and active for all other networks. Finally, it removes a couple of special cases that implemented the same behavior in an ad-hoc fashion since it is now the default for all otherwise unspecified required agendas.
This adds a test to ensure the required default agendas are created with the expected states when no deployments are specified for them in the chain parameters.
While the existing agenda state determination once an agenda becomes active is reasonably efficient, it still requires adding entries to the threshold state cache at every rule change interval in order to propagate the terminal state forward. Anchor points for active agendas allow a more efficient approach for querying since they can be implemented with a single pointer that only has to be set once. Aside from allowing for more efficient handling in the general case, anchor points also have the important property that they do not directly depend on rule change intervals. This property means they can be set independently of vote counting when the information can be determined via other means. For example, when historical facts about activation points are known. While this commit does not yet take advantage of the property, it is worth mentioning because it is part of the motivation for implementing them. With that in mind, this modifies the tracked information about agendas to support a cached anchor point that corresponds to the parent of the block at which the agenda activated. The active anchor is discovered opportunistically when tallying votes in a full-context path. Finally, the consolidated path for querying an agenda state is updated to use the anchor when it is set to immediately return the active state for all descendants of the anchor. The state query falls back to the normal mechanism based on the threshold state cache when the anchor is not set or usable.
This makes use of the new active agenda anchors to add basic support for hard-coded known historical activation points that are now facts of the chain and adds the details for all historical agendas on the main and version 3 test networks. It introduces a new positional agenda state query that attempts to determine the status of an agenda for a given block using only information available that depends on its position within the block chain and the headers of all ancestors. The new positional query uses the historical data, when present, to definitively determine whether or not an agenda is active without counting votes. Concretely, the new positional query is able to provide a definitive result in the following circumstances: - The agenda is forced active - The parent of the activation block is a historical fact - The activation has been opportunistically discovered while tallying votes in a full-context path Ideally, a historical agenda should be able to stand in for a deployment entirely in addition to working alongside one when present. However, the ability to query state changes and vote information via various methods currently depends on agendas having an associated deployment. So, this retains the requirement for agendas to have associated deployment information unless they also have a forced state. Nevertheless, it is still a useful incremental improvement that paves the way for more efficient and stronger validation of approved historical agendas.
This adds extensive tests for the new positional agenda state determination. It includes testing the state for the genesis block, forced states, and historical states. Historical states are tested before, exactly at, and after the anchor along with side chains that do and do not descend from the anchor. It also doubles as more thorough testing for the new active agenda anchors. The existing agenda tests do a good job exercising them for the normal paths while these tests exercise the edge cases.
davecgh
force-pushed
the
blockchain_historical_agendas
branch
from
September 9, 2026 03:13
74a376b to
319f034
Compare
davecgh
commented
Sep 9, 2026
| // - the scenario is exceedingly rare | ||
| // - it would add significant cost and complexity to allow the | ||
| // anchor to move around because this code path will only ever run | ||
| // once per discovered activation due to the threshold state |
Member
Author
There was a problem hiding this comment.
Suggested change
| // once per discovered activation due to the threshold state | |
| // once per discovered activation due to the threshold state cache. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This consists of a series of commits that culminate in adding basic support for hard-coded known historical activation points that are now facts of the chain and adds the details for all historical agendas on the main and version 3 test networks.
It introduces a new positional agenda state query that attempts to determine the status of an agenda for a given block using only information available that depends on its position within the block chain and the headers of all ancestors.
The new positional query uses the historical data, when present, to definitively determine whether or not an agenda is active without counting votes.
Concretely, the new positional query is able to provide a definitive result in the following circumstances:
Ideally, a historical agenda should be able to stand in for a deployment entirely in addition to working alongside one when present. However, the ability to query state changes and vote information via various methods currently depends on agendas having an associated deployment. So, this retains the requirement for agendas to have associated deployment information unless they also have a forced state.
Nevertheless, it is still a useful incremental improvement that paves the way for more efficient and stronger validation of approved historical agendas.
There is a fair amount of preparatory work in the earlier commits such that each commit is a self-contained and logical change that fully builds and passes all tests. An overview of the progression is:
chaincfg.ChoiceSee each commit message for full details.