mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
ECIP1017 implementation for multi-geth
This commit is contained in:
parent
b1184b78ac
commit
9206a1ed6f
2 changed files with 118 additions and 16 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue