Skip to content

Conversation

achow101
Copy link
Member

@achow101 achow101 commented Mar 9, 2021

Currently versionbits deployments are stored in a simple C array in Params. Setting the actual values needs to be done externally. Since the memory is allocated and initialized when Params is initialized, it is possible to have a deployment with uninitialized (or otherwise garbage and invalid) values set for its parameters if something is forgotten when they are being set.

Instead of this two step approach (create deployment object, then set its members), I think it is better to have a constructor where those parameters are passed in and set when the deployment is initialized. This PR does that. In order for this to work though, vDeployments cannot be a simple C array. It is instead changed to be a std::map<DeploymentPos, VBitsDeployment>. This maps the deployment enum to the VBitsDeployment object itself; this is essentially how we were using vDeployments previously. Additionally, by also changing VersionBitsDeploymentInfo to a map as well, we are able to remove MAX_VERSION_BITS_DEPLOYMENT and all of the places where we were iterating the deployments no longer need to cast an int to DeploymentPos.

An additional concern is that the members of VBitsDeployment are not const and could thus be accidentally changed during runtime. To prevent this, this PR makes all members of VBitsDeployment const.

Lastly, to make VBitsDeployment actually fully describe a deployment, this PR moves the number of blocks in a period into the struct. In order to ensure that this variable matches up with the retarget period, a unit test is added.

Built on top of #21392 and #21380 for the refactors and other changes they make to VBitsDeployment.

Copy link
Contributor

@ajtowns ajtowns left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

globalChainParams / Params() is already const during runtime, so that should already prevent changing any of the fields in vDeployments. Ah, a different approach that might be worth considering:

class CChainParams
{
protected:
    CChainParams(const Consensus::Params& cons) : consensus{cons} { } // or std::move, whatever
public:
    const Consensus::Params consensus;
    ...
};

class CRegTestParams : public CChainParams
{
public:
    CRegTestParams(const ArgsManager& args) : CChainParams{getConsensus(args)}
    { ... }
    
    static Consensus::Params getConsensus(const ArgsManager& args)
    {
        Consensus::Params consensus{};
        consensus.foo = bar; ...
        // parse -segwitheight and -vbparams here as well
    }
};

and have default initializers for everything in Consensus::Params?

Not keen on the map -- the possibility that deployments.at(DEPLOYMENT_FOO) might throw doesn't seem that great to me; and if you're just using deployments[DEPLOYMENT_FOO] and relying on it getting default initialised to something sane, might as well give VBitsDeployment a default initiaizer and just use the array?

consensus.m_deployments.emplace(Consensus::DEPLOYMENT_TESTDUMMY, Consensus::VBitsDeployment(28, false /* active */));

// Deployment of Taproot (BIPs 340-342)
consensus.m_deployments.emplace(Consensus::DEPLOYMENT_TAPROOT, Consensus::VBitsDeployment(2, true /* active */));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually do these comments as /* active= */ false I think

@achow101
Copy link
Member Author

Ah, a different approach that might be worth considering:

That doesn't seem that much different from what we already do now.

Not keen on the map -- the possibility that deployments.at(DEPLOYMENT_FOO) might throw doesn't seem that great to me; and if you're just using deployments[DEPLOYMENT_FOO] and relying on it getting default initialised to something sane, might as well give VBitsDeployment a default initiaizer and just use the array?

It seems better to me to throw (and hard shutdown) than to use some defaults, or worse, uninitialized members. I don't really like the idea of consensus params being initialized with default values that might not actually be what is wanted.

@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 10, 2021

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@practicalswift
Copy link
Contributor

Concept ACK on not using error prone C arrays like maps.

luke-jr and others added 11 commits March 16, 2021 16:53
Co-authored-by: Anthony Towns <aj@erisian.com.au>
Co-authored-by: Anthony Towns <aj@erisian.com.au>
As thresholds are now parameterized, nRuleChangeActivationThreshold is
no longer the threshold used for activating new rule changes. Instead it
is now only used to warn if there is an unkonwn versionbits deployment.
To make this clear, rename to m_vbits_min_threshold and update the
comment describing it.

Additionally, because this is just a minimum used for a warning, reduce
the threshold to 75% so that future soft forks which may have thresholds
lower than 95% will still have warnings.
vDeployments is a C array that is used like a map. To make construction
of deployments and later iteration easier, use a std::map for all things
containing versionbits deployment data.

Also removes MAX_VERSION_BITS_DEPLOYMENTS as it is no longer needed.
Instead of using the default struct constructor and then filling in the
parameters later, add constructors to VBitsDeployment where the
parameters are filled in at initialization.
@jnewbery
Copy link
Contributor

This is built on #21392, which is now closed. Should this PR also be closed?

@fanquake fanquake marked this pull request as draft April 12, 2021 07:05
@maflcko
Copy link
Member

maflcko commented Apr 12, 2021

I'd say it needs rebase after #21377 is merged

@luke-jr
Copy link
Member

luke-jr commented May 13, 2021

This seems to be a lot less readable. Is there a good way to get uninitialised warnings without harming readability, perhaps?

@achow101
Copy link
Member Author

Closing for now, may revisit in the future, or someone else can take it over.

@achow101 achow101 closed this May 25, 2021
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants