Skip to content

[PROPOSAL:CONSENSUS][WIP] Simple Extended Consensus Resolution#40

Open
benevanoff wants to merge 16 commits into
nerva-project:masterfrom
benevanoff:SECOR
Open

[PROPOSAL:CONSENSUS][WIP] Simple Extended Consensus Resolution#40
benevanoff wants to merge 16 commits into
nerva-project:masterfrom
benevanoff:SECOR

Conversation

@benevanoff
Copy link
Copy Markdown
Contributor

@benevanoff benevanoff commented Mar 3, 2026

SECOR

https://github.com/masari-project/research-corner/blob/master/secor/secor.pdf

Proposal Summary

I would like to increase the speed of Nerva transactions by integrating the "Simple Extendend Consensus Resolution" (SECOR) protocol into Nerva.

The goal is to better define how the network should respond to temporary chain forks when an orphan block is found and reduce deep chain reorganizations.

Consensus

When two blocks are found for the top block height, all network participants should reorganize so that the block with Proof-of-Work which clears the highest difficulty should be on top.

Miners should include the hash of the losing block in their next block via the uncle_hash block field.

A miner will be rewarded an additional bonus for including that uncle block hash in their block, and the difficulty for the uncle block will be included in the chain cumulative difficulty, giving a miner who includes a valid uncle hash an advantage over miners who may choose not to.

Miner Transaction Format

Miner transactions should include only 1 reward output if the uncle_hash is null.

If an uncle block is included in the block, then the miner transaction must include a secondary transaction output.

In order to generate a transaction on behalf of another miner in a non-interactive way without compromising privacy, we re-use the keys associated with the original uncle block miner transaction from the alt chain into the nephew block.

Since output index is a part of the stealth address generation algorithm, Hs(aR|i)*G + B = Hs(rA|i)G + B (see cryptonote whitepaper section 4.3), the ordering of the output destinations in the transaction is important.

If a block doesn't reference an uncle block, then there should be only one output in the reward transaction, which should be used to reward the person who mined the block. If that block is then included into a nephew block as an uncle block, then the nephew block must place the reward for the uncle miner, using the output key from the uncle block miner tx, into the nephew block miner transaction at index 0. The reward for the person who found the nephew block should be placed at index 1 in the reward transaction.

If an uncle block references an uncle block itself, then the reward to the true uncle miner should be at index 1 in the uncle block. To accomodate this, the reward to the nephew miner in the main chain should be addressed to output index 0 so that the uncle reward from index 1 may be recycled.

Block Reward Bonuses

I use the reward constants proposed in the original SECOR paper: +5% of the base reward amount to the nephew miner and 50% of the base reward amount to the uncle miner. The impact of this is detailed in the "Block Reward Rationale" section.

The optimal reward for Nerva's implementation is still an active research question.

Block Time Target and Transaction Maturity

Nerva currently has a target block time of 1 minute and requires a maturity of 20 blocks to spend non-miner transaction outputs. I propose to use a 15 second block time as proposed in the original SECOR paper. The first (and only known?) project to integrate SECOR with CryptoNote was Masari, which decreased from a 2 minute to a 1 minute block time. Therefore, real-world behavior with a 15 second block time is currently unknown. Further research should be done to select/confirm the optimal block time for Nerva.

With a 20 block transaction maturity threshold and a 15 seconds block target, it should take about 5 minutes for a transaction to mature. If we succeed in preventing blockchain reorganizations > depth 1, then we may be able to decrease the threshold to only 5 blocks, or 75 seconds.

Block Reward Rationale

Maximum block reward emission per minute, R, given base reward X:

R = X + (X/2) + (X/20)
R = X + (10X/20) + (X/20)
R = X + (11X/20)

If we keep the base emission reward the same, X=0.3, then...

R = 0.3 + ((11*0.3)/20) = 0.465

If we preserve the current emission target of R=0.3 then...

0.3 = (20X/20) + (11X/20) = 31X/20
0.3 * 20 = 31X
X = (0.3 * 20) / 31 = 0.19354838709

If you have an estimate of how frequently uncle blocks are included in the blockchain, Z, then you can scale the reward to produce the same estimated average emission.

R = X + (((X/2) + (X/20)) * Z)
R = X + ((11X/20) * Z)

If we think that uncle blocks will be included in half of the main chain blocks then...

0.3 = X + ((11X/20) * 0.5)
0.3 = X + (11X/40)
0.3 = 51X / 40
X = (0.3 * 40) / 51 = 0.23529411764

Modeling Orphan/Uncle Block Frequencies

Mining is essentially an IID process as the output of the hashing function used for mining should be an IID random variable. Each time the miner chooses a nonce and produces a hash, the miner has either found a valid block for the given difficulty, or they have not and must attempt again with a successive independent trial. The probabilities for this kind of binary problem follow a bernoulli distribution. Therefore, a binomial distribution where k=1, aka a geometric distribution, can be used to model the cumulative probability of finding a block after mining n hashes.

A block difficulty target is used to control the rate at which blockchain can be written to. Nerva currently has a block time target of 1 block per minute. If there are 10 miners on the network, each mining at a rate of 5 hashes/second, then the target difficulty should eventualy fit to about 10*5*60.

Scenario A - Few miners, low difficulty.

Suppose:
There is a target block time of 60 seconds.
There are 2 miners, miner A and miner B, on the network, each mining at a rate of 1 H/s.

Then:
The network difficulty should be 1*2*60=120
The probability that miner A finds a block after 1 second of hashing is 1/120.
The probability that miner B has found a block after 1 second of hashing is also 1/120.

The probability that miner A finds a block after 2 seconds of hashing is 2/120.
The probability that miner B has found a block after 2 seconds of hashing is also 1/120.

The probability that miner A and miner B both find a block after 1 second of mining (at the same time) is (1/120)*(1/120) per IID joint probability.

The cumulative probability that miner A finds a block after 2 seconds of mining is 1 - (1-(1/120))^2 per geometric CDF
The cumulative probability that miner B finds a block after 2 seconds of mining is 1 - (1-(1/120))^2 per geometric CDF

The probability that miner A and miner B have both found a block after 2 seconds of mining is (1 - (1-(1/120))^2)^2

The probability that miner A and miner B have both found a block after 10 seconds of mining is (1 - (1-(1/120))^10)^2

The probability that a given miner finds a block after mining for 1 minute is 1 - ((1-(1/120))^60), roughly 40%.

The probability that both miners have each found a block after 1 minute of mining is (1 - ((1-(1/120))^60))^2, which is roughly 15%.

Scenario B - Few miners, higher difficulty.

Suppose:
There is a target block time of 60 seconds.
There are 2 miners, miner A and miner B, on the network, each mining at a rate of 1,000 H/s.

Then:
The network difficulty should be 1000*2*60=120000
The probability that miner A finds a block after mining a single hash is 1/120000.
The probability that miner B has found a block after mining a single is also 1/120000.

The probability that miner A and miner B both find a block at the same time after each mining a single hash is (1/120000)^2 per IID joint probability.

The probability that a given miner finds a block after mining for 1 second is 1 - ((1-(1/120000))^1000) per geometric CDF.

The probability that miner A and miner B have both found a block after mining 10 hashes is (1 - (1-(1/120000))^10)^2

The probability that miner A and miner B have both found after 1 second of mining is (1 - (1-(1/120000))^1000)^2

The probability that a given miner finds a block after mining for 1 minute is 1 - ((1-(1/120000))^60000), which is roughly 40%. This is the same as when the network hashrate is only 2 H/s.

The probability that both miners have each found a block after mining for 1 minute is (1 - ((1-(1/120000))^60000))^2, which is roughly 15%.

Scenario C - Many miners

Suppose:
There is a target block time of 60 seconds.
There are 100 miners on the network, each mining at a rate of 1,000 H/s.

Then:
The network difficulty should be 1000*100*60=6000000
The probability that a given miner finds a block after mining a single hash is 1/6000000.

The probability that 2 miners both find a block at the same time after each mining a single hash is (1/6000000)^2 per IID joint probability.

The probability that a given miner finds a block after mining for 1 second is 1 - ((1-(1/6000000))^1000) per geometric CDF.

The probability that two miners have both found a block after mining 10 hashes is (1 - (1-(1/6000000))^10)^2

The probability that two miners have both found after 1 second of mining is (1 - (1-(1/6000000))^1000)^2

The cumulative probability that a given miner finds a block after mining for 1 minute is 1 - ((1-(1/6000000))^60000), which is just less than 1%.

The probability that any two miners have each found a block after mining for 1 minute is (100*99/2)*((1-(1-(1/6000000))^(60000))^2)*(((1-(1/6000000))^(60000))^98), per binomial distribution (100, 2) which is about 18%

Overall, the network difficulty adjusts in a way that adding miners to the network doesnt affect the probability of chain splits significantly assuming that mining power is distributed evenly among miners. This model does not account for the fact that adding miners to the network increases the amount of work required for block propogation across all miners on the network.

Status

This proposal is a work in progress. I am seeking community feedback to see if I should continue working on this idea, and to get an idea of what people want to do about the block reward.

TODOs

Coding

  • graceful database migration - currently a sync from scratch is required after upgrading

Research

  • How does changing the difficulty target affect the rest of the difficulty algo parameters ?

    • CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 references this. TX locking can be done with unix timestamps instead of blocks. This should be consistent.
    • DIFFICULTY_BLOCKS_COUNT - should the DIFFICULTY_WINDOW be adjusted ?
    • CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V6 should probably be adjusted
  • How long does it currently take for a block to propogate throughout the network ?

  • Quantify frequency of orphans / chain re-organizations

  • Decide transaction maturity blocks #

Testing

  • Unit test the whole thing

  • Deploy to testnet

@ReufesTech
Copy link
Copy Markdown

Interesting proposal. I understand the motivation behind SECOR with reducing wasted work from stale blocks and incorporating uncle blocks into the chain’s effective weight. That said, this change touches several consensus-critical areas at once, so I think a few things need deeper analysis before it could be considered production-ready.

First is the emission model. With rewards structured as base + uncle + nephew, total issuance becomes dependent on actual uncle frequency. Even if the base reward is adjusted to target an average emission rate, the real uncle rate will depend on network conditions such as propagation latency, miner distribution, and block interval. If those differ from the assumptions used in the model, the effective emission curve could drift. It would be useful to see supply modeling under different uncle-rate scenarios rather than relying on a single expected case.

Second is deterministic uncle handling. Uncle inclusion rules have to be strictly deterministic across all nodes. If more than one valid uncle candidate exists, the protocol needs a clearly defined method for selecting which one is eligible. Any ambiguity here could cause nodes to disagree on block validity, which quickly becomes a consensus problem.

The block interval discussion is another point worth examining. The proposal mentions shorter block targets as a possible direction. If the design moves toward significantly shorter intervals, orphan rates, propagation delay, and difficulty adjustment behavior should all be modeled together. SECOR may reduce wasted work, but shorter intervals will still increase fork frequency and amplify network-latency effects.

There is also the incentive side to consider. Introducing uncle rewards changes miner behavior, and it would be worth analyzing whether the reward ratios introduce any edge cases for strategic block withholding or other unintended mining incentives.

Overall it’s an interesting direction, but because it modifies block structure with reward distribution, and chain weighting at the same time, I’d want to see deterministic uncle rules, emission modeling across different fork-rate scenarios, and some real testnet data before treating it as a candidate consensus upgrade. If it helps move the discussion forward, I’d also be willing to help spin up or participate in a testnet to evaluate how it behaves under real network conditions.

@Rolandjg
Copy link
Copy Markdown

This looks like a good faith addition. It's a bit out of my domain to comment on though.

@benevanoff
Copy link
Copy Markdown
Contributor Author

benevanoff commented Mar 20, 2026

@ReufesTech Thank you for taking time to review my proposal.

You are right that there are many variables which influence the frequency of chain splits/alt chains/orphan block/uncle block. In an effort to better estimate the frequency at which we will encounter uncle blocks and therefore affect the emission rate / money supply, I've started some scripting to gather data about the current state of the network and I've begun reasoning through a statistical model for this problem.

scripts/analyze_alt_chains.py contains a Python script which will dump out the timestamp difference between all all alt block time stamps vs their respective main chain blocks as well as the length of the alt chain and the number of blocks which have passed since the last alt chain was seen. The goal is to first get a picture for how frequently chain splits occur currently on the main net.

You are correct that block propagation times affect the likelihood of chain splits. I've opened #43 to add functionality to the Nerva daemon to record timestamps for when each block is reported by which peer, which I hope can help us to get more visibility into this on the current main net. I still need to work on integrating block propagation times into my statistical model. To be clear, the overall goal of SECOR is to reduce the frequency of chain re-organizations so that we may safely reduce the block time target. (See section 3.1 of the SECOR paper).

Under this proposal, when two blocks are found for the same block height, whichever block has the greatest PoW hash value should be included in the main chain. This preference is coded into the consensus rules such that if two chains with the same cumulative difficulty are seen, the one with the greatest PoW hash value for the top block is chosen as the "winning" chain, and the block with the smaller PoW value hash is not allowed to include the greater value PoW block as an uncle. In the unlikely event that 3 blocks are all found for the same block height within a very short window of time, the greatest PoW hash valued block is given preference for the main chain, and whichever of the 2 alt blocks gets to be the alt block is decided by cumulative difficulty, ie whichever of those chains grows "longest"/"heaviest" first. We are essentially falling back to the current behavior for temporary fork resolution. I believe this resolution mechanism keeps things simple and is sufficient for maintaining stable consensus over time (any ambiguity should be resolved in under a minute or two with 15 second block times).

I agree that the reward co-efficients should be backed up by stronger justification. As I admit in the proposal, the numbers were mostly chosen for convenience while I "got the ball rolling".

Just to be super clear, I agree that all of this needs to be much further tested and reviewed and essentially "voted on" as I am proposing to alter the consensus rules, hence the "WIP" tag and the comments about testing in the post. Again, I appreciate you taking the time to be the first reviewer and sharing thoughts :)

}
else
{
// assumes that tail emission was already reached before/by HF_VERSION_SECOR
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

for such a critical part of code, lets use asserts to make sure our assumption holds. In case of failure, we want the entire operation to fail since it is consider a fatal error.

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.

4 participants