ECIP1017 implementation for multi-geth

This commit is contained in:
Ellaismer 2018-03-27 05:19:52 -04:00
parent b1184b78ac
commit 9206a1ed6f
2 changed files with 118 additions and 16 deletions

View file

@ -40,6 +40,8 @@ var (
ByzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
maxUncles = 2 // Maximum number of uncles allowed in a single block
allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
DisinflationRateQuotient = big.NewInt(4) // Disinflation rate quotient for ECIP1017
DisinflationRateDivisor = big.NewInt(5) // Disinflation rate divisor for ECIP1017
)
// Various error messages to mark blocks invalid. These should be private to
@ -579,18 +581,105 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
if config.IsByzantium(header.Number) {
blockReward = ByzantiumBlockReward
}
// Accumulate the rewards for the miner and any included uncles
reward := new(big.Int).Set(blockReward)
r := new(big.Int)
for _, uncle := range uncles {
r.Add(uncle.Number, big8)
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r)
if config.HasECIP1017() {
// Ensure value 'era' is configured.
eraLen := config.ECIP1017EraRounds
era := GetBlockEra(header.Number, eraLen)
wr := GetBlockWinnerRewardByEra(era, blockReward) // wr "winner reward". 5, 4, 3.2, 2.56, ...
wurs := GetBlockWinnerRewardForUnclesByEra(era, uncles, blockReward) // wurs "winner uncle rewards"
wr.Add(wr, wurs)
state.AddBalance(header.Coinbase, wr) // $$
r.Div(blockReward, big32)
reward.Add(reward, r)
// Reward uncle miners.
for _, uncle := range uncles {
ur := GetBlockUncleRewardByEra(era, header, uncle, blockReward)
state.AddBalance(uncle.Coinbase, ur) // $$
}
} else {
// Accumulate the rewards for the miner and any included uncles
reward := new(big.Int).Set(blockReward)
r := new(big.Int)
for _, uncle := range uncles {
r.Add(uncle.Number, big8)
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
state.AddBalance(uncle.Coinbase, r)
r.Div(blockReward, big32)
reward.Add(reward, r)
}
state.AddBalance(header.Coinbase, reward)
}
state.AddBalance(header.Coinbase, reward)
}
// As of "Era 2" (zero-index era 1), uncle miners and winners are rewarded equally for each included block.
// So they share this function.
func getEraUncleBlockReward(era *big.Int, blockReward *big.Int) *big.Int {
return new(big.Int).Div(GetBlockWinnerRewardByEra(era, blockReward), big32)
}
// GetBlockUncleRewardByEra gets called _for each uncle miner_ associated with a winner block's uncles.
func GetBlockUncleRewardByEra(era *big.Int, header, uncle *types.Header, blockReward *big.Int) *big.Int {
// Era 1 (index 0):
// An extra reward to the winning miner for including uncles as part of the block, in the form of an extra 1/32 (0.15625ETC) per uncle included, up to a maximum of two (2) uncles.
if era.Cmp(big.NewInt(0)) == 0 {
r := new(big.Int)
r.Add(uncle.Number, big8) // 2,534,998 + 8 = 2,535,006
r.Sub(r, header.Number) // 2,535,006 - 2,534,999 = 7
r.Mul(r, blockReward) // 7 * 5e+18 = 35e+18
r.Div(r, big8) // 35e+18 / 8 = 7/8 * 5e+18
return r
}
return getEraUncleBlockReward(era, blockReward)
}
// GetBlockWinnerRewardForUnclesByEra gets called _per winner_, and accumulates rewards for each included uncle.
// Assumes uncles have been validated and limited (@ func (v *BlockValidator) VerifyUncles).
func GetBlockWinnerRewardForUnclesByEra(era *big.Int, uncles []*types.Header, blockReward *big.Int) *big.Int {
r := big.NewInt(0)
for range uncles {
r.Add(r, getEraUncleBlockReward(era, blockReward)) // can reuse this, since 1/32 for winner's uncles remain unchanged from "Era 1"
}
return r
}
// GetRewardByEra gets a block reward at disinflation rate.
// Constants MaxBlockReward, DisinflationRateQuotient, and DisinflationRateDivisor assumed.
func GetBlockWinnerRewardByEra(era *big.Int, blockReward *big.Int) *big.Int {
if era.Cmp(big.NewInt(0)) == 0 {
return new(big.Int).Set(blockReward)
}
// MaxBlockReward _r_ * (4/5)**era == MaxBlockReward * (4**era) / (5**era)
// since (q/d)**n == q**n / d**n
// qed
var q, d, r *big.Int = new(big.Int), new(big.Int), new(big.Int)
q.Exp(DisinflationRateQuotient, era, nil)
d.Exp(DisinflationRateDivisor, era, nil)
r.Mul(blockReward, q)
r.Div(r, d)
return r
}
// GetBlockEra gets which "Era" a given block is within, given an era length (ecip-1017 has era=5,000,000 blocks)
// Returns a zero-index era number, so "Era 1": 0, "Era 2": 1, "Era 3": 2 ...
func GetBlockEra(blockNum, eraLength *big.Int) *big.Int {
// If genesis block or impossible negative-numbered block, return zero-val.
if blockNum.Sign() < 1 {
return new(big.Int)
}
remainder := big.NewInt(0).Mod(big.NewInt(0).Sub(blockNum, big.NewInt(1)), eraLength)
base := big.NewInt(0).Sub(blockNum, remainder)
d := big.NewInt(0).Div(base, eraLength)
dremainder := big.NewInt(0).Mod(d, big.NewInt(1))
return new(big.Int).Sub(d, dremainder)
}

View file

@ -59,6 +59,7 @@ var (
ByzantiumBlock: nil,
DisposalBlock: big.NewInt(0),
ConstantinopleBlock: nil,
ECIP1017EraRounds: big.NewInt(10000000),
Ethash: new(EthashConfig),
}
@ -102,16 +103,16 @@ var (
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, new(EthashConfig), nil}
TestRules = TestChainConfig.Rules(new(big.Int))
)
@ -139,6 +140,8 @@ type ChainConfig struct {
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
ECIP1017EraRounds *big.Int `json:"ecip1017EraRounds,omitempty"` // ECIP1017 era rounds
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
@ -174,7 +177,7 @@ func (c *ChainConfig) String() string {
default:
engine = "unknown"
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v, Disposal: %v, Constantinople: %v Engine: %v}",
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v, Disposal: %v, ECIP1017: %v, Constantinople: %v, Engine: %v}",
c.ChainId,
c.HomesteadBlock,
c.DAOForkBlock,
@ -184,11 +187,21 @@ func (c *ChainConfig) String() string {
c.EIP158Block,
c.ByzantiumBlock,
c.DisposalBlock,
c.ECIP1017EraRounds,
c.ConstantinopleBlock,
engine,
)
}
// HasECIP1017 returns whether the chain is configured with ECIP1017.
func (c *ChainConfig) HasECIP1017() bool {
if c.ECIP1017EraRounds == nil {
return false
} else {
return true
}
}
// IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
return isForked(c.HomesteadBlock, num)