Skip to content

Commit

Permalink
EVM-607 Hard-forking PoC (#1544)
Browse files Browse the repository at this point in the history
  • Loading branch information
igorcrevar committed Jun 2, 2023
1 parent 7e66cd5 commit fb7a3f3
Show file tree
Hide file tree
Showing 17 changed files with 612 additions and 141 deletions.
2 changes: 1 addition & 1 deletion blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,7 @@ func (b *Blockchain) Close() error {

// CalculateBaseFee calculates the basefee of the header.
func (b *Blockchain) CalculateBaseFee(parent *types.Header) uint64 {
if !b.config.Params.Forks.IsLondon(parent.Number) {
if !b.config.Params.Forks.IsActive(chain.London, parent.Number) {
return chain.GenesisBaseFee
}

Expand Down
3 changes: 1 addition & 2 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1365,12 +1365,11 @@ func TestBlockchain_CalculateBaseFee(t *testing.T) {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
t.Parallel()

fork := chain.Fork(5)
blockchain := Blockchain{
config: &chain.Chain{
Params: &chain.Params{
Forks: &chain.Forks{
London: &fork,
chain.London: chain.NewFork(5),
},
},
Genesis: &chain.Genesis{
Expand Down
9 changes: 5 additions & 4 deletions blockchain/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,14 @@ func NewTestBlockchain(t *testing.T, headers []*types.Header) *Blockchain {
Number: 0,
GasLimit: 0,
}
forksAvail := &chain.Forks{
chain.EIP155: chain.NewFork(0),
chain.Homestead: chain.NewFork(0),
}
config := &chain.Chain{
Genesis: genesis,
Params: &chain.Params{
Forks: &chain.Forks{
EIP155: chain.NewFork(0),
Homestead: chain.NewFork(0),
},
Forks: forksAvail,
BlockGasTarget: defaultBlockGasTarget,
},
}
Expand Down
2 changes: 0 additions & 2 deletions chain/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ type Chain struct {

// Genesis specifies the header fields, state of a genesis block
type Genesis struct {
Config *Params `json:"config"`

Nonce [8]byte `json:"nonce"`
Timestamp uint64 `json:"timestamp"`
ExtraData []byte `json:"extraData,omitempty"`
Expand Down
88 changes: 33 additions & 55 deletions chain/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,70 +74,46 @@ func (p *Params) GetEngine() string {
return ""
}

// Forks specifies when each fork is activated
type Forks struct {
Homestead *Fork `json:"homestead,omitempty"`
Byzantium *Fork `json:"byzantium,omitempty"`
Constantinople *Fork `json:"constantinople,omitempty"`
Petersburg *Fork `json:"petersburg,omitempty"`
Istanbul *Fork `json:"istanbul,omitempty"`
London *Fork `json:"london,omitempty"`
EIP150 *Fork `json:"EIP150,omitempty"`
EIP158 *Fork `json:"EIP158,omitempty"`
EIP155 *Fork `json:"EIP155,omitempty"`
}

func (f *Forks) active(ff *Fork, block uint64) bool {
if ff == nil {
return false
}

return ff.Active(block)
}

func (f *Forks) IsHomestead(block uint64) bool {
return f.active(f.Homestead, block)
}

func (f *Forks) IsByzantium(block uint64) bool {
return f.active(f.Byzantium, block)
}

func (f *Forks) IsConstantinople(block uint64) bool {
return f.active(f.Constantinople, block)
}

func (f *Forks) IsPetersburg(block uint64) bool {
return f.active(f.Petersburg, block)
}
// predefined forks
const (
Homestead = "homestead"
Byzantium = "byzantium"
Constantinople = "constantinople"
Petersburg = "petersburg"
Istanbul = "istanbul"
London = "london"
EIP150 = "EIP150"
EIP158 = "EIP158"
EIP155 = "EIP155"
)

func (f *Forks) IsLondon(block uint64) bool {
return f.active(f.London, block)
}
// Forks is map which contains all forks and their starting blocks from genesis
type Forks map[string]*Fork

func (f *Forks) IsEIP150(block uint64) bool {
return f.active(f.EIP150, block)
}
// IsActive returns true if fork defined by name exists and defined for the block
func (f *Forks) IsActive(name string, block uint64) bool {
ff := (*f)[name]

func (f *Forks) IsEIP158(block uint64) bool {
return f.active(f.EIP158, block)
return ff != nil && ff.Active(block)
}

func (f *Forks) IsEIP155(block uint64) bool {
return f.active(f.EIP155, block)
// SetFork adds/updates fork defined by name
func (f *Forks) SetFork(name string, value *Fork) {
(*f)[name] = value
}

// At returns ForksInTime instance that shows which supported forks are enabled for the block
func (f *Forks) At(block uint64) ForksInTime {
return ForksInTime{
Homestead: f.active(f.Homestead, block),
Byzantium: f.active(f.Byzantium, block),
Constantinople: f.active(f.Constantinople, block),
Petersburg: f.active(f.Petersburg, block),
Istanbul: f.active(f.Istanbul, block),
London: f.active(f.London, block),
EIP150: f.active(f.EIP150, block),
EIP158: f.active(f.EIP158, block),
EIP155: f.active(f.EIP155, block),
Homestead: f.IsActive(Homestead, block),
Byzantium: f.IsActive(Byzantium, block),
Constantinople: f.IsActive(Constantinople, block),
Petersburg: f.IsActive(Petersburg, block),
Istanbul: f.IsActive(Istanbul, block),
London: f.IsActive(London, block),
EIP150: f.IsActive(EIP150, block),
EIP158: f.IsActive(EIP158, block),
EIP155: f.IsActive(EIP155, block),
}
}

Expand All @@ -157,6 +133,7 @@ func (f Fork) Int() *big.Int {
return big.NewInt(int64(f))
}

// ForksInTime should contain all supported forks by current edge version
type ForksInTime struct {
Homestead,
Byzantium,
Expand All @@ -169,6 +146,7 @@ type ForksInTime struct {
EIP155 bool
}

// AllForksEnabled should contain all supported forks by current edge version
var AllForksEnabled = &Forks{
Homestead: NewFork(0),
EIP150: NewFork(0),
Expand Down
2 changes: 1 addition & 1 deletion command/genesis/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ func (p *genesisParams) initGenesisConfig() error {
// Disable london hardfork if burn contract address is not provided
enabledForks := chain.AllForksEnabled
if len(p.burnContracts) == 0 {
enabledForks.London = nil
enabledForks.SetFork(chain.London, nil)
}

chainConfig := &chain.Chain{
Expand Down
7 changes: 6 additions & 1 deletion command/genesis/polybft_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/0xPolygon/polygon-edge/consensus/polybft/contractsapi/artifact"
"github.com/0xPolygon/polygon-edge/consensus/polybft/validator"
"github.com/0xPolygon/polygon-edge/contracts"
"github.com/0xPolygon/polygon-edge/forkmanager"
"github.com/0xPolygon/polygon-edge/helper/common"
"github.com/0xPolygon/polygon-edge/server"
"github.com/0xPolygon/polygon-edge/types"
Expand Down Expand Up @@ -71,6 +72,10 @@ var (

// generatePolyBftChainConfig creates and persists polybft chain configuration to the provided file path
func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) error {
if err := forkmanager.ForkManagerInit(polybft.ForkManagerFactory, chain.AllForksEnabled); err != nil {
return err
}

// populate premine balance map
premineBalances := make(map[types.Address]*premineInfo, len(p.premine))

Expand Down Expand Up @@ -149,7 +154,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
// Disable london hardfork if burn contract address is not provided
enabledForks := chain.AllForksEnabled
if len(p.burnContracts) == 0 {
enabledForks.London = nil
enabledForks.SetFork(chain.London, nil)
}

chainConfig := &chain.Chain{
Expand Down
11 changes: 0 additions & 11 deletions consensus/polybft/extra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,6 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) {
const validatorsCount = 7
vals := validator.NewTestValidators(t, validatorsCount)

polyBftConfig := PolyBFTConfig{InitialValidatorSet: vals.GetParamValidators()}

delta := &validator.ValidatorSetDelta{
Added: make(validator.AccountSet, validatorsCount),
Removed: bitmap.Bitmap{},
Expand All @@ -516,9 +514,6 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) {
extra := Extra{Validators: delta}

genesis := &chain.Genesis{
Config: &chain.Params{Engine: map[string]interface{}{
ConsensusName: polyBftConfig,
}},
ExtraData: extra.MarshalRLPTo(nil),
}

Expand All @@ -531,13 +526,7 @@ func TestExtra_InitGenesisValidatorsDelta(t *testing.T) {
t.Run("Invalid Extra data", func(t *testing.T) {
t.Parallel()

validators := validator.NewTestValidators(t, 5)
polyBftConfig := PolyBFTConfig{InitialValidatorSet: validators.GetParamValidators()}

genesis := &chain.Genesis{
Config: &chain.Params{Engine: map[string]interface{}{
ConsensusName: polyBftConfig,
}},
ExtraData: append(make([]byte, ExtraVanity), []byte{0x2, 0x3}...),
}

Expand Down
5 changes: 5 additions & 0 deletions consensus/polybft/polybft.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,11 @@ func GenesisPostHookFactory(config *chain.Chain, engineName string) func(txn *st
}
}

func ForkManagerFactory(forks *chain.Forks) error {
// place fork manager handler registration here
return nil
}

// Initialize initializes the consensus (e.g. setup data)
func (p *Polybft) Initialize() error {
p.logger.Info("initializing polybft...")
Expand Down
78 changes: 78 additions & 0 deletions forkmanager/fork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package forkmanager

import (
"fmt"

"github.com/0xPolygon/polygon-edge/chain"
)

const InitialFork = "initialfork"

// HandlerDesc gives description for the handler
// eq: "extra", "proposer_calculator", etc
type HandlerDesc string

// Fork structure defines one fork
type Fork struct {
// name of the fork
Name string
// after the fork is activated, `FromBlockNumber` shows from which block is enabled
FromBlockNumber uint64
// this value is false if fork is registered but not activated
IsActive bool
// map of all handlers registered for this fork
Handlers map[HandlerDesc]interface{}
}

// Handler defines one custom handler
type Handler struct {
// Handler should be active from block `FromBlockNumber``
FromBlockNumber uint64
// instance of some structure, function etc
Handler interface{}
}

func ForkManagerInit(factory func(*chain.Forks) error, forks *chain.Forks) error {
if factory == nil {
return nil
}

fm := GetInstance()
fm.Clear()

// register initial fork
fm.RegisterFork(InitialFork)

// Register forks
for name := range *forks {
// check if fork is not supported by current edge version
if _, found := (*chain.AllForksEnabled)[name]; !found {
return fmt.Errorf("fork is not available: %s", name)
}

fm.RegisterFork(name)
}

// Register handlers and additional forks here
if err := factory(forks); err != nil {
return err
}

// Activate initial fork
if err := fm.ActivateFork(InitialFork, uint64(0)); err != nil {
return err
}

// Activate forks
for name, blockNumber := range *forks {
if blockNumber == nil {
continue
}

if err := fm.ActivateFork(name, (uint64)(*blockNumber)); err != nil {
return err
}
}

return nil
}
Loading

0 comments on commit fb7a3f3

Please sign in to comment.