>AgentChain

Difficulty Algorithm

AgentChain uses a custom difficulty adjustment algorithm called CalcDifficultyAgentChain. It is designed to converge on a 6-second block time target while remaining simple, predictable, and free of any difficulty bomb mechanism.

Overview

The difficulty algorithm adjusts the mining difficulty of each new block based on how long it took to mine the parent block. If blocks are coming too fast, difficulty increases. If blocks are coming too slow, difficulty decreases. If the block time is within an acceptable range, difficulty stays the same.

Key properties:

  • Target block time: 6 seconds
  • No difficulty bomb: Unlike Ethereum mainnet, there is no exponential difficulty increase over time.
  • Minimum difficulty floor: 131,072 (0x20000), matching the genesis difficulty.
  • Smooth adjustment: Changes are made in increments of parent_difficulty / 2048, preventing sudden jumps.

Pseudocode

function CalcDifficultyAgentChain(time, parent):
    // Target block time: 6 seconds
    target = 6

    // Time difference from parent
    diff = time - parent.time

    // Adjustment factor
    if diff < target:
        adjustment = 1  // increase difficulty
    else if diff >= target and diff < target * 2:
        adjustment = 0  // no change
    else:
        adjustment = -1  // decrease difficulty

    // Apply adjustment
    // adjustment_step = parent.difficulty / 2048
    new_difficulty = parent.difficulty + (parent.difficulty / 2048) * adjustment

    // Minimum difficulty
    if new_difficulty < 131072:
        new_difficulty = 131072

    return new_difficulty

How It Works

Three Zones of Adjustment

The algorithm divides block times into three zones:

| Block Time | Condition | Adjustment | Effect | |------------|-----------|------------|--------| | < 6 seconds | diff < target | +1 | Difficulty increases — blocks are too fast | | 6-11 seconds | diff >= target && diff < target * 2 | 0 | No change — block time is acceptable | | >= 12 seconds | diff >= target * 2 | -1 | Difficulty decreases — blocks are too slow |

The "acceptable" zone spans from exactly the target (6 seconds) up to but not including double the target (12 seconds). This dead zone prevents oscillation by allowing minor variations in block time without triggering adjustments.

Adjustment Step Size

Each adjustment step is exactly parent.difficulty / 2048. This means:

  • At difficulty 131,072 (minimum), each step is 64.
  • At difficulty 1,000,000, each step is approximately 488.
  • At difficulty 1,000,000,000, each step is approximately 488,281.

The step size scales proportionally with difficulty, ensuring that adjustments are always a consistent fraction (~0.049%) of the current difficulty regardless of the absolute value.

Minimum Difficulty Floor

The difficulty can never fall below 131,072 (0x20000). This floor prevents two problems:

  1. Trivial mining: Without a floor, difficulty could theoretically reach 1, allowing instant block creation.
  2. Division by zero protection: Since the adjustment step is difficulty / 2048, extremely low difficulties could produce a step size of 0, causing the algorithm to stall.

The floor value of 131,072 was chosen because it produces a minimum adjustment step of 64, which is large enough for meaningful adjustments while being low enough for initial bootstrapping.

Comparison with Ethereum Mainnet

| Property | Ethereum (pre-Merge) | AgentChain | |----------|---------------------|------------| | Target block time | ~13 seconds | 6 seconds | | Difficulty bomb | Yes (ice age) | No | | Uncle consideration | Yes (adjusts for uncles) | No | | Adjustment zones | Continuous formula | Three discrete zones | | Step size | parent.difficulty / 2048 | parent.difficulty / 2048 | | Minimum difficulty | 131,072 | 131,072 |

The key differences are:

  1. No difficulty bomb. Ethereum's difficulty bomb was a mechanism to force hard forks by making mining exponentially harder over time. AgentChain has no such mechanism — difficulty is purely a function of block times.
  2. No uncle adjustment. Ethereum increased difficulty when uncle blocks were present (indicating network congestion). AgentChain ignores uncles entirely in the difficulty calculation.
  3. Simpler adjustment logic. Ethereum used a more complex formula with a continuous adjustment factor. AgentChain uses three discrete zones for clarity and predictability.

Convergence Behavior

The algorithm converges on the 6-second target through a self-correcting feedback loop:

Scenario: Hashrate Increase

  1. A large miner joins the network.
  2. Blocks start arriving faster than 6 seconds (e.g., 3 seconds).
  3. The algorithm detects diff < target and sets adjustment = +1.
  4. Difficulty increases by difficulty / 2048 on each block.
  5. This continues until block times return to the 6-12 second range.
  6. Once in range, adjustment = 0 and difficulty stabilizes.

Scenario: Hashrate Decrease

  1. A large miner leaves the network.
  2. Blocks start arriving slower than 12 seconds (e.g., 20 seconds).
  3. The algorithm detects diff >= target * 2 and sets adjustment = -1.
  4. Difficulty decreases by difficulty / 2048 on each block.
  5. This continues until block times return to the 6-12 second range.

Convergence Speed

Because each adjustment is approximately 0.049% of the current difficulty, recovering from a large hashrate change requires many blocks. For example, if hashrate doubles overnight:

  • Block times halve (from ~6s to ~3s).
  • Each block increases difficulty by ~0.049%.
  • It takes approximately 1,400 blocks (~2.3 hours at 6s/block) for difficulty to double and restore equilibrium.

This gradual adjustment prevents abrupt difficulty spikes that could destabilize the network.

Implementation Notes

Go Implementation Reference

In the Go-ethereum (Geth) codebase, the difficulty calculation is implemented in the consensus engine. The AgentChain variant replaces the standard calcDifficultyFrontier / calcDifficultyHomestead / makeDifficultyCalculator functions with the custom CalcDifficultyAgentChain function.

func CalcDifficultyAgentChain(time uint64, parent *types.Header) *big.Int {
    target := uint64(6)
    diff := time - parent.Time
 
    var adjustment int64
    if diff < target {
        adjustment = 1
    } else if diff < target*2 {
        adjustment = 0
    } else {
        adjustment = -1
    }
 
    // adjustment_step = parent.Difficulty / 2048
    adjustmentStep := new(big.Int).Div(parent.Difficulty, big.NewInt(2048))
 
    // new_difficulty = parent.Difficulty + adjustmentStep * adjustment
    result := new(big.Int).Set(parent.Difficulty)
    result.Add(result, new(big.Int).Mul(adjustmentStep, big.NewInt(adjustment)))
 
    // Enforce minimum difficulty
    minDifficulty := big.NewInt(131072)
    if result.Cmp(minDifficulty) < 0 {
        result.Set(minDifficulty)
    }
 
    return result
}

Edge Cases

  • Genesis block: The genesis block has difficulty 131,072. The first mined block (block 1) uses this as the parent difficulty.
  • Timestamp manipulation: Miners could theoretically set a future timestamp to trigger a difficulty decrease. However, Geth rejects blocks with timestamps too far in the future (typically 15 seconds ahead of local time), limiting this attack vector.
  • Zero time delta: If time == parent.time (same second), diff = 0, which is less than the target. Difficulty increases, discouraging timestamp collision.

Monitoring Difficulty

You can monitor the current network difficulty through the JSON-RPC API:

curl -X POST http://localhost:8545 \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false],"id":1}'

The difficulty field in the response shows the current block's difficulty in hexadecimal.