ADR-016: MESS (Modified Exponential Subjective Scoring) Implementation¶
Status: Accepted
Date: 2025-11-16
Context¶
Ethereum Classic nodes currently use pure objective consensus based on total difficulty to determine the canonical chain. This approach, while mathematically sound, is vulnerable to certain attack vectors, particularly long-range reorganization attacks where an attacker with historical mining power could attempt to create an alternative chain history that honest nodes might accept.
Problem¶
The current consensus mechanism in Fukuii uses ChainWeight which is calculated based on:
1. Last checkpoint number
2. Total difficulty (sum of all block difficulties in the chain)
This purely objective approach has limitations: - Long-Range Attack Vulnerability: An attacker who controlled significant mining power in the past could secretly mine an alternative chain and later release it, potentially causing a deep reorganization. - Eclipse Attack Amplification: Nodes that are isolated from the network could be fed malicious chains that appear valid based solely on total difficulty. - No Time Awareness: The current system doesn't consider when blocks were first observed, treating all blocks equally regardless of when they arrive.
Background on MESS¶
Modified Exponential Subjective Scoring (MESS) is a consensus enhancement proposed for Ethereum Classic in ECIP-1097/ECBP-1100 (https://github.com/ethereumclassic/ECIPs/pull/373) and implemented in core-geth. MESS adds a subjective component to consensus by:
- Tracking First-Seen Time: Recording when each block is first observed by the node
- Applying Time-Based Penalty: Penalizing blocks that arrive late using an exponential decay function
- Protecting Against Long-Range Attacks: Making it extremely difficult for attackers to create alternative histories that would be accepted
The core principle is that honest nodes will have seen the canonical chain blocks first, while attack chains will arrive later and be heavily penalized.
Decision¶
We will implement MESS in Fukuii as an optional consensus enhancement with the following design:
Architecture¶
┌─────────────────────────────┐
│ Block Reception │
│ (via P2P network) │
└─────────┬───────────────────┘
│
▼
┌─────────────────────────────┐
│ BlockFirstSeenTracker │
│ - Record timestamp │
│ - Store in database │
└─────────┬───────────────────┘
│
▼
┌─────────────────────────────┐
│ MESSScorer │
│ - Calculate penalty │
│ - Apply to chain weight │
└─────────┬───────────────────┘
│
▼
┌─────────────────────────────┐
│ Consensus Evaluation │
│ - Compare weighted chains │
│ - Select canonical chain │
└─────────────────────────────┘
Implementation Components¶
1. Block First-Seen Storage¶
New Storage Layer: BlockFirstSeenStorage
- Stores mapping of block hash → first seen timestamp
- Persists to RocksDB for durability across restarts
- Provides efficient lookup by block hash
trait BlockFirstSeenStorage {
def put(blockHash: ByteString, timestamp: Long): Unit
def get(blockHash: ByteString): Option[Long]
def remove(blockHash: ByteString): Unit
}
2. MESS Scoring Algorithm¶
New Component: MESSScorer
- Calculates time-based penalty for blocks
- Applies exponential decay function
- Returns adjusted chain weight
Formula:
messWeight = difficulty * exp(-lambda * timeDelta)
where:
lambda = decay constant (configurable, default: 0.0001 per second)
timeDelta = max(0, currentTime - firstSeenTime)
For chains:
chainMessWeight = sum(messWeight for each block)
Penalty Characteristics: - Blocks seen immediately: no penalty (exp(0) = 1.0) - Blocks delayed by 1 hour: ~30% penalty (exp(-0.36) ≈ 0.70, retains 70%) - Blocks delayed by 6 hours: ~88.5% penalty (exp(-2.16) ≈ 0.115, retains 11.5%) - Blocks delayed by 24 hours: ~99.98% penalty (exp(-8.64) ≈ 0.00018, retains 0.02%)
3. Configuration¶
Config Path: fukuii.consensus.mess
fukuii {
consensus {
mess {
# Enable MESS scoring (default: false for backward compatibility)
enabled = false
# Decay constant (lambda) in the exponential function
# Higher values = stronger penalties for delayed blocks
# Default: 0.0001 per second
decay-constant = 0.0001
# Maximum time delta to consider (in seconds)
# Blocks older than this are treated as having this age
# Default: 30 days (2592000 seconds)
max-time-delta = 2592000
# Minimum MESS weight multiplier (prevents weights from going to zero)
# Default: 0.0001 (0.01%)
min-weight-multiplier = 0.0001
}
}
}
CLI Override:
- --enable-mess or --mess-enabled: Enable MESS regardless of config
- --disable-mess or --no-mess: Disable MESS regardless of config
- --mess-decay-constant <value>: Override decay constant
4. ChainWeight Enhancement¶
Modified: ChainWeight class
- Add optional MESS score field
- Maintain backward compatibility with non-MESS weights
- Update comparison logic to use MESS score when enabled
case class ChainWeight(
lastCheckpointNumber: BigInt,
totalDifficulty: BigInt,
messScore: Option[BigInt] = None // New field
) extends Ordered[ChainWeight] {
override def compare(that: ChainWeight): Int = {
// If both have MESS scores, use those
// Otherwise fall back to original comparison
(this.messScore, that.messScore) match {
case (Some(thisScore), Some(thatScore)) =>
(this.lastCheckpointNumber, thisScore)
.compare((that.lastCheckpointNumber, thatScore))
case _ =>
this.asTuple.compare(that.asTuple)
}
}
}
5. Integration Points¶
BlockBroadcast Reception: - When new block is received, check if first-seen time exists - If not, record current timestamp - Pass to consensus evaluation with MESS scoring if enabled
Consensus Evaluation:
- ConsensusImpl.evaluateBranch: Apply MESS scoring when comparing branches
- Use MESSScorer to calculate adjusted weights
- Compare using enhanced ChainWeight with MESS scores
Block Import: - Record first-seen time for all imported blocks - Persist to storage before block processing - Handle edge cases (genesis block, checkpoint blocks)
Testing Strategy¶
Unit Tests¶
- MESSScorer Tests:
- Test exponential decay function with various time deltas
- Test edge cases (zero time, very large times, negative times)
- Test configuration parameter effects
-
Test min weight multiplier enforcement
-
BlockFirstSeenStorage Tests:
- Test put/get/remove operations
- Test persistence across restarts
- Test concurrent access patterns
-
Test cleanup of old entries
-
ChainWeight Tests:
- Test MESS score comparison logic
- Test backward compatibility with non-MESS weights
- Test mixing MESS and non-MESS weights
Integration Tests¶
- Consensus Tests:
- Test branch selection with MESS enabled
- Test that recent chain beats old chain with same difficulty
- Test that sufficiently high difficulty overcomes time penalty
-
Test checkpoint interaction with MESS
-
Network Sync Tests:
- Test fast sync with MESS
- Test regular sync with MESS
-
Test peer selection based on MESS-weighted chains
-
Configuration Tests:
- Test enabling/disabling MESS via config
- Test CLI overrides
-
Test parameter adjustments
-
Attack Scenario Tests:
- Simulate long-range attack (old chain revealed late)
- Simulate eclipse attack (isolated node receives delayed chain)
- Verify MESS prevents acceptance of attack chains
Best Practices from core-geth¶
Based on the core-geth implementation and Ethereum Classic community discussions:
- Conservative Default: MESS is disabled by default to maintain backward compatibility and allow gradual adoption
- Configurable Parameters: Allow node operators to tune decay constant based on network conditions
- Persistent Storage: First-seen times must be persistent to maintain protection across restarts
- Genesis Block Handling: Genesis block always has first-seen time = 0 or its timestamp
- Checkpoint Interaction: MESS scoring respects checkpoint-based chain weight (checkpoints take precedence)
- Monitoring: Expose MESS-related metrics for observability
Consequences¶
Positive¶
- Enhanced Security: Protection against long-range reorganization attacks
- Eclipse Attack Mitigation: Isolated nodes are more resistant to being fed malicious chains
- Subjective Finality: Nodes develop stronger confidence in blocks they've seen for longer
- Configurable: Can be disabled if issues arise or for testing
- Backward Compatible: Doesn't break existing consensus when disabled
- Community Alignment: Follows ECIP proposal and core-geth implementation
- Metrics: New observability into consensus behavior
Negative¶
- Subjective Component: Different nodes may have different views based on when they saw blocks
- Mitigation: Only affects edge cases with competing chains; normal operation unaffected
-
Mitigation: Checkpoints provide objective anchors
-
Storage Overhead: Need to persist first-seen timestamps for all blocks
- Mitigation: Relatively small data (8 bytes per block)
-
Mitigation: Can implement cleanup for very old blocks
-
Clock Dependency: Requires reasonably accurate node clocks
- Mitigation: Modern systems have NTP; clock drift is minimal
-
Mitigation: Configurable time tolerances
-
Complexity: Adds another dimension to consensus logic
- Mitigation: Well-encapsulated in dedicated components
-
Mitigation: Comprehensive test coverage
-
Network Latency Considerations: Honest nodes with poor connectivity could be disadvantaged
- Mitigation: Decay constant tuned to only penalize very late blocks (hours/days)
-
Mitigation: Normal network latency (seconds) has negligible impact
-
Restart Behavior: Node restarts don't reset first-seen times (by design)
- Mitigation: This is intentional and correct behavior
- Note: Protects against attacker exploiting node restarts
Security Considerations¶
- Clock Attacks: Attacker manipulating node's clock
- Mitigation: Requires system-level compromise; NTP protects against this
-
Note: If attacker controls system clock, many other attacks are possible
-
Storage Exhaustion: Attacker sending many blocks to fill storage
- Mitigation: Only store for blocks that pass basic validation
-
Mitigation: Implement cleanup policy for very old blocks
-
Parameter Tuning: Incorrect decay constant could weaken security
- Mitigation: Use well-tested default from core-geth
- Mitigation: Document parameter effects clearly
Alternatives Considered¶
1. Pure Checkpoint-Based Finality¶
- Pros: Objective, well-understood, no clock dependency
- Cons: Requires coordinated checkpoint updates, less flexible
- Decision: Use both; checkpoints and MESS complement each other
2. Finality Gadget (Casper FFG)¶
- Pros: Strong finality guarantees
- Cons: Requires proof-of-stake, major protocol change
- Decision: Out of scope; MESS is lighter-weight enhancement
3. Time-to-Live for Reorganizations¶
- Pros: Simple to understand and implement
- Cons: Hard cutoff is less nuanced than exponential decay
- Decision: MESS's exponential function is more flexible
4. No Change (Status Quo)¶
- Pros: No implementation cost, no new risks
- Cons: Remains vulnerable to long-range attacks
- Decision: MESS provides meaningful security improvement
Implementation Plan¶
Phase 1: Core Infrastructure (Week 1-2)¶
- Create
BlockFirstSeenStoragetrait and RocksDB implementation - Add storage initialization in node startup
- Create unit tests for storage layer
- Update
BlockchainConfigwith MESS configuration
Phase 2: MESS Scoring (Week 2-3)¶
- Implement
MESSScorerwith exponential decay function - Create unit tests for scoring algorithm
- Add configuration parsing and validation
- Implement CLI flag support
Phase 3: Consensus Integration (Week 3-4)¶
- Enhance
ChainWeightwith MESS score support - Update
ConsensusImplto use MESS scoring when enabled - Modify block reception to record first-seen times
- Update chain comparison logic
Phase 4: Testing (Week 4-5)¶
- Create integration tests for MESS-enabled consensus
- Test attack scenario simulations
- Test configuration and CLI overrides
- Test backward compatibility (MESS disabled)
Phase 5: Documentation and Metrics (Week 5-6)¶
- Document MESS configuration in runbooks
- Add MESS metrics (Prometheus/Micrometer)
- Update architecture documentation
- Create user guide for MESS feature
Phase 6: Validation (Week 6)¶
- Code review
- Security analysis (CodeQL)
- Performance testing
- Testnet deployment and monitoring
References¶
- ECIP-1097/ECBP-1100: https://github.com/ethereumclassic/ECIPs/pull/373
- core-geth Implementation: https://github.com/etclabscore/core-geth
- Related ADRs:
- CON-002: Bootstrap Checkpoints - Complementary security enhancement
- CON-003: Block Sync Improvements - Related sync mechanism work
Rollout Strategy¶
- Development: Implement with MESS disabled by default
- Testing: Enable on private testnet for validation
- Mordor Testnet: Deploy and monitor on Mordor with MESS enabled
- Community Review: Share findings and gather feedback
- Mainnet Release: Include in release with MESS disabled by default
- Documentation: Publish operator guide for enabling MESS
- Gradual Adoption: Encourage operators to enable after testing
- Future: Consider enabling by default in future release after adoption
Success Criteria¶
- Functional: MESS correctly penalizes late-arriving blocks
- Performance: No significant impact on sync speed or block processing
- Compatibility: Works correctly with MESS enabled and disabled
- Security: Passes attack scenario simulations
- Observability: Metrics allow monitoring of MESS behavior
- Documentation: Clear guides for operators
- Testing: >90% test coverage for MESS components