Skip to content

Conversation

@dathonohm
Copy link

@dathonohm dathonohm commented Nov 24, 2025

This PR re-implements #234 as a UASF rather than an MASF. That is, it adds:

  • a max_activation_height which is mutually exclusive with timeout, and
  • a BIP148/BIP8-style mandatory signaling period leading up to lock-in.

Commits prior to "Add DEPLOYMENT_REDUCED_DATA as temporary BIP9 UASF" do not compile; this is intentional to preserve all REDUCED_DATA commits precisely after dropping the original BuriedDeployment commits.

Commits prior to "Add mainnet configuration for REDUCED_DATA deployment" have failing unit tests.

Functional tests are passing on all commits.

Not eligibile for merge until the following are complete:

  • Rebase on v29.2.knots20251110
  • Fix CI failures

@GregTonoski
Copy link

Let me suggest adding a note that OP_RETURN is deprecated in help texts, please.

@cal-gooo
Copy link

what's the timeline to get this merged so the signaling can use this implementation?

@dathonohm
Copy link
Author

dathonohm commented Dec 1, 2025

There is no specific timeline to get this merged into Knots, as it is not confirmed that it will be eligible for merging, even when complete. However, I am aiming to have this draft ready for review in the next few days.

Miner signaling can still use this deployment if the activation client is released after the start of the signaling period (which is today, so this will definitely happen).

@dathonohm
Copy link
Author

dathonohm commented Dec 2, 2025

All comments from #234 are now addressed.

Undrafting since the code is relatively stable now.

Still needs rebase.

@dathonohm
Copy link
Author

@GregTonoski

Let me suggest adding a note that OP_RETURN is deprecated in help texts, please.

OP_RETURN is not deprecated; it is merely limited to 83 bytes in consensus.

@dathonohm dathonohm marked this pull request as ready for review December 2, 2025 23:29
…to reduce data push size limit to 256 bytes (except for P2SH redeemScript push)
…l never), limit non-OP_RETURN scripts to 34 bytes
…BLE_WITNESS_PROGRAM,UPGRADABLE_TAPROOT_VERSION,OP_SUCCESS}
…AM,UPGRADABLE_TAPROOT_VERSION,OP_SUCCESS} on blocks when DEPLOYMENT_REDUCED_DATA is active (never yet)
Add NODE_BIP444 flag to GetDesirableServiceFlags assertions in
peerman_tests and to service flags in denialofservice_tests and
net_tests peer setup.

NODE_BIP444 (bit 27) signals BIP444/REDUCED_DATA enforcement and
is now included in desirable service flags alongside NODE_NETWORK
and NODE_WITNESS for peer connections.
@dathonohm
Copy link
Author

dathonohm commented Dec 3, 2025

Rebased on v29.2.knots20251110.

Ready for review.

@stackingsaunter
Copy link

Concept NACK

There shouldn't be any emergency softfork to address spam without at least a sketeched out permanent solution

@dathonohm
Copy link
Author

@stackingsaunter Please keep conceptual discussion to the BIP PR. This PR is for code review only.

Comment on lines 44 to 51
if (ThresholdState::ACTIVE != versionbitscache.State(index.pprev, params, dep)) return false;

const auto& deployment = params.vDeployments[dep];
// Permanent deployment (never expires)
if (deployment.active_duration == std::numeric_limits<int>::max()) return true;

const int activation_height = versionbitscache.StateSinceHeight(index.pprev, params, dep);
return index.nHeight < activation_height + deployment.active_duration;

Choose a reason for hiding this comment

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

StateSinceHeight() is called even when State() returns ACTIVE. If the deployment transitions from ACTIVE back to some other state (due to code changes or reorg), StateSinceHeight may return unexpected values.

Should we be caching the state check result and passing it to avoid redundant cache lookups?

Copy link
Author

Choose a reason for hiding this comment

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

Can you elaborate on your concern here? StateSinceHeight() is only called when State() returns ACTIVE. In the scenario where the state is ACTIVE then later not active, locks should guarantee that the versionbits cache doesn't change between these two calls.

Let me know if I'm misunderstanding your question.

Copy link
Collaborator

@luke-jr luke-jr left a comment

Choose a reason for hiding this comment

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

Review not complete yet

{RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
{RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
{RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
{RPCResult::Type::NUM, "max_activation_height", "height at which the deployment will activate (2147483647 if not set)"},
Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like it would be better to omit the field entirely, rather than return maxint when unused.

Copy link
Author

Choose a reason for hiding this comment

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

Will change this field only to be populated when used.

{RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
{RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
{RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
{RPCResult::Type::NUM, "max_activation_height", "height at which the deployment will activate (2147483647 if not set)"},
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: "not set" is phrased poorly IMO

Copy link
Author

@dathonohm dathonohm Dec 26, 2025

Choose a reason for hiding this comment

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

How's this: "height at which the deployment will unconditionally activate", and the parameter is now marked as optional?

bip9.pushKV("max_activation_height", chainman.GetConsensus().vDeployments[id].max_activation_height);

// BIP9 status
bip9.pushKV("status", get_state_name(current_state));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think "status_next" (below) won't work correctly for expiring softforks.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, currently the BIP9 state machine treats this deployment as permanently active, even though in practice the rules stop being enforced at the expiry height.

I can add an "EXPIRED" state to the next version of the activation code, if you think this is a good idea. It just seemed unnecessary for this version.

bip9.pushKV("max_activation_height", chainman.GetConsensus().vDeployments[id].max_activation_height);

// BIP9 status
bip9.pushKV("status", get_state_name(current_state));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggest adding a "height_end" with the final enforcement block height, for temporary softforks.

Copy link
Author

Choose a reason for hiding this comment

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

Added in the next update

// Overrides timeout to guarantee activation
stateNext = ThresholdState::LOCKED_IN;
} else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
// Timeout without activation (only if max_activation_height not set)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comment is wrong. If nTimeTimeout is set, it can still trigger a failure if it's reached before max_activation_height - nPeriod

Copy link
Author

Choose a reason for hiding this comment

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

max_activation_height is intended to be mutually exclusive with timeout. Currently there is no validation code to check this for mainnet deployments, but I can add it if you think this is necessary.

See: #238 (comment)

options.version_bits_parameters[Consensus::DeploymentPos(j)] = vbparams;
found = true;
LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height);
LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d, max_activation_height=%d\n", vDeploymentParams[0], vbparams.start_time, vbparams.timeout, vbparams.min_activation_height, vbparams.max_activation_height);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should probably include duration?

Copy link
Author

Choose a reason for hiding this comment

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

Done.

@dathonohm dathonohm requested a review from luke-jr December 27, 2025 02:59
dathonohm and others added 5 commits December 29, 2025 15:14
…ensus limit; add reduced_data deployment name to allow regtest RPC access for testing
…YMENT_REDUCED_DATA); adapt 6 tests to NODE_BIP148 service flag; add assert_equal_without_usage helper for testmempoolaccept results
@dathonohm
Copy link
Author

dathonohm commented Jan 3, 2026

All review comments are now addressed.

CI is now fully passing (except for the "test each commit" job).

A tag has been created for the current version, RC2 (identical to this branch except for the last commit, which updates the UA string for BIP-110).

Next I will make a release for RC2, and clean up the commit history here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants