Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions _specs/ecip-1100.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
ecip: 1100
title: MESS (Modified Exponential Subjective Scoring)
lang: en
author: Isaac <b5c6@protonmail.com>
discussions-to: https://github.com/ethereumclassic/ECIPs/issues/374
status: Draft
type: Standards Track
category: ECBP
created: 2020-09-09
license: Apache-2
---

## Abstract

Define a function arbitrating chain acceptance using relative total difficulty and common ancestor time to raise finality confidence.

## Motivation

A low hashrate has caused Ethereum Classic's consensus algorithms to yield inconvenient and undesirable finality rates.

This proposal offers a way to increase the finality rate without tampering with existing "hard" chain consensus functions or characteristics, and to do so with minimal negative side effects.

## Specification

As a successor to established chain reorganization arbitration, the following logic should be added.

The _sinusoidal function_ should be used to derive the "anti/gravity" of a proposed chain segment. The _condition function_ works to derive the necessary total difficulty ratio parameter, comparing it against the antigravity output.

__Sinusoidal Function__

```go
/*
ecbp1100AGSinusoidalA is a "ceilinged" sinusoidal function which limits the domain
to within the first ascent of the curve. X values exceeding this range
are capped to the ceiling limit. The curve's peak has a differentiable transition to its constant ceiling.

h(x)=15 sin((x+12000 π)/(8000))+15+1
*/
func ecbp1100AGSinusoidalA(x float64) (antiGravity float64) {
ampl := float64(15) // amplitude
pDiv := float64(8000) // period divisor
phaseShift := math.Pi * (pDiv * 1.5)
peakX := math.Pi * pDiv // x value of first sin peak where x > 0
if x > peakX {
// Cause the x value to limit to the x value of the first peak of the sin wave (ceiling).
x = peakX
}
return (ampl * math.Sin((x+phaseShift)/pDiv)) + ampl + 1
}
```

__Condition__

```go
// ecpb1100 implements the "MESS" artificial finality mechanism
// "Modified Exponential Subjective Scoring" used to prefer known chain segments
// over later-to-come counterparts, especially proposed segments stretching far into the past.
func (bc *BlockChain) ecbp1100(commonAncestor, current, proposed *types.Header) error {

// Get the total difficulty ratio of the proposed chain segment over the existing one.
commonAncestorTD := bc.GetTd(commonAncestor.Hash(), commonAncestor.Number.Uint64())

proposedParentTD := bc.GetTd(proposed.ParentHash, proposed.Number.Uint64()-1)
proposedTD := new(big.Int).Add(proposed.Difficulty, proposedParentTD)

localTD := bc.GetTd(current.Hash(), current.Number.Uint64())

tdRatio, _ := new(big.Float).Quo(
new(big.Float).SetInt(new(big.Int).Sub(proposedTD, commonAncestorTD)),
new(big.Float).SetInt(new(big.Int).Sub(localTD, commonAncestorTD)),
).Float64()

x := float64(proposed.Time - commonAncestor.Time)
antiGravity := ecbp1100AGSinusoidalA(x)

if tdRatio < antiGravity {
// Using "b/a" here as "'B' chain vs. 'A' chain", where A is original (current), and B is proposed (new).
underpoweredBy := tdRatio / antiGravity
return fmt.Errorf("%w: ECPB1100-MESS: td.B/A%0.6f < antigravity%0.6f (under=%0.6f)",
errReorgFinality, tdRatio, antiGravity, underpoweredBy)
}
return nil
}
```

This is a _modified (M)_ version of Buterin's _Exponential Subjective Scoring (ESS)_ by
- using a capped sinusoidal function instead of an unbounded exponential function
- using the difference of proposed head time(stamp) from common ancestor time(stamp), rather than the previously described block lengths or times of block reception used by Buterin.

See [References](#References) for what I've found on the topic.

## Rationale

#### Benefits

- Mini-forks and normal reorganizations are not effected, since their difficulty variances fall within the curve in this domain (200 seconds, give or take).
- There is no Edge-of-Eternity attack vector (no vulnerable focal points for an attacker to target).
- Partitions resolve quickly and consistently.
- Intentional partitions are extremely difficult to maintain.
- The sinusoidal function naturally yields a "ceiling" that would be extravagantly high for an attacker to achieve relative to the main network, but within reasonable operating bounds for the victim of an eclipse attack to eventually recover and rejoin the network. Unbounded exponential growth for the antigravity function serves no purpose beyond some point.

#### Costs

- Nodes subject to eclipse attacks (mostly considered as nodes coming online after a long time or starting out) are vulnerable to destitution, even once released. This is addressed by the function's ceiling causing the attacker to need to establish (and maintain) a total difficulty 1/31x of the competing honest chain, and can be addressed further by the operator including a checkpoint value.
- It may be anticipated that the network uncle and waste rates will rise slightly, as blocks that would otherwise be [randomly included](http://www.cs.cornell.edu/~ie53/publications/btcProcFC.pdf) will be rejected. ETC currently has a 3.5% uncle rate compared to ETH's 5.5%.


#### Discussion of Constant Parameters

The _sin_ function uses constant parameters `period = 2pi/8000` and `amplitude = 15`, the values of which are reasoned as follows.

The _period_ value of `2pi/8000` causes the peak of the sin wave (and ultimate ceiling) to occur at 25132 seconds (approximately 7 hours). This falls in between the rates of the previously considered exponential functions. The "ramp up" domain (nearest `x=0`) sees a flattened curve, yielding a more generous lenience for competing short segments. The _sin_ curve eventually intersects the original exponential function at about 900 seconds (15 minutes) at about `y=1.09`.

The _amplitude_ value of `15` causes the peak to occur at `(2*15)+1 = 31`. This value means that the maximum "antigravity" an attack will face is a 31, where the proposed chain would need a total difficulty 31 times that of the chain it would replace.

The _phase shift_ of `1.5pi * 8000` is trivially derivable by seeking `f(0) = 1`.

These values were chosen for ETC with the following assumptions and reasoning.

- Assume global Ethash hashrate availability is 200TH.
- Assume greatest single Ethash mining _entity_ is 33% of the global, yielding about 66TH. This is considered as the largest possible antagonist for the ETC chain.
- Assume ETC has 3TH total contributed hashrate.
- Following this, we deduce that the largest Ethash mining entity has 22 times of ETC's current mining power. An "attack" by this entity on ETC would result in a `(66/(66+3))*100 = 95`% attack.
- Given a 22x anticipated "reasonable" worst-case scenario, the amplitude of `15` yielding a total `31` ceiling, around 50% above the anticipated worst-case scenario, is intended to be sufficiently future-proof and resilient to unforeseen scenarios.

#### Alternatives Considered

An bounded exponential function would work in much the same way, although it would not have a continuous ceiling transition and would, in a far-edge case, present an exploitable focal point of vulnerability at that transition.

### Comparative Visualizations of (Anti)Gravity Functions

![mess-sin-far](https://user-images.githubusercontent.com/45600330/92998206-2510da80-f4de-11ea-9220-4aeebb1c3cdf.png)

![mess-sin-close](https://user-images.githubusercontent.com/45600330/92998205-217d5380-f4de-11ea-841b-f49cc4192721.png)

The graphs below show a 200 block chain accepting, sidechaining, or rejecting reorganizations of varying relative difficulty and length.

![nomess-acceptreject](https://user-images.githubusercontent.com/45600330/92998210-2a6e2500-f4de-11ea-9c25-3e20bde41ef1.png)

![mess-acceptreject](https://user-images.githubusercontent.com/45600330/92998215-2fcb6f80-f4de-11ea-8af9-178d905c9086.png)

## Implementation

This feature does not require a hard fork, but the network stands to benefit and avoid risk with majority coordinated acivation.

__Core-Geth__

- Feature is tentatively proposed to activate in Core-Geth on Ethereum Classic network at and above block 11295300.
- Feature is proposed to activate in Core-Geth on Ethereum Classic's Mordor test network at and above block 2290740.

- Core-Geth feature implementation includes a few additional safety mechanisms:
+ MESS is disabled for any sync mode besides full sync.
+ MESS is only enabled once a peer has completed initial chain synchronisation, not while they are fast syncing or even full syncing during the download and process phase. This reduces the chances of a node coming online being lured into an eclipse scenario.
+ MESS is only enabled if a peer has greater than or equal to the `2 * MinimumSyncPeers` peers. In Core-Geth this value is by default `5`, yielding a necessary limit of `10` for the MESS feature.
+ MESS is disabled if, once synced, a node's head block is not changed within a time limit (ie becomes stale). In Core-Geth this value is by default `10 * 13 seconds`.

The associated Core-Geth implementation is available [here](https://github.com/etclabscore/core-geth/pull/181).

## References

- https://bitcointalk.org/index.php?topic=865169.msg16349234#msg16349234
- https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/

Bespoke previously considered exponential functions:

```go
/*
ecbp1100AGExpB is an exponential function with x as a base (and rationalized exponent).

OPTION 2: Slightly slower takeoff, steeper eventual ascent
g(x)=x^(x*0.00002)
*/
func ecbp1100AGExpB(x float64) (antiGravity float64) {
return math.Pow(x, x*0.00002)
}
```

```go
/*
ecbp1100AGExpA is an exponential function with x as exponent.

This was (one of?) Buterin's "original" specs:
> 1.0001 ** (number of seconds between when S1 was received and when S2 was received)
- https://bitcointalk.org/index.php?topic=865169.msg16349234#msg16349234
> gravity(B') = gravity(B) * 0.99 ^ n
- https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/

OPTION 1 (Original ESS)
f(x)=1.0001^(x)
*/
func ecbp1100AGExpA(x float64) (antiGravity float64) {
return math.Pow(1.0001, x)
}
```

A further alternative is demonstrated with a _cosin_ function as follows, which, being squared, has an even flatter "ramp up" section. However, since difficulty adjustment is discrete and the
primary case of consideration in this context is one of equivalent difficulty, efforts toward an ultra-low
antigravity product seem well-intentioned but practically ineffectual.

```
s(x)=8 (-cos((0.5 π x)/(6000))+1)^(2)+1
```