mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
Merge 215787789b into 888b71b3cf
This commit is contained in:
commit
308d4008c6
47 changed files with 1885 additions and 368 deletions
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -74,11 +75,12 @@ func New(ethone consensus.Engine) *Beacon {
|
||||||
// isPostMerge reports whether the given block number is assumed to be post-merge.
|
// isPostMerge reports whether the given block number is assumed to be post-merge.
|
||||||
// Here we check the MergeNetsplitBlock to allow configuring networks with a PoW or
|
// Here we check the MergeNetsplitBlock to allow configuring networks with a PoW or
|
||||||
// PoA chain for unit testing purposes.
|
// PoA chain for unit testing purposes.
|
||||||
func isPostMerge(config *params.ChainConfig, blockNum uint64, timestamp uint64) bool {
|
func isPostMerge(config *params.Config2, blockNum uint64, timestamp uint64) bool {
|
||||||
mergedAtGenesis := config.TerminalTotalDifficulty != nil && config.TerminalTotalDifficulty.Sign() == 0
|
ttd := params.TerminalTotalDifficulty.Get(config)
|
||||||
|
mergedAtGenesis := ttd != nil && ttd.Sign() == 0
|
||||||
return mergedAtGenesis ||
|
return mergedAtGenesis ||
|
||||||
config.MergeNetsplitBlock != nil && blockNum >= config.MergeNetsplitBlock.Uint64() ||
|
config.Active(forks.Paris, blockNum, timestamp) ||
|
||||||
config.ShanghaiTime != nil && timestamp >= *config.ShanghaiTime
|
config.Active(forks.Shanghai, blockNum, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Author implements consensus.Engine, returning the verified author of the block.
|
// Author implements consensus.Engine, returning the verified author of the block.
|
||||||
|
|
@ -256,7 +258,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Verify existence / non-existence of withdrawalsHash.
|
// Verify existence / non-existence of withdrawalsHash.
|
||||||
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
shanghai := chain.Config().Active(forks.Shanghai, header.Number.Uint64(), header.Time)
|
||||||
if shanghai && header.WithdrawalsHash == nil {
|
if shanghai && header.WithdrawalsHash == nil {
|
||||||
return errors.New("missing withdrawalsHash")
|
return errors.New("missing withdrawalsHash")
|
||||||
}
|
}
|
||||||
|
|
@ -264,7 +266,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
||||||
}
|
}
|
||||||
// Verify the existence / non-existence of cancun-specific header fields
|
// Verify the existence / non-existence of cancun-specific header fields
|
||||||
cancun := chain.Config().IsCancun(header.Number, header.Time)
|
cancun := chain.Config().Active(forks.Cancun, header.Number.Uint64(), header.Time)
|
||||||
if !cancun {
|
if !cancun {
|
||||||
switch {
|
switch {
|
||||||
case header.ExcessBlobGas != nil:
|
case header.ExcessBlobGas != nil:
|
||||||
|
|
@ -357,7 +359,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
if !beacon.IsPoSHeader(header) {
|
if !beacon.IsPoSHeader(header) {
|
||||||
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
|
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
|
||||||
}
|
}
|
||||||
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
|
shanghai := chain.Config().Active(forks.Shanghai, header.Number.Uint64(), header.Time)
|
||||||
if shanghai {
|
if shanghai {
|
||||||
// All blocks after Shanghai must include a withdrawals root.
|
// All blocks after Shanghai must include a withdrawals root.
|
||||||
if body.Withdrawals == nil {
|
if body.Withdrawals == nil {
|
||||||
|
|
@ -379,7 +381,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
|
|
||||||
// Create the block witness and attach to block.
|
// Create the block witness and attach to block.
|
||||||
// This step needs to happen as late as possible to catch all access events.
|
// This step needs to happen as late as possible to catch all access events.
|
||||||
if chain.Config().IsVerkle(header.Number, header.Time) {
|
if chain.Config().Active(forks.Verkle, header.Number.Uint64(), header.Time) {
|
||||||
keys := state.AccessEvents().Keys()
|
keys := state.AccessEvents().Keys()
|
||||||
|
|
||||||
// Open the pre-tree to prove the pre-state against
|
// Open the pre-tree to prove the pre-state against
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
@ -51,20 +52,25 @@ const (
|
||||||
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
|
inmemorySignatures = 4096 // Number of recent block signatures to keep in memory
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExtraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
||||||
|
ExtraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||||
|
|
||||||
|
DiffInTurn = 2 // Block difficulty for in-turn signatures
|
||||||
|
DiffNoTurn = 1 // Block difficulty for out-of-turn signatures
|
||||||
|
)
|
||||||
|
|
||||||
// Clique proof-of-authority protocol constants.
|
// Clique proof-of-authority protocol constants.
|
||||||
var (
|
var (
|
||||||
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
epochLength = uint64(30000) // Default number of blocks after which to checkpoint and reset the pending votes
|
||||||
|
|
||||||
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
|
|
||||||
extraSeal = crypto.SignatureLength // Fixed number of extra-data suffix bytes reserved for signer seal
|
|
||||||
|
|
||||||
nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
|
nonceAuthVote = hexutil.MustDecode("0xffffffffffffffff") // Magic nonce number to vote on adding a new signer
|
||||||
nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.
|
nonceDropVote = hexutil.MustDecode("0x0000000000000000") // Magic nonce number to vote on removing a signer.
|
||||||
|
|
||||||
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW.
|
||||||
|
|
||||||
diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
|
diffInTurn = big.NewInt(DiffInTurn)
|
||||||
diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures
|
diffNoTurn = big.NewInt(DiffNoTurn)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Various error messages to mark blocks invalid. These should be private to
|
// Various error messages to mark blocks invalid. These should be private to
|
||||||
|
|
@ -145,10 +151,10 @@ func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
|
||||||
return address, nil
|
return address, nil
|
||||||
}
|
}
|
||||||
// Retrieve the signature from the header extra-data
|
// Retrieve the signature from the header extra-data
|
||||||
if len(header.Extra) < extraSeal {
|
if len(header.Extra) < ExtraSeal {
|
||||||
return common.Address{}, errMissingSignature
|
return common.Address{}, errMissingSignature
|
||||||
}
|
}
|
||||||
signature := header.Extra[len(header.Extra)-extraSeal:]
|
signature := header.Extra[len(header.Extra)-ExtraSeal:]
|
||||||
|
|
||||||
// Recover the public key and the Ethereum address
|
// Recover the public key and the Ethereum address
|
||||||
pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature)
|
pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature)
|
||||||
|
|
@ -165,7 +171,7 @@ func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
|
||||||
// Clique is the proof-of-authority consensus engine proposed to support the
|
// Clique is the proof-of-authority consensus engine proposed to support the
|
||||||
// Ethereum testnet following the Ropsten attacks.
|
// Ethereum testnet following the Ropsten attacks.
|
||||||
type Clique struct {
|
type Clique struct {
|
||||||
config *params.CliqueConfig // Consensus engine configuration parameters
|
config *Config // Consensus engine configuration parameters
|
||||||
db ethdb.Database // Database to store and retrieve snapshot checkpoints
|
db ethdb.Database // Database to store and retrieve snapshot checkpoints
|
||||||
|
|
||||||
recents *lru.Cache[common.Hash, *Snapshot] // Snapshots for recent block to speed up reorgs
|
recents *lru.Cache[common.Hash, *Snapshot] // Snapshots for recent block to speed up reorgs
|
||||||
|
|
@ -182,18 +188,17 @@ type Clique struct {
|
||||||
|
|
||||||
// New creates a Clique proof-of-authority consensus engine with the initial
|
// New creates a Clique proof-of-authority consensus engine with the initial
|
||||||
// signers set to the ones provided by the user.
|
// signers set to the ones provided by the user.
|
||||||
func New(config *params.CliqueConfig, db ethdb.Database) *Clique {
|
func New(config Config, db ethdb.Database) *Clique {
|
||||||
// Set any missing consensus parameters to their defaults
|
// Set any missing consensus parameters to their defaults
|
||||||
conf := *config
|
if config.Epoch == 0 {
|
||||||
if conf.Epoch == 0 {
|
config.Epoch = epochLength
|
||||||
conf.Epoch = epochLength
|
|
||||||
}
|
}
|
||||||
// Allocate the snapshot caches and create the engine
|
// Allocate the snapshot caches and create the engine
|
||||||
recents := lru.NewCache[common.Hash, *Snapshot](inmemorySnapshots)
|
recents := lru.NewCache[common.Hash, *Snapshot](inmemorySnapshots)
|
||||||
signatures := lru.NewCache[common.Hash, common.Address](inmemorySignatures)
|
signatures := lru.NewCache[common.Hash, common.Address](inmemorySignatures)
|
||||||
|
|
||||||
return &Clique{
|
return &Clique{
|
||||||
config: &conf,
|
config: &config,
|
||||||
db: db,
|
db: db,
|
||||||
recents: recents,
|
recents: recents,
|
||||||
signatures: signatures,
|
signatures: signatures,
|
||||||
|
|
@ -260,14 +265,14 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
||||||
return errInvalidCheckpointVote
|
return errInvalidCheckpointVote
|
||||||
}
|
}
|
||||||
// Check that the extra-data contains both the vanity and signature
|
// Check that the extra-data contains both the vanity and signature
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < ExtraVanity {
|
||||||
return errMissingVanity
|
return errMissingVanity
|
||||||
}
|
}
|
||||||
if len(header.Extra) < extraVanity+extraSeal {
|
if len(header.Extra) < ExtraVanity+ExtraSeal {
|
||||||
return errMissingSignature
|
return errMissingSignature
|
||||||
}
|
}
|
||||||
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
|
// Ensure that the extra-data contains a signer list on checkpoint, but none otherwise
|
||||||
signersBytes := len(header.Extra) - extraVanity - extraSeal
|
signersBytes := len(header.Extra) - ExtraVanity - ExtraSeal
|
||||||
if !checkpoint && signersBytes != 0 {
|
if !checkpoint && signersBytes != 0 {
|
||||||
return errExtraSigners
|
return errExtraSigners
|
||||||
}
|
}
|
||||||
|
|
@ -292,14 +297,14 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
||||||
if header.GasLimit > params.MaxGasLimit {
|
if header.GasLimit > params.MaxGasLimit {
|
||||||
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
|
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, params.MaxGasLimit)
|
||||||
}
|
}
|
||||||
if chain.Config().IsShanghai(header.Number, header.Time) {
|
if chain.Config().Active(forks.Shanghai, header.Number.Uint64(), header.Time) {
|
||||||
return errors.New("clique does not support shanghai fork")
|
return errors.New("clique does not support shanghai fork")
|
||||||
}
|
}
|
||||||
// Verify the non-existence of withdrawalsHash.
|
// Verify the non-existence of withdrawalsHash.
|
||||||
if header.WithdrawalsHash != nil {
|
if header.WithdrawalsHash != nil {
|
||||||
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
||||||
}
|
}
|
||||||
if chain.Config().IsCancun(header.Number, header.Time) {
|
if chain.Config().Active(forks.Cancun, header.Number.Uint64(), header.Time) {
|
||||||
return errors.New("clique does not support cancun fork")
|
return errors.New("clique does not support cancun fork")
|
||||||
}
|
}
|
||||||
// Verify the non-existence of cancun-specific header fields
|
// Verify the non-existence of cancun-specific header fields
|
||||||
|
|
@ -342,7 +347,7 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
||||||
if header.GasUsed > header.GasLimit {
|
if header.GasUsed > header.GasLimit {
|
||||||
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||||
}
|
}
|
||||||
if !chain.Config().IsLondon(header.Number) {
|
if !chain.Config().Active(forks.London, header.Number.Uint64(), header.Time) {
|
||||||
// Verify BaseFee not present before EIP-1559 fork.
|
// Verify BaseFee not present before EIP-1559 fork.
|
||||||
if header.BaseFee != nil {
|
if header.BaseFee != nil {
|
||||||
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
|
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
|
||||||
|
|
@ -365,8 +370,8 @@ func (c *Clique) verifyCascadingFields(chain consensus.ChainHeaderReader, header
|
||||||
for i, signer := range snap.signers() {
|
for i, signer := range snap.signers() {
|
||||||
copy(signers[i*common.AddressLength:], signer[:])
|
copy(signers[i*common.AddressLength:], signer[:])
|
||||||
}
|
}
|
||||||
extraSuffix := len(header.Extra) - extraSeal
|
extraSuffix := len(header.Extra) - ExtraSeal
|
||||||
if !bytes.Equal(header.Extra[extraVanity:extraSuffix], signers) {
|
if !bytes.Equal(header.Extra[ExtraVanity:extraSuffix], signers) {
|
||||||
return errMismatchingCheckpointSigners
|
return errMismatchingCheckpointSigners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -404,9 +409,9 @@ func (c *Clique) snapshot(chain consensus.ChainHeaderReader, number uint64, hash
|
||||||
if checkpoint != nil {
|
if checkpoint != nil {
|
||||||
hash := checkpoint.Hash()
|
hash := checkpoint.Hash()
|
||||||
|
|
||||||
signers := make([]common.Address, (len(checkpoint.Extra)-extraVanity-extraSeal)/common.AddressLength)
|
signers := make([]common.Address, (len(checkpoint.Extra)-ExtraVanity-ExtraSeal)/common.AddressLength)
|
||||||
for i := 0; i < len(signers); i++ {
|
for i := 0; i < len(signers); i++ {
|
||||||
copy(signers[i][:], checkpoint.Extra[extraVanity+i*common.AddressLength:])
|
copy(signers[i][:], checkpoint.Extra[ExtraVanity+i*common.AddressLength:])
|
||||||
}
|
}
|
||||||
snap = newSnapshot(c.config, c.signatures, number, hash, signers)
|
snap = newSnapshot(c.config, c.signatures, number, hash, signers)
|
||||||
if err := snap.store(c.db); err != nil {
|
if err := snap.store(c.db); err != nil {
|
||||||
|
|
@ -544,17 +549,17 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header
|
||||||
header.Difficulty = calcDifficulty(snap, signer)
|
header.Difficulty = calcDifficulty(snap, signer)
|
||||||
|
|
||||||
// Ensure the extra data has all its components
|
// Ensure the extra data has all its components
|
||||||
if len(header.Extra) < extraVanity {
|
if len(header.Extra) < ExtraVanity {
|
||||||
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, extraVanity-len(header.Extra))...)
|
header.Extra = append(header.Extra, bytes.Repeat([]byte{0x00}, ExtraVanity-len(header.Extra))...)
|
||||||
}
|
}
|
||||||
header.Extra = header.Extra[:extraVanity]
|
header.Extra = header.Extra[:ExtraVanity]
|
||||||
|
|
||||||
if number%c.config.Epoch == 0 {
|
if number%c.config.Epoch == 0 {
|
||||||
for _, signer := range snap.signers() {
|
for _, signer := range snap.signers() {
|
||||||
header.Extra = append(header.Extra, signer[:]...)
|
header.Extra = append(header.Extra, signer[:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
|
header.Extra = append(header.Extra, make([]byte, ExtraSeal)...)
|
||||||
|
|
||||||
// Mix digest is reserved for now, set to empty
|
// Mix digest is reserved for now, set to empty
|
||||||
header.MixDigest = common.Hash{}
|
header.MixDigest = common.Hash{}
|
||||||
|
|
@ -587,7 +592,8 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
||||||
c.Finalize(chain, header, state, body)
|
c.Finalize(chain, header, state, body)
|
||||||
|
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
deleteEmptyObjects := chain.Config().Active(forks.SpuriousDragon, header.Number.Uint64(), header.Time)
|
||||||
|
header.Root = state.IntermediateRoot(deleteEmptyObjects)
|
||||||
|
|
||||||
// Assemble and return the final block for sealing.
|
// Assemble and return the final block for sealing.
|
||||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,14 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package clique
|
package clique_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -40,18 +41,19 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr = crypto.PubkeyToAddress(key.PublicKey)
|
addr = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
engine = New(params.AllCliqueProtocolChanges.Clique, db)
|
config = clique.ConfigParam.Get(presets.AllCliqueProtocolChanges)
|
||||||
|
engine = clique.New(config, db)
|
||||||
signer = new(types.HomesteadSigner)
|
signer = new(types.HomesteadSigner)
|
||||||
)
|
)
|
||||||
genspec := &core.Genesis{
|
genspec := &core.Genesis{
|
||||||
Config: params.AllCliqueProtocolChanges,
|
Config: params.AllCliqueProtocolChanges,
|
||||||
ExtraData: make([]byte, extraVanity+common.AddressLength+extraSeal),
|
ExtraData: make([]byte, clique.ExtraVanity+common.AddressLength+clique.ExtraSeal),
|
||||||
Alloc: map[common.Address]types.Account{
|
Alloc: map[common.Address]types.Account{
|
||||||
addr: {Balance: big.NewInt(10000000000000000)},
|
addr: {Balance: big.NewInt(10000000000000000)},
|
||||||
},
|
},
|
||||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||||
}
|
}
|
||||||
copy(genspec.ExtraData[extraVanity:], addr[:])
|
copy(genspec.ExtraData[clique.ExtraVanity:], addr[:])
|
||||||
|
|
||||||
// Generate a batch of blocks, each properly signed
|
// Generate a batch of blocks, each properly signed
|
||||||
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), genspec, engine, nil)
|
chain, _ := core.NewBlockChain(rawdb.NewMemoryDatabase(), genspec, engine, nil)
|
||||||
|
|
@ -60,7 +62,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
|
_, blocks, _ := core.GenerateChainWithGenesis(genspec, engine, 3, func(i int, block *core.BlockGen) {
|
||||||
// The chain maker doesn't have access to a chain, so the difficulty will be
|
// The chain maker doesn't have access to a chain, so the difficulty will be
|
||||||
// lets unset (nil). Set it here to the correct value.
|
// lets unset (nil). Set it here to the correct value.
|
||||||
block.SetDifficulty(diffInTurn)
|
block.SetDifficulty(big.NewInt(clique.DiffInTurn))
|
||||||
|
|
||||||
// We want to simulate an empty middle block, having the same state as the
|
// We want to simulate an empty middle block, having the same state as the
|
||||||
// first one. The last is needs a state change again to force a reorg.
|
// first one. The last is needs a state change again to force a reorg.
|
||||||
|
|
@ -80,7 +82,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
header.Extra = make([]byte, extraVanity+extraSeal)
|
header.Extra = make([]byte, extraVanity+extraSeal)
|
||||||
header.Difficulty = diffInTurn
|
header.Difficulty = diffInTurn
|
||||||
|
|
||||||
sig, _ := crypto.Sign(SealHash(header).Bytes(), key)
|
sig, _ := crypto.Sign(clique.SealHash(header).Bytes(), key)
|
||||||
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
copy(header.Extra[len(header.Extra)-extraSeal:], sig)
|
||||||
blocks[i] = block.WithSeal(header)
|
blocks[i] = block.WithSeal(header)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
consensus/clique/config.go
Normal file
31
consensus/clique/config.go
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package clique
|
||||||
|
|
||||||
|
import "github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
|
var ConfigParam = params.Define(params.T[Config]{
|
||||||
|
Name: "clique",
|
||||||
|
Optional: true, // optional says
|
||||||
|
Default: Config{},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Config is the consensus engine configs for proof-of-authority based sealing.
|
||||||
|
type Config struct {
|
||||||
|
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
|
||||||
|
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vote represents a single vote that an authorized signer made to modify the
|
// Vote represents a single vote that an authorized signer made to modify the
|
||||||
|
|
@ -52,7 +51,7 @@ type sigLRU = lru.Cache[common.Hash, common.Address]
|
||||||
|
|
||||||
// Snapshot is the state of the authorization voting at a given point in time.
|
// Snapshot is the state of the authorization voting at a given point in time.
|
||||||
type Snapshot struct {
|
type Snapshot struct {
|
||||||
config *params.CliqueConfig // Consensus engine parameters to fine tune behavior
|
config *Config // Consensus engine parameters to fine tune behavior
|
||||||
sigcache *sigLRU // Cache of recent block signatures to speed up ecrecover
|
sigcache *sigLRU // Cache of recent block signatures to speed up ecrecover
|
||||||
|
|
||||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||||
|
|
@ -66,7 +65,7 @@ type Snapshot struct {
|
||||||
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
// newSnapshot creates a new snapshot with the specified startup parameters. This
|
||||||
// method does not initialize the set of recent signers, so only ever use if for
|
// method does not initialize the set of recent signers, so only ever use if for
|
||||||
// the genesis block.
|
// the genesis block.
|
||||||
func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
|
func newSnapshot(config *Config, sigcache *sigLRU, number uint64, hash common.Hash, signers []common.Address) *Snapshot {
|
||||||
snap := &Snapshot{
|
snap := &Snapshot{
|
||||||
config: config,
|
config: config,
|
||||||
sigcache: sigcache,
|
sigcache: sigcache,
|
||||||
|
|
@ -83,7 +82,7 @@ func newSnapshot(config *params.CliqueConfig, sigcache *sigLRU, number uint64, h
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadSnapshot loads an existing snapshot from the database.
|
// loadSnapshot loads an existing snapshot from the database.
|
||||||
func loadSnapshot(config *params.CliqueConfig, sigcache *sigLRU, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
func loadSnapshot(config *Config, sigcache *sigLRU, db ethdb.Database, hash common.Hash) (*Snapshot, error) {
|
||||||
blob, err := db.Get(append(rawdb.CliqueSnapshotPrefix, hash[:]...))
|
blob, err := db.Get(append(rawdb.CliqueSnapshotPrefix, hash[:]...))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package clique
|
package clique_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
// blockchain during header verification.
|
// blockchain during header verification.
|
||||||
type ChainHeaderReader interface {
|
type ChainHeaderReader interface {
|
||||||
// Config retrieves the blockchain's chain configuration.
|
// Config retrieves the blockchain's chain configuration.
|
||||||
Config() *params.ChainConfig
|
Config() *params.Config2
|
||||||
|
|
||||||
// CurrentHeader retrieves the current header from the local chain.
|
// CurrentHeader retrieves the current header from the local chain.
|
||||||
CurrentHeader() *types.Header
|
CurrentHeader() *types.Header
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -249,7 +250,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
|
||||||
}
|
}
|
||||||
// Verify the block's gas usage and (if applicable) verify the base fee.
|
// Verify the block's gas usage and (if applicable) verify the base fee.
|
||||||
if !chain.Config().IsLondon(header.Number) {
|
if !chain.Config().ActiveAtBlock(forks.London, header.Number) {
|
||||||
// Verify BaseFee not present before EIP-1559 fork.
|
// Verify BaseFee not present before EIP-1559 fork.
|
||||||
if header.BaseFee != nil {
|
if header.BaseFee != nil {
|
||||||
return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
|
return fmt.Errorf("invalid baseFee before fork: have %d, expected 'nil'", header.BaseFee)
|
||||||
|
|
@ -265,14 +266,14 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainHeaderReader, header, pa
|
||||||
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
|
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
|
||||||
return consensus.ErrInvalidNumber
|
return consensus.ErrInvalidNumber
|
||||||
}
|
}
|
||||||
if chain.Config().IsShanghai(header.Number, header.Time) {
|
if chain.Config().Active(forks.Shanghai, header.Number.Uint64(), header.Time) {
|
||||||
return errors.New("ethash does not support shanghai fork")
|
return errors.New("ethash does not support shanghai fork")
|
||||||
}
|
}
|
||||||
// Verify the non-existence of withdrawalsHash.
|
// Verify the non-existence of withdrawalsHash.
|
||||||
if header.WithdrawalsHash != nil {
|
if header.WithdrawalsHash != nil {
|
||||||
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
return fmt.Errorf("invalid withdrawalsHash: have %x, expected nil", header.WithdrawalsHash)
|
||||||
}
|
}
|
||||||
if chain.Config().IsCancun(header.Number, header.Time) {
|
if chain.Config().Active(forks.Cancun, header.Number.Uint64(), header.Time) {
|
||||||
return errors.New("ethash does not support cancun fork")
|
return errors.New("ethash does not support cancun fork")
|
||||||
}
|
}
|
||||||
// Verify the non-existence of cancun-specific header fields
|
// Verify the non-existence of cancun-specific header fields
|
||||||
|
|
@ -308,22 +309,22 @@ func (ethash *Ethash) CalcDifficulty(chain consensus.ChainHeaderReader, time uin
|
||||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block should have when created at time
|
// the difficulty that a new block should have when created at time
|
||||||
// given the parent block's time and difficulty.
|
// given the parent block's time and difficulty.
|
||||||
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
func CalcDifficulty(config *params.Config2, time uint64, parent *types.Header) *big.Int {
|
||||||
next := new(big.Int).Add(parent.Number, big1)
|
next := new(big.Int).Add(parent.Number, big1)
|
||||||
switch {
|
switch {
|
||||||
case config.IsGrayGlacier(next):
|
case config.ActiveAtBlock(forks.GrayGlacier, next):
|
||||||
return calcDifficultyEip5133(time, parent)
|
return calcDifficultyEip5133(time, parent)
|
||||||
case config.IsArrowGlacier(next):
|
case config.ActiveAtBlock(forks.ArrowGlacier, next):
|
||||||
return calcDifficultyEip4345(time, parent)
|
return calcDifficultyEip4345(time, parent)
|
||||||
case config.IsLondon(next):
|
case config.ActiveAtBlock(forks.London, next):
|
||||||
return calcDifficultyEip3554(time, parent)
|
return calcDifficultyEip3554(time, parent)
|
||||||
case config.IsMuirGlacier(next):
|
case config.ActiveAtBlock(forks.MuirGlacier, next):
|
||||||
return calcDifficultyEip2384(time, parent)
|
return calcDifficultyEip2384(time, parent)
|
||||||
case config.IsConstantinople(next):
|
case config.ActiveAtBlock(forks.Constantinople, next):
|
||||||
return calcDifficultyConstantinople(time, parent)
|
return calcDifficultyConstantinople(time, parent)
|
||||||
case config.IsByzantium(next):
|
case config.ActiveAtBlock(forks.Byzantium, next):
|
||||||
return calcDifficultyByzantium(time, parent)
|
return calcDifficultyByzantium(time, parent)
|
||||||
case config.IsHomestead(next):
|
case config.ActiveAtBlock(forks.Homestead, next):
|
||||||
return calcDifficultyHomestead(time, parent)
|
return calcDifficultyHomestead(time, parent)
|
||||||
default:
|
default:
|
||||||
return calcDifficultyFrontier(time, parent)
|
return calcDifficultyFrontier(time, parent)
|
||||||
|
|
@ -519,7 +520,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||||
ethash.Finalize(chain, header, state, body)
|
ethash.Finalize(chain, header, state, body)
|
||||||
|
|
||||||
// Assign the final state root to header.
|
// Assign the final state root to header.
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().ActiveAtBlock(forks.SpuriousDragon, header.Number))
|
||||||
|
|
||||||
// Header seems complete, assemble into a block and return
|
// Header seems complete, assemble into a block and return
|
||||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
||||||
|
|
@ -567,13 +568,13 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
// accumulateRewards credits the coinbase of the given block with the mining
|
// accumulateRewards credits the coinbase of the given block with the mining
|
||||||
// reward. The total reward consists of the static block reward and rewards for
|
// reward. The total reward consists of the static block reward and rewards for
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||||
func accumulateRewards(config *params.ChainConfig, stateDB vm.StateDB, header *types.Header, uncles []*types.Header) {
|
func accumulateRewards(config *params.Config2, stateDB vm.StateDB, header *types.Header, uncles []*types.Header) {
|
||||||
// Select the correct block reward based on chain progression
|
// Select the correct block reward based on chain progression
|
||||||
blockReward := FrontierBlockReward
|
blockReward := FrontierBlockReward
|
||||||
if config.IsByzantium(header.Number) {
|
if config.ActiveAtBlock(forks.Byzantium, header.Number) {
|
||||||
blockReward = ByzantiumBlockReward
|
blockReward = ByzantiumBlockReward
|
||||||
}
|
}
|
||||||
if config.IsConstantinople(header.Number) {
|
if config.ActiveAtBlock(forks.Constantinople, header.Number) {
|
||||||
blockReward = ConstantinopleBlockReward
|
blockReward = ConstantinopleBlockReward
|
||||||
}
|
}
|
||||||
// Accumulate the rewards for the miner and any included uncles
|
// Accumulate the rewards for the miner and any included uncles
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
type diffTest struct {
|
type diffTest struct {
|
||||||
|
|
@ -74,7 +75,7 @@ func TestCalcDifficulty(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
|
config := params.NewConfig2(params.Activations{forks.Homestead: 1150000})
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ package misc
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -46,18 +46,21 @@ var (
|
||||||
// with the fork specific extra-data set.
|
// with the fork specific extra-data set.
|
||||||
// - if the node is pro-fork, require blocks in the specific range to have the
|
// - if the node is pro-fork, require blocks in the specific range to have the
|
||||||
// unique extra-data set.
|
// unique extra-data set.
|
||||||
func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
|
func VerifyDAOHeaderExtraData(config *params.Config2, header *types.Header) error {
|
||||||
// Short circuit validation if the node doesn't care about the DAO fork
|
// Short circuit validation if the node doesn't care about the DAO fork
|
||||||
if config.DAOForkBlock == nil {
|
if !config.Scheduled(forks.DAO) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the block is within the fork's modified extra-data range
|
// Make sure the block is within the fork's modified extra-data range
|
||||||
limit := new(big.Int).Add(config.DAOForkBlock, params.DAOForkExtraRange)
|
activation, _ := config.Activation(forks.DAO)
|
||||||
if header.Number.Cmp(config.DAOForkBlock) < 0 || header.Number.Cmp(limit) >= 0 {
|
limit := activation + uint64(params.DAOForkExtraRange)
|
||||||
|
if header.Number.Uint64() < activation || header.Number.Uint64() >= limit {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depending on whether we support or oppose the fork, validate the extra-data contents
|
// Depending on whether we support or oppose the fork, validate the extra-data contents
|
||||||
if config.DAOForkSupport {
|
if params.DAOForkSupport.Get(config) {
|
||||||
if !bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
if !bytes.Equal(header.Extra, params.DAOForkBlockExtra) {
|
||||||
return ErrBadProDAOExtra
|
return ErrBadProDAOExtra
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,16 +25,33 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var FeeConfigParam = params.Define(params.T[FeeConfig]{
|
||||||
|
Name: "eip1559Config",
|
||||||
|
Optional: true,
|
||||||
|
Default: FeeConfig{
|
||||||
|
ElasticityMultiplier: params.DefaultElasticityMultiplier,
|
||||||
|
BaseFeeChangeDenominator: params.DefaultBaseFeeChangeDenominator,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
type FeeConfig struct {
|
||||||
|
ElasticityMultiplier uint64 `json:"elasticityMultiplier"`
|
||||||
|
BaseFeeChangeDenominator uint64 `json:"baseFeeChangeDenominator"`
|
||||||
|
}
|
||||||
|
|
||||||
// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
|
// VerifyEIP1559Header verifies some header attributes which were changed in EIP-1559,
|
||||||
// - gas limit check
|
// - gas limit check
|
||||||
// - basefee check
|
// - basefee check
|
||||||
func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Header) error {
|
func VerifyEIP1559Header(config *params.Config2, parent, header *types.Header) error {
|
||||||
|
feecfg := FeeConfigParam.Get(config)
|
||||||
|
|
||||||
// Verify that the gas limit remains within allowed bounds
|
// Verify that the gas limit remains within allowed bounds
|
||||||
parentGasLimit := parent.GasLimit
|
parentGasLimit := parent.GasLimit
|
||||||
if !config.IsLondon(parent.Number) {
|
if !config.Active(forks.London, parent.Number.Uint64(), parent.Time) {
|
||||||
parentGasLimit = parent.GasLimit * config.ElasticityMultiplier()
|
parentGasLimit = parent.GasLimit * feecfg.ElasticityMultiplier
|
||||||
}
|
}
|
||||||
if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
|
if err := misc.VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -53,13 +70,15 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcBaseFee calculates the basefee of the header.
|
// CalcBaseFee calculates the basefee of the header.
|
||||||
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
func CalcBaseFee(config *params.Config2, parent *types.Header) *big.Int {
|
||||||
|
feecfg := FeeConfigParam.Get(config)
|
||||||
|
|
||||||
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||||
if !config.IsLondon(parent.Number) {
|
if !config.Active(forks.London, parent.Number.Uint64(), parent.Time) {
|
||||||
return new(big.Int).SetUint64(params.InitialBaseFee)
|
return new(big.Int).SetUint64(params.InitialBaseFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
parentGasTarget := parent.GasLimit / config.ElasticityMultiplier()
|
parentGasTarget := parent.GasLimit / feecfg.ElasticityMultiplier
|
||||||
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||||
if parent.GasUsed == parentGasTarget {
|
if parent.GasUsed == parentGasTarget {
|
||||||
return new(big.Int).Set(parent.BaseFee)
|
return new(big.Int).Set(parent.BaseFee)
|
||||||
|
|
@ -76,7 +95,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
num.SetUint64(parent.GasUsed - parentGasTarget)
|
num.SetUint64(parent.GasUsed - parentGasTarget)
|
||||||
num.Mul(num, parent.BaseFee)
|
num.Mul(num, parent.BaseFee)
|
||||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
num.Div(num, denom.SetUint64(feecfg.BaseFeeChangeDenominator))
|
||||||
if num.Cmp(common.Big1) < 0 {
|
if num.Cmp(common.Big1) < 0 {
|
||||||
return num.Add(parent.BaseFee, common.Big1)
|
return num.Add(parent.BaseFee, common.Big1)
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +106,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
|
||||||
num.SetUint64(parentGasTarget - parent.GasUsed)
|
num.SetUint64(parentGasTarget - parent.GasUsed)
|
||||||
num.Mul(num, parent.BaseFee)
|
num.Mul(num, parent.BaseFee)
|
||||||
num.Div(num, denom.SetUint64(parentGasTarget))
|
num.Div(num, denom.SetUint64(parentGasTarget))
|
||||||
num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
|
num.Div(num, denom.SetUint64(feecfg.BaseFeeChangeDenominator))
|
||||||
|
|
||||||
baseFee := num.Sub(parent.BaseFee, num)
|
baseFee := num.Sub(parent.BaseFee, num)
|
||||||
if baseFee.Cmp(common.Big0) < 0 {
|
if baseFee.Cmp(common.Big0) < 0 {
|
||||||
|
|
|
||||||
|
|
@ -23,35 +23,15 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
)
|
)
|
||||||
|
|
||||||
// copyConfig does a _shallow_ copy of a given config. Safe to set new values, but
|
func config() *params.Config2 {
|
||||||
// do not use e.g. SetInt() on the numbers. For testing only
|
config := presets.AllEthashProtocolChanges
|
||||||
func copyConfig(original *params.ChainConfig) *params.ChainConfig {
|
config = config.SetActivations(params.Activations{
|
||||||
return ¶ms.ChainConfig{
|
forks.London: 5,
|
||||||
ChainID: original.ChainID,
|
})
|
||||||
HomesteadBlock: original.HomesteadBlock,
|
|
||||||
DAOForkBlock: original.DAOForkBlock,
|
|
||||||
DAOForkSupport: original.DAOForkSupport,
|
|
||||||
EIP150Block: original.EIP150Block,
|
|
||||||
EIP155Block: original.EIP155Block,
|
|
||||||
EIP158Block: original.EIP158Block,
|
|
||||||
ByzantiumBlock: original.ByzantiumBlock,
|
|
||||||
ConstantinopleBlock: original.ConstantinopleBlock,
|
|
||||||
PetersburgBlock: original.PetersburgBlock,
|
|
||||||
IstanbulBlock: original.IstanbulBlock,
|
|
||||||
MuirGlacierBlock: original.MuirGlacierBlock,
|
|
||||||
BerlinBlock: original.BerlinBlock,
|
|
||||||
LondonBlock: original.LondonBlock,
|
|
||||||
TerminalTotalDifficulty: original.TerminalTotalDifficulty,
|
|
||||||
Ethash: original.Ethash,
|
|
||||||
Clique: original.Clique,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func config() *params.ChainConfig {
|
|
||||||
config := copyConfig(params.TestChainConfig)
|
|
||||||
config.LondonBlock = big.NewInt(5)
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,12 @@ package eip4844
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -32,10 +34,11 @@ var (
|
||||||
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
|
||||||
// if the current block contains no transactions, the excessBlobGas is updated
|
// if the current block contains no transactions, the excessBlobGas is updated
|
||||||
// accordingly.
|
// accordingly.
|
||||||
func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Header) error {
|
func VerifyEIP4844Header(config *params.Config2, parent, header *types.Header) error {
|
||||||
if header.Number.Uint64() != parent.Number.Uint64()+1 {
|
if header.Number.Uint64() != parent.Number.Uint64()+1 {
|
||||||
panic("bad header pair")
|
panic("bad header pair")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the header is not malformed
|
// Verify the header is not malformed
|
||||||
if header.ExcessBlobGas == nil {
|
if header.ExcessBlobGas == nil {
|
||||||
return errors.New("header is missing excessBlobGas")
|
return errors.New("header is missing excessBlobGas")
|
||||||
|
|
@ -43,8 +46,14 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
if header.BlobGasUsed == nil {
|
if header.BlobGasUsed == nil {
|
||||||
return errors.New("header is missing blobGasUsed")
|
return errors.New("header is missing blobGasUsed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blobcfg := scheduleAtTime(config, header.Time)
|
||||||
|
if blobcfg == nil {
|
||||||
|
return fmt.Errorf("blob schedule is undefined at time %d", header.Time)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that the blob gas used remains within reasonable limits.
|
// Verify that the blob gas used remains within reasonable limits.
|
||||||
maxBlobGas := MaxBlobGasPerBlock(config, header.Time)
|
maxBlobGas := uint64(blobcfg.Max) * params.BlobTxBlobGasPerBlob
|
||||||
if *header.BlobGasUsed > maxBlobGas {
|
if *header.BlobGasUsed > maxBlobGas {
|
||||||
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas)
|
return fmt.Errorf("blob gas used %d exceeds maximum allowance %d", *header.BlobGasUsed, maxBlobGas)
|
||||||
}
|
}
|
||||||
|
|
@ -61,7 +70,7 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
|
||||||
|
|
||||||
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
|
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
|
||||||
// blobs on top of the excess blob gas.
|
// blobs on top of the excess blob gas.
|
||||||
func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTimestamp uint64) uint64 {
|
func CalcExcessBlobGas(config *params.Config2, parent *types.Header, headTimestamp uint64) uint64 {
|
||||||
var (
|
var (
|
||||||
parentExcessBlobGas uint64
|
parentExcessBlobGas uint64
|
||||||
parentBlobGasUsed uint64
|
parentBlobGasUsed uint64
|
||||||
|
|
@ -78,7 +87,7 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
|
||||||
if excessBlobGas < targetGas {
|
if excessBlobGas < targetGas {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if !config.IsOsaka(config.LondonBlock, headTimestamp) {
|
if !config.Active(forks.Osaka, parent.Number.Uint64()+1, headTimestamp) {
|
||||||
// Pre-Osaka, we use the formula defined by EIP-4844.
|
// Pre-Osaka, we use the formula defined by EIP-4844.
|
||||||
return excessBlobGas - targetGas
|
return excessBlobGas - targetGas
|
||||||
}
|
}
|
||||||
|
|
@ -98,94 +107,64 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
// CalcBlobFee calculates the blobfee from the header's excess blob gas field.
|
||||||
func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
|
func CalcBlobFee(config *params.Config2, header *types.Header) *big.Int {
|
||||||
blobConfig := latestBlobConfig(config, header.Time)
|
blobcfg := scheduleAtTime(config, header.Time)
|
||||||
if blobConfig == nil {
|
if blobcfg == nil {
|
||||||
panic("calculating blob fee on unsupported fork")
|
return new(big.Int)
|
||||||
}
|
}
|
||||||
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(blobConfig.UpdateFraction))
|
frac := blobcfg.UpdateFraction
|
||||||
|
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
|
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
|
||||||
func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
func MaxBlobsPerBlock(cfg *params.Config2, time uint64) int {
|
||||||
blobConfig := latestBlobConfig(cfg, time)
|
blobcfg := scheduleAtTime(cfg, time)
|
||||||
if blobConfig == nil {
|
if blobcfg == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return blobConfig.Max
|
return blobcfg.Max
|
||||||
}
|
}
|
||||||
|
|
||||||
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig {
|
// MaxBlobsPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
|
||||||
if cfg.BlobScheduleConfig == nil {
|
func MaxBlobGasPerBlock(cfg *params.Config2, time uint64) uint64 {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
london = cfg.LondonBlock
|
|
||||||
s = cfg.BlobScheduleConfig
|
|
||||||
)
|
|
||||||
switch {
|
|
||||||
case cfg.IsBPO5(london, time) && s.BPO5 != nil:
|
|
||||||
return s.BPO5
|
|
||||||
case cfg.IsBPO4(london, time) && s.BPO4 != nil:
|
|
||||||
return s.BPO4
|
|
||||||
case cfg.IsBPO3(london, time) && s.BPO3 != nil:
|
|
||||||
return s.BPO3
|
|
||||||
case cfg.IsBPO2(london, time) && s.BPO2 != nil:
|
|
||||||
return s.BPO2
|
|
||||||
case cfg.IsBPO1(london, time) && s.BPO1 != nil:
|
|
||||||
return s.BPO1
|
|
||||||
case cfg.IsOsaka(london, time) && s.Osaka != nil:
|
|
||||||
return s.Osaka
|
|
||||||
case cfg.IsPrague(london, time) && s.Prague != nil:
|
|
||||||
return s.Prague
|
|
||||||
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
|
||||||
return s.Cancun
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaxBlobGasPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
|
|
||||||
func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
|
|
||||||
return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob
|
return uint64(MaxBlobsPerBlock(cfg, time)) * params.BlobTxBlobGasPerBlob
|
||||||
}
|
}
|
||||||
|
|
||||||
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
|
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
|
||||||
// configuration, regardless of the currently active fork.
|
// configuration, regardless of the currently active fork.
|
||||||
func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
func LatestMaxBlobsPerBlock(cfg *params.Config2) int {
|
||||||
s := cfg.BlobScheduleConfig
|
blobcfg := scheduleAtTime(cfg, math.MaxUint64)
|
||||||
if s == nil {
|
return blobcfg.Max
|
||||||
return 0
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case s.BPO5 != nil:
|
|
||||||
return s.BPO5.Max
|
|
||||||
case s.BPO4 != nil:
|
|
||||||
return s.BPO4.Max
|
|
||||||
case s.BPO3 != nil:
|
|
||||||
return s.BPO3.Max
|
|
||||||
case s.BPO2 != nil:
|
|
||||||
return s.BPO2.Max
|
|
||||||
case s.BPO1 != nil:
|
|
||||||
return s.BPO1.Max
|
|
||||||
case s.Osaka != nil:
|
|
||||||
return s.Osaka.Max
|
|
||||||
case s.Prague != nil:
|
|
||||||
return s.Prague.Max
|
|
||||||
case s.Cancun != nil:
|
|
||||||
return s.Cancun.Max
|
|
||||||
default:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
|
// targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
|
||||||
func targetBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
|
func targetBlobsPerBlock(cfg *params.Config2, time uint64) int {
|
||||||
blobConfig := latestBlobConfig(cfg, time)
|
return scheduleAtTime(cfg, time).Target
|
||||||
if blobConfig == nil {
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
return blobConfig.Target
|
|
||||||
|
// scheduleAtTime resolves the blob schedule at the given timestamp.
|
||||||
|
func scheduleAtTime(cfg *params.Config2, time uint64) *params.BlobConfig {
|
||||||
|
schedule := params.BlobSchedule.Get(cfg)
|
||||||
|
if schedule == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the latest fork defined by the schedule.
|
||||||
|
forkList := make([]forks.Fork, 0, len(schedule))
|
||||||
|
for f := range schedule {
|
||||||
|
act, ok := cfg.Activation(f)
|
||||||
|
if ok && act <= time {
|
||||||
|
forkList = append(forkList, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forkList = forks.DependencyOrder(forkList)
|
||||||
|
|
||||||
|
// Return the blob config of the last available fork.
|
||||||
|
if len(forkList) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
blobcfg := schedule[forkList[len(forkList)-1]]
|
||||||
|
return &blobcfg
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||||
|
|
@ -206,7 +185,7 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// calcBlobPrice calculates the blob price for a block.
|
// calcBlobPrice calculates the blob price for a block.
|
||||||
func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int {
|
func calcBlobPrice(config *params.Config2, header *types.Header) *big.Int {
|
||||||
blobBaseFee := CalcBlobFee(config, header)
|
blobBaseFee := CalcBlobFee(config, header)
|
||||||
return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob))
|
return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,15 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCalcExcessBlobGas(t *testing.T) {
|
func TestCalcExcessBlobGas(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
config = params.MainnetChainConfig
|
config = presets.Mainnet
|
||||||
targetBlobs = targetBlobsPerBlock(config, *config.CancunTime)
|
cancunTime, _ = config.Activation(forks.Cancun)
|
||||||
|
targetBlobs = targetBlobsPerBlock(config, cancunTime)
|
||||||
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
targetBlobGas = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
||||||
)
|
)
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
|
|
@ -58,10 +61,11 @@ func TestCalcExcessBlobGas(t *testing.T) {
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob
|
blobGasUsed := uint64(tt.blobs) * params.BlobTxBlobGasPerBlob
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
|
Number: big.NewInt(1),
|
||||||
ExcessBlobGas: &tt.excess,
|
ExcessBlobGas: &tt.excess,
|
||||||
BlobGasUsed: &blobGasUsed,
|
BlobGasUsed: &blobGasUsed,
|
||||||
}
|
}
|
||||||
result := CalcExcessBlobGas(config, header, *config.CancunTime)
|
result := CalcExcessBlobGas(config, header, cancunTime)
|
||||||
if result != tt.want {
|
if result != tt.want {
|
||||||
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
|
t.Errorf("test %d: excess blob gas mismatch: have %v, want %v", i, result, tt.want)
|
||||||
}
|
}
|
||||||
|
|
@ -69,8 +73,6 @@ func TestCalcExcessBlobGas(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalcBlobFee(t *testing.T) {
|
func TestCalcBlobFee(t *testing.T) {
|
||||||
zero := uint64(0)
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
excessBlobGas uint64
|
excessBlobGas uint64
|
||||||
blobfee int64
|
blobfee int64
|
||||||
|
|
@ -81,7 +83,15 @@ func TestCalcBlobFee(t *testing.T) {
|
||||||
{10 * 1024 * 1024, 23},
|
{10 * 1024 * 1024, 23},
|
||||||
}
|
}
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
config := ¶ms.ChainConfig{LondonBlock: big.NewInt(0), CancunTime: &zero, BlobScheduleConfig: params.DefaultBlobSchedule}
|
config := params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.London: 0,
|
||||||
|
forks.Cancun: 0,
|
||||||
|
},
|
||||||
|
params.BlobSchedule.V(map[forks.Fork]params.BlobConfig{
|
||||||
|
forks.Cancun: *params.DefaultCancunBlobConfig,
|
||||||
|
}),
|
||||||
|
)
|
||||||
header := &types.Header{ExcessBlobGas: &tt.excessBlobGas}
|
header := &types.Header{ExcessBlobGas: &tt.excessBlobGas}
|
||||||
have := CalcBlobFee(config, header)
|
have := CalcBlobFee(config, header)
|
||||||
if have.Int64() != tt.blobfee {
|
if have.Int64() != tt.blobfee {
|
||||||
|
|
@ -130,13 +140,15 @@ func TestFakeExponential(t *testing.T) {
|
||||||
|
|
||||||
func TestCalcExcessBlobGasEIP7918(t *testing.T) {
|
func TestCalcExcessBlobGasEIP7918(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
cfg = params.MergedTestChainConfig
|
cfg = presets.MergedTestChainConfig
|
||||||
targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime)
|
cancunTime, _ = cfg.Activation(forks.Cancun)
|
||||||
|
targetBlobs = targetBlobsPerBlock(cfg, cancunTime)
|
||||||
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
||||||
)
|
)
|
||||||
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
|
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
|
||||||
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
|
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
|
||||||
return &types.Header{
|
return &types.Header{
|
||||||
|
Number: big.NewInt(1),
|
||||||
BaseFee: big.NewInt(int64(parentBaseFee)),
|
BaseFee: big.NewInt(int64(parentBaseFee)),
|
||||||
ExcessBlobGas: &parentExcess,
|
ExcessBlobGas: &parentExcess,
|
||||||
BlobGasUsed: &blobGasUsed,
|
BlobGasUsed: &blobGasUsed,
|
||||||
|
|
@ -160,7 +172,7 @@ func TestCalcExcessBlobGasEIP7918(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime)
|
got := CalcExcessBlobGas(cfg, tc.header, cancunTime)
|
||||||
if got != tc.wantExcessGas {
|
if got != tc.wantExcessGas {
|
||||||
t.Fatalf("%s: excess-blob-gas mismatch – have %d, want %d",
|
t.Fatalf("%s: excess-blob-gas mismatch – have %d, want %d",
|
||||||
tc.name, got, tc.wantExcessGas)
|
tc.name, got, tc.wantExcessGas)
|
||||||
|
|
|
||||||
|
|
@ -601,7 +601,7 @@ func ReadRawReceipts(db ethdb.Reader, hash common.Hash, number uint64) types.Rec
|
||||||
// The current implementation populates these metadata fields by reading the receipts'
|
// The current implementation populates these metadata fields by reading the receipts'
|
||||||
// corresponding block body, so if the block body is not found it will return nil even
|
// corresponding block body, so if the block body is not found it will return nil even
|
||||||
// if the receipt itself is stored.
|
// if the receipt itself is stored.
|
||||||
func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, config *params.ChainConfig) types.Receipts {
|
func ReadReceipts(db ethdb.Reader, hash common.Hash, number uint64, time uint64, config *params.Config2) types.Receipts {
|
||||||
// We're deriving many fields from the block body, retrieve beside the receipt
|
// We're deriving many fields from the block body, retrieve beside the receipt
|
||||||
receipts := ReadRawReceipts(db, hash, number)
|
receipts := ReadRawReceipts(db, hash, number)
|
||||||
if receipts == nil {
|
if receipts == nil {
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
@ -356,7 +356,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
|
|
||||||
// Check that no receipt entries are in a pristine database
|
// Check that no receipt entries are in a pristine database
|
||||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
|
if rs := ReadReceipts(db, hash, 0, 0, presets.TestChainConfig); len(rs) != 0 {
|
||||||
t.Fatalf("non existent receipts returned: %v", rs)
|
t.Fatalf("non existent receipts returned: %v", rs)
|
||||||
}
|
}
|
||||||
// Insert the body that corresponds to the receipts
|
// Insert the body that corresponds to the receipts
|
||||||
|
|
@ -364,7 +364,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
|
|
||||||
// Insert the receipt slice into the database and check presence
|
// Insert the receipt slice into the database and check presence
|
||||||
WriteReceipts(db, hash, 0, receipts)
|
WriteReceipts(db, hash, 0, receipts)
|
||||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 {
|
if rs := ReadReceipts(db, hash, 0, 0, presets.TestChainConfig); len(rs) == 0 {
|
||||||
t.Fatal("no receipts returned")
|
t.Fatal("no receipts returned")
|
||||||
} else {
|
} else {
|
||||||
if err := checkReceiptsRLP(rs, receipts); err != nil {
|
if err := checkReceiptsRLP(rs, receipts); err != nil {
|
||||||
|
|
@ -373,7 +373,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
}
|
}
|
||||||
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
|
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
|
||||||
DeleteBody(db, hash, 0)
|
DeleteBody(db, hash, 0)
|
||||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); rs != nil {
|
if rs := ReadReceipts(db, hash, 0, 0, presets.TestChainConfig); rs != nil {
|
||||||
t.Fatalf("receipts returned when body was deleted: %v", rs)
|
t.Fatalf("receipts returned when body was deleted: %v", rs)
|
||||||
}
|
}
|
||||||
// Ensure that receipts without metadata can be returned without the block body too
|
// Ensure that receipts without metadata can be returned without the block body too
|
||||||
|
|
@ -388,7 +388,7 @@ func TestBlockReceiptStorage(t *testing.T) {
|
||||||
WriteBody(db, hash, 0, body)
|
WriteBody(db, hash, 0, body)
|
||||||
|
|
||||||
DeleteReceipts(db, hash, 0)
|
DeleteReceipts(db, hash, 0)
|
||||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
|
if rs := ReadReceipts(db, hash, 0, 0, presets.TestChainConfig); len(rs) != 0 {
|
||||||
t.Fatalf("deleted receipts returned: %v", rs)
|
t.Fatalf("deleted receipts returned: %v", rs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -751,7 +751,7 @@ func TestReadLogs(t *testing.T) {
|
||||||
|
|
||||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||||
// Check that no receipt entries are in a pristine database
|
// Check that no receipt entries are in a pristine database
|
||||||
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) != 0 {
|
if rs := ReadReceipts(db, hash, 0, 0, presets.TestChainConfig); len(rs) != 0 {
|
||||||
t.Fatalf("non existent receipts returned: %v", rs)
|
t.Fatalf("non existent receipts returned: %v", rs)
|
||||||
}
|
}
|
||||||
// Insert the body that corresponds to the receipts
|
// Insert the body that corresponds to the receipts
|
||||||
|
|
@ -842,7 +842,7 @@ func TestDeriveLogFields(t *testing.T) {
|
||||||
// Derive log metadata fields
|
// Derive log metadata fields
|
||||||
number := big.NewInt(1)
|
number := big.NewInt(1)
|
||||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||||
types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 12, big.NewInt(0), big.NewInt(0), txs)
|
types.Receipts(receipts).DeriveFields(presets.TestChainConfig, hash, number.Uint64(), 12, big.NewInt(0), big.NewInt(0), txs)
|
||||||
|
|
||||||
// Iterate over all the computed fields and check that they're correct
|
// Iterate over all the computed fields and check that they're correct
|
||||||
logIndex := uint(0)
|
logIndex := uint(0)
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ func ReadCanonicalTransaction(db ethdb.Reader, hash common.Hash) (*types.Transac
|
||||||
// ReadCanonicalReceipt retrieves a specific transaction receipt from the database,
|
// ReadCanonicalReceipt retrieves a specific transaction receipt from the database,
|
||||||
// along with its added positional metadata. Notably, only the receipt in the canonical
|
// along with its added positional metadata. Notably, only the receipt in the canonical
|
||||||
// chain is visible.
|
// chain is visible.
|
||||||
func ReadCanonicalReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) {
|
func ReadCanonicalReceipt(db ethdb.Reader, hash common.Hash, config *params.Config2) (*types.Receipt, common.Hash, uint64, uint64) {
|
||||||
// Retrieve the context of the receipt based on the transaction hash
|
// Retrieve the context of the receipt based on the transaction hash
|
||||||
blockNumber := ReadTxLookupEntry(db, hash)
|
blockNumber := ReadTxLookupEntry(db, hash)
|
||||||
if blockNumber == nil {
|
if blockNumber == nil {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/internal/blocktest"
|
"github.com/ethereum/go-ethereum/internal/blocktest"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
@ -278,7 +279,7 @@ func makeBenchBlock() *Block {
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
txs = make([]*Transaction, 70)
|
txs = make([]*Transaction, 70)
|
||||||
receipts = make([]*Receipt, len(txs))
|
receipts = make([]*Receipt, len(txs))
|
||||||
signer = LatestSigner(params.TestChainConfig)
|
signer = LatestSigner(presets.TestChainConfig)
|
||||||
uncles = make([]*Header, 3)
|
uncles = make([]*Header, 3)
|
||||||
)
|
)
|
||||||
header := &Header{
|
header := &Header{
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
|
||||||
|
|
||||||
// DeriveFields fills the receipts with their computed fields based on consensus
|
// DeriveFields fills the receipts with their computed fields based on consensus
|
||||||
// data and contextual infos like containing block and transactions.
|
// data and contextual infos like containing block and transactions.
|
||||||
func (rs Receipts) DeriveFields(config *params.ChainConfig, blockHash common.Hash, blockNumber uint64, blockTime uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error {
|
func (rs Receipts) DeriveFields(config *params.Config2, blockHash common.Hash, blockNumber uint64, blockTime uint64, baseFee *big.Int, blobGasPrice *big.Int, txs []*Transaction) error {
|
||||||
signer := MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
|
signer := MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime)
|
||||||
|
|
||||||
logIndex := uint(0)
|
logIndex := uint(0)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"github.com/kylelemons/godebug/diff"
|
"github.com/kylelemons/godebug/diff"
|
||||||
|
|
@ -330,7 +331,8 @@ func TestDeriveFields(t *testing.T) {
|
||||||
blobGasPrice := big.NewInt(920)
|
blobGasPrice := big.NewInt(920)
|
||||||
receipts := getTestReceipts()
|
receipts := getTestReceipts()
|
||||||
derivedReceipts := clearComputedFieldsOnReceipts(receipts)
|
derivedReceipts := clearComputedFieldsOnReceipts(receipts)
|
||||||
err := Receipts(derivedReceipts).DeriveFields(params.TestChainConfig, blockHash, blockNumber.Uint64(), blockTime, basefee, blobGasPrice, txs)
|
config := presets.AllEthashProtocolChanges
|
||||||
|
err := Receipts(derivedReceipts).DeriveFields(config, blockHash, blockNumber.Uint64(), blockTime, basefee, blobGasPrice, txs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
t.Fatalf("DeriveFields(...) = %v, want <nil>", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,20 +39,23 @@ type sigCache struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeSigner returns a Signer based on the given chain config and block number.
|
// MakeSigner returns a Signer based on the given chain config and block number.
|
||||||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint64) Signer {
|
func MakeSigner(config *params.Config2, blockNumber *big.Int, blockTime uint64) Signer {
|
||||||
|
number := blockNumber.Uint64()
|
||||||
|
chainID := params.ChainID.Get(config)
|
||||||
|
|
||||||
var signer Signer
|
var signer Signer
|
||||||
switch {
|
switch {
|
||||||
case config.IsPrague(blockNumber, blockTime):
|
case config.Active(forks.Prague, number, blockTime):
|
||||||
signer = NewPragueSigner(config.ChainID)
|
signer = NewPragueSigner(chainID)
|
||||||
case config.IsCancun(blockNumber, blockTime):
|
case config.Active(forks.Cancun, number, blockTime):
|
||||||
signer = NewCancunSigner(config.ChainID)
|
signer = NewCancunSigner(chainID)
|
||||||
case config.IsLondon(blockNumber):
|
case config.Active(forks.London, number, blockTime):
|
||||||
signer = NewLondonSigner(config.ChainID)
|
signer = NewLondonSigner(chainID)
|
||||||
case config.IsBerlin(blockNumber):
|
case config.Active(forks.Berlin, number, blockTime):
|
||||||
signer = NewEIP2930Signer(config.ChainID)
|
signer = NewEIP2930Signer(chainID)
|
||||||
case config.IsEIP155(blockNumber):
|
case config.Active(forks.SpuriousDragon, number, blockTime):
|
||||||
signer = NewEIP155Signer(config.ChainID)
|
signer = NewEIP155Signer(chainID)
|
||||||
case config.IsHomestead(blockNumber):
|
case config.Active(forks.Homestead, number, blockTime):
|
||||||
signer = HomesteadSigner{}
|
signer = HomesteadSigner{}
|
||||||
default:
|
default:
|
||||||
signer = FrontierSigner{}
|
signer = FrontierSigner{}
|
||||||
|
|
@ -67,20 +70,22 @@ func MakeSigner(config *params.ChainConfig, blockNumber *big.Int, blockTime uint
|
||||||
//
|
//
|
||||||
// Use this in transaction-handling code where the current block number is unknown. If you
|
// Use this in transaction-handling code where the current block number is unknown. If you
|
||||||
// have the current block number available, use MakeSigner instead.
|
// have the current block number available, use MakeSigner instead.
|
||||||
func LatestSigner(config *params.ChainConfig) Signer {
|
func LatestSigner(config *params.Config2) Signer {
|
||||||
|
chainID := params.ChainID.Get(config)
|
||||||
|
|
||||||
var signer Signer
|
var signer Signer
|
||||||
if config.ChainID != nil {
|
if chainID != nil {
|
||||||
switch {
|
switch {
|
||||||
case config.PragueTime != nil:
|
case config.Scheduled(forks.Prague):
|
||||||
signer = NewPragueSigner(config.ChainID)
|
signer = NewPragueSigner(chainID)
|
||||||
case config.CancunTime != nil:
|
case config.Scheduled(forks.Cancun):
|
||||||
signer = NewCancunSigner(config.ChainID)
|
signer = NewCancunSigner(chainID)
|
||||||
case config.LondonBlock != nil:
|
case config.Scheduled(forks.London):
|
||||||
signer = NewLondonSigner(config.ChainID)
|
signer = NewLondonSigner(chainID)
|
||||||
case config.BerlinBlock != nil:
|
case config.Scheduled(forks.Berlin):
|
||||||
signer = NewEIP2930Signer(config.ChainID)
|
signer = NewEIP2930Signer(chainID)
|
||||||
case config.EIP155Block != nil:
|
case config.Scheduled(forks.SpuriousDragon):
|
||||||
signer = NewEIP155Signer(config.ChainID)
|
signer = NewEIP155Signer(chainID)
|
||||||
default:
|
default:
|
||||||
signer = HomesteadSigner{}
|
signer = HomesteadSigner{}
|
||||||
}
|
}
|
||||||
|
|
@ -198,25 +203,25 @@ func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
|
||||||
}
|
}
|
||||||
// configure legacy signer
|
// configure legacy signer
|
||||||
switch {
|
switch {
|
||||||
case fork >= forks.SpuriousDragon:
|
case fork.After(forks.SpuriousDragon):
|
||||||
s.legacy = NewEIP155Signer(chainID)
|
s.legacy = NewEIP155Signer(chainID)
|
||||||
case fork >= forks.Homestead:
|
case fork.After(forks.Homestead):
|
||||||
s.legacy = HomesteadSigner{}
|
s.legacy = HomesteadSigner{}
|
||||||
default:
|
default:
|
||||||
s.legacy = FrontierSigner{}
|
s.legacy = FrontierSigner{}
|
||||||
}
|
}
|
||||||
s.txtypes[LegacyTxType] = struct{}{}
|
s.txtypes[LegacyTxType] = struct{}{}
|
||||||
// configure tx types
|
// configure tx types
|
||||||
if fork >= forks.Berlin {
|
if fork.After(forks.Berlin) {
|
||||||
s.txtypes[AccessListTxType] = struct{}{}
|
s.txtypes[AccessListTxType] = struct{}{}
|
||||||
}
|
}
|
||||||
if fork >= forks.London {
|
if fork.After(forks.London) {
|
||||||
s.txtypes[DynamicFeeTxType] = struct{}{}
|
s.txtypes[DynamicFeeTxType] = struct{}{}
|
||||||
}
|
}
|
||||||
if fork >= forks.Cancun {
|
if fork.After(forks.Cancun) {
|
||||||
s.txtypes[BlobTxType] = struct{}{}
|
s.txtypes[BlobTxType] = struct{}{}
|
||||||
}
|
}
|
||||||
if fork >= forks.Prague {
|
if fork.After(forks.Prague) {
|
||||||
s.txtypes[SetCodeTxType] = struct{}{}
|
s.txtypes[SetCodeTxType] = struct{}{}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -596,7 +596,7 @@ func BenchmarkHash(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkEffectiveGasTip(b *testing.B) {
|
func BenchmarkEffectiveGasTip(b *testing.B) {
|
||||||
signer := LatestSigner(params.TestChainConfig)
|
signer := LatestSigner(presets.TestChainConfig)
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
txdata := &DynamicFeeTx{
|
txdata := &DynamicFeeTx{
|
||||||
ChainID: big.NewInt(1),
|
ChainID: big.NewInt(1),
|
||||||
|
|
@ -634,7 +634,7 @@ func BenchmarkEffectiveGasTip(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEffectiveGasTipInto(t *testing.T) {
|
func TestEffectiveGasTipInto(t *testing.T) {
|
||||||
signer := LatestSigner(params.TestChainConfig)
|
signer := LatestSigner(presets.TestChainConfig)
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256r1"
|
"github.com/ethereum/go-ethereum/crypto/secp256r1"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -206,21 +207,21 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
|
func activePrecompiledContracts(rules params.Rules2) PrecompiledContracts {
|
||||||
switch {
|
switch {
|
||||||
case rules.IsVerkle:
|
case rules.Active(forks.Verkle):
|
||||||
return PrecompiledContractsVerkle
|
return PrecompiledContractsVerkle
|
||||||
case rules.IsOsaka:
|
case rules.Active(forks.Osaka):
|
||||||
return PrecompiledContractsOsaka
|
return PrecompiledContractsOsaka
|
||||||
case rules.IsPrague:
|
case rules.Active(forks.Prague):
|
||||||
return PrecompiledContractsPrague
|
return PrecompiledContractsPrague
|
||||||
case rules.IsCancun:
|
case rules.Active(forks.Cancun):
|
||||||
return PrecompiledContractsCancun
|
return PrecompiledContractsCancun
|
||||||
case rules.IsBerlin:
|
case rules.Active(forks.Berlin):
|
||||||
return PrecompiledContractsBerlin
|
return PrecompiledContractsBerlin
|
||||||
case rules.IsIstanbul:
|
case rules.Active(forks.Istanbul):
|
||||||
return PrecompiledContractsIstanbul
|
return PrecompiledContractsIstanbul
|
||||||
case rules.IsByzantium:
|
case rules.Active(forks.Byzantium):
|
||||||
return PrecompiledContractsByzantium
|
return PrecompiledContractsByzantium
|
||||||
default:
|
default:
|
||||||
return PrecompiledContractsHomestead
|
return PrecompiledContractsHomestead
|
||||||
|
|
@ -228,7 +229,7 @@ func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration.
|
// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration.
|
||||||
func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
|
func ActivePrecompiledContracts(rules params.Rules2) PrecompiledContracts {
|
||||||
return maps.Clone(activePrecompiledContracts(rules))
|
return maps.Clone(activePrecompiledContracts(rules))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ func enable1344(jt *JumpTable) {
|
||||||
|
|
||||||
// opChainID implements CHAINID opcode
|
// opChainID implements CHAINID opcode
|
||||||
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
|
chainId, _ := uint256.FromBig(params.ChainID.Get(interpreter.evm.chainConfig))
|
||||||
scope.Stack.push(chainId)
|
scope.Stack.push(chainId)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -99,10 +100,10 @@ type EVM struct {
|
||||||
depth int
|
depth int
|
||||||
|
|
||||||
// chainConfig contains information about the current chain
|
// chainConfig contains information about the current chain
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.Config2
|
||||||
|
|
||||||
// chain rules contains the chain rules for the current epoch
|
// chain rules contains the chain rules for the current epoch
|
||||||
chainRules params.Rules
|
chainRules params.Rules2
|
||||||
|
|
||||||
// virtual machine configuration options used to initialise the evm
|
// virtual machine configuration options used to initialise the evm
|
||||||
Config Config
|
Config Config
|
||||||
|
|
@ -130,13 +131,18 @@ type EVM struct {
|
||||||
// database and several configs. It meant to be used throughout the entire
|
// database and several configs. It meant to be used throughout the entire
|
||||||
// state transition of a block, with the transaction context switched as
|
// state transition of a block, with the transaction context switched as
|
||||||
// needed by calling evm.SetTxContext.
|
// needed by calling evm.SetTxContext.
|
||||||
func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
|
func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.Config2, config Config) *EVM {
|
||||||
|
blocknum := uint64(0)
|
||||||
|
if blockCtx.BlockNumber != nil {
|
||||||
|
blocknum = blockCtx.BlockNumber.Uint64()
|
||||||
|
}
|
||||||
|
|
||||||
evm := &EVM{
|
evm := &EVM{
|
||||||
Context: blockCtx,
|
Context: blockCtx,
|
||||||
StateDB: statedb,
|
StateDB: statedb,
|
||||||
Config: config,
|
Config: config,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
chainRules: chainConfig.Rules(blocknum, blockCtx.Time),
|
||||||
jumpDests: newMapJumpDests(),
|
jumpDests: newMapJumpDests(),
|
||||||
}
|
}
|
||||||
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
||||||
|
|
@ -159,7 +165,7 @@ func (evm *EVM) SetJumpDestCache(jumpDests JumpDestCache) {
|
||||||
// SetTxContext resets the EVM with a new transaction context.
|
// SetTxContext resets the EVM with a new transaction context.
|
||||||
// This is not threadsafe and should only be done very cautiously.
|
// This is not threadsafe and should only be done very cautiously.
|
||||||
func (evm *EVM) SetTxContext(txCtx TxContext) {
|
func (evm *EVM) SetTxContext(txCtx TxContext) {
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.Active(forks.Verkle) {
|
||||||
txCtx.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache())
|
txCtx.AccessEvents = state.NewAccessEvents(evm.StateDB.PointCache())
|
||||||
}
|
}
|
||||||
evm.TxContext = txCtx
|
evm.TxContext = txCtx
|
||||||
|
|
@ -209,7 +215,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
p, isPrecompile := evm.precompile(addr)
|
p, isPrecompile := evm.precompile(addr)
|
||||||
|
|
||||||
if !evm.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) {
|
if !isPrecompile && evm.chainRules.Active(forks.Verkle) && !isSystemCall(caller) {
|
||||||
// Add proof of absence to witness
|
// Add proof of absence to witness
|
||||||
// At this point, the read costs have already been charged, either because this
|
// At this point, the read costs have already been charged, either because this
|
||||||
// is a direct tx call, in which case it's covered by the intrinsic gas, or because
|
// is a direct tx call, in which case it's covered by the intrinsic gas, or because
|
||||||
|
|
@ -225,7 +231,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
||||||
gas -= wgas
|
gas -= wgas
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() {
|
if !isPrecompile && evm.chainRules.Active(forks.SpuriousDragon) && value.IsZero() {
|
||||||
// Calling a non-existing account, don't do anything.
|
// Calling a non-existing account, don't do anything.
|
||||||
return nil, gas, nil
|
return nil, gas, nil
|
||||||
}
|
}
|
||||||
|
|
@ -442,7 +448,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
evm.StateDB.SetNonce(caller, nonce+1, tracing.NonceChangeContractCreator)
|
||||||
|
|
||||||
// Charge the contract creation init gas in verkle mode
|
// Charge the contract creation init gas in verkle mode
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.Active(forks.Verkle) {
|
||||||
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas)
|
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas)
|
||||||
if statelessGas > gas {
|
if statelessGas > gas {
|
||||||
return nil, common.Address{}, 0, ErrOutOfGas
|
return nil, common.Address{}, 0, ErrOutOfGas
|
||||||
|
|
@ -455,7 +461,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
|
|
||||||
// We add this to the access list _before_ taking a snapshot. Even if the
|
// We add this to the access list _before_ taking a snapshot. Even if the
|
||||||
// creation fails, the access-list change should not be rolled back.
|
// creation fails, the access-list change should not be rolled back.
|
||||||
if evm.chainRules.IsEIP2929 {
|
if evm.chainRules.Active(forks.Berlin) && !evm.chainRules.Active(forks.Verkle) {
|
||||||
evm.StateDB.AddAddressToAccessList(address)
|
evm.StateDB.AddAddressToAccessList(address)
|
||||||
}
|
}
|
||||||
// Ensure there's no existing contract already at the designated address.
|
// Ensure there's no existing contract already at the designated address.
|
||||||
|
|
@ -486,11 +492,11 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
// acts inside that account.
|
// acts inside that account.
|
||||||
evm.StateDB.CreateContract(address)
|
evm.StateDB.CreateContract(address)
|
||||||
|
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.Active(forks.SpuriousDragon) {
|
||||||
evm.StateDB.SetNonce(address, 1, tracing.NonceChangeNewContract)
|
evm.StateDB.SetNonce(address, 1, tracing.NonceChangeNewContract)
|
||||||
}
|
}
|
||||||
// Charge the contract creation init gas in verkle mode
|
// Charge the contract creation init gas in verkle mode
|
||||||
if evm.chainRules.IsEIP4762 {
|
if evm.chainRules.Active(forks.Verkle) {
|
||||||
consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas)
|
consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas)
|
||||||
if consumed < wanted {
|
if consumed < wanted {
|
||||||
return nil, common.Address{}, 0, ErrOutOfGas
|
return nil, common.Address{}, 0, ErrOutOfGas
|
||||||
|
|
@ -512,7 +518,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
contract.IsDeployment = true
|
contract.IsDeployment = true
|
||||||
|
|
||||||
ret, err = evm.initNewContract(contract, address)
|
ret, err = evm.initNewContract(contract, address)
|
||||||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
if err != nil && (evm.chainRules.Active(forks.Homestead) || err != ErrCodeStoreOutOfGas) {
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
if err != ErrExecutionReverted {
|
if err != ErrExecutionReverted {
|
||||||
contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution)
|
contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution)
|
||||||
|
|
@ -530,16 +536,16 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the max code size has been exceeded, assign err if the case.
|
// Check whether the max code size has been exceeded, assign err if the case.
|
||||||
if evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
|
if evm.chainRules.Active(forks.SpuriousDragon) && len(ret) > params.MaxCodeSize {
|
||||||
return ret, ErrMaxCodeSizeExceeded
|
return ret, ErrMaxCodeSizeExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject code starting with 0xEF if EIP-3541 is enabled.
|
// Reject code starting with 0xEF if EIP-3541 is enabled.
|
||||||
if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon {
|
if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.Active(forks.London) {
|
||||||
return ret, ErrInvalidCode
|
return ret, ErrInvalidCode
|
||||||
}
|
}
|
||||||
|
|
||||||
if !evm.chainRules.IsEIP4762 {
|
if !evm.chainRules.Active(forks.Verkle) {
|
||||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||||
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||||
return ret, ErrCodeStoreOutOfGas
|
return ret, ErrCodeStoreOutOfGas
|
||||||
|
|
@ -576,7 +582,7 @@ func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowmen
|
||||||
// Prague, it can also resolve code pointed to by a delegation designator.
|
// Prague, it can also resolve code pointed to by a delegation designator.
|
||||||
func (evm *EVM) resolveCode(addr common.Address) []byte {
|
func (evm *EVM) resolveCode(addr common.Address) []byte {
|
||||||
code := evm.StateDB.GetCode(addr)
|
code := evm.StateDB.GetCode(addr)
|
||||||
if !evm.chainRules.IsPrague {
|
if !evm.chainRules.Active(forks.Prague) {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
if target, ok := types.ParseDelegation(code); ok {
|
if target, ok := types.ParseDelegation(code); ok {
|
||||||
|
|
@ -591,7 +597,7 @@ func (evm *EVM) resolveCode(addr common.Address) []byte {
|
||||||
// delegation designator. Although this is not accessible in the EVM it is used
|
// delegation designator. Although this is not accessible in the EVM it is used
|
||||||
// internally to associate jumpdest analysis to code.
|
// internally to associate jumpdest analysis to code.
|
||||||
func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash {
|
func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash {
|
||||||
if evm.chainRules.IsPrague {
|
if evm.chainRules.Active(forks.Prague) {
|
||||||
code := evm.StateDB.GetCode(addr)
|
code := evm.StateDB.GetCode(addr)
|
||||||
if target, ok := types.ParseDelegation(code); ok {
|
if target, ok := types.ParseDelegation(code); ok {
|
||||||
// Note we only follow one level of delegation.
|
// Note we only follow one level of delegation.
|
||||||
|
|
@ -602,7 +608,7 @@ func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig returns the environment's chain configuration
|
// ChainConfig returns the environment's chain configuration
|
||||||
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
func (evm *EVM) ChainConfig() *params.Config2 { return evm.chainConfig }
|
||||||
|
|
||||||
func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) {
|
func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) {
|
||||||
tracer := evm.Config.Tracer
|
tracer := evm.Config.Tracer
|
||||||
|
|
@ -623,7 +629,7 @@ func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret [
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reverted = true
|
reverted = true
|
||||||
}
|
}
|
||||||
if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
|
if !evm.chainRules.Active(forks.Homestead) && errors.Is(err, ErrCodeStoreOutOfGas) {
|
||||||
reverted = false
|
reverted = false
|
||||||
}
|
}
|
||||||
if tracer.OnExit != nil {
|
if tracer.OnExit != nil {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
)
|
)
|
||||||
|
|
||||||
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
|
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
|
||||||
|
|
@ -104,7 +105,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||||
// The legacy gas metering only takes into consideration the current state
|
// The legacy gas metering only takes into consideration the current state
|
||||||
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
||||||
// OR Constantinople is not active
|
// OR Constantinople is not active
|
||||||
if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople {
|
if evm.chainRules.Active(forks.Petersburg) || !evm.chainRules.Active(forks.Constantinople) {
|
||||||
// This checks for 3 scenarios and calculates gas accordingly:
|
// This checks for 3 scenarios and calculates gas accordingly:
|
||||||
//
|
//
|
||||||
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
||||||
|
|
@ -374,14 +375,14 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
transfersValue = !stack.Back(2).IsZero()
|
transfersValue = !stack.Back(2).IsZero()
|
||||||
address = common.Address(stack.Back(1).Bytes20())
|
address = common.Address(stack.Back(1).Bytes20())
|
||||||
)
|
)
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.Active(forks.SpuriousDragon) {
|
||||||
if transfersValue && evm.StateDB.Empty(address) {
|
if transfersValue && evm.StateDB.Empty(address) {
|
||||||
gas += params.CallNewAccountGas
|
gas += params.CallNewAccountGas
|
||||||
}
|
}
|
||||||
} else if !evm.StateDB.Exist(address) {
|
} else if !evm.StateDB.Exist(address) {
|
||||||
gas += params.CallNewAccountGas
|
gas += params.CallNewAccountGas
|
||||||
}
|
}
|
||||||
if transfersValue && !evm.chainRules.IsEIP4762 {
|
if transfersValue && !evm.chainRules.Active(forks.Verkle) {
|
||||||
gas += params.CallValueTransferGas
|
gas += params.CallValueTransferGas
|
||||||
}
|
}
|
||||||
memoryGas, err := memoryGasCost(mem, memorySize)
|
memoryGas, err := memoryGasCost(mem, memorySize)
|
||||||
|
|
@ -393,7 +394,7 @@ func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.Active(forks.TangerineWhistle), contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -413,13 +414,13 @@ func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memory
|
||||||
gas uint64
|
gas uint64
|
||||||
overflow bool
|
overflow bool
|
||||||
)
|
)
|
||||||
if stack.Back(2).Sign() != 0 && !evm.chainRules.IsEIP4762 {
|
if stack.Back(2).Sign() != 0 && !evm.chainRules.Active(forks.Verkle) {
|
||||||
gas += params.CallValueTransferGas
|
gas += params.CallValueTransferGas
|
||||||
}
|
}
|
||||||
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.Active(forks.TangerineWhistle), contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -434,7 +435,7 @@ func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.Active(forks.TangerineWhistle), contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -450,7 +451,7 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
|
evm.callGasTemp, err = callGas(evm.chainRules.Active(forks.TangerineWhistle), contract.Gas, gas, stack.Back(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
@ -464,11 +465,11 @@ func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memo
|
||||||
func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
// EIP150 homestead gas reprice fork:
|
// EIP150 homestead gas reprice fork:
|
||||||
if evm.chainRules.IsEIP150 {
|
if evm.chainRules.Active(forks.TangerineWhistle) {
|
||||||
gas = params.SelfdestructGasEIP150
|
gas = params.SelfdestructGasEIP150
|
||||||
var address = common.Address(stack.Back(0).Bytes20())
|
var address = common.Address(stack.Back(0).Bytes20())
|
||||||
|
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.Active(forks.SpuriousDragon) {
|
||||||
// if empty and transfers value
|
// if empty and transfers value
|
||||||
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
||||||
gas += params.CreateBySelfdestructGas
|
gas += params.CreateBySelfdestructGas
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ func TestEIP2200(t *testing.T) {
|
||||||
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
|
||||||
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int) {},
|
||||||
}
|
}
|
||||||
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
|
evm := NewEVM(vmctx, statedb, presets.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}})
|
||||||
|
|
||||||
_, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int))
|
_, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int))
|
||||||
if !errors.Is(err, tt.failure) {
|
if !errors.Is(err, tt.failure) {
|
||||||
|
|
@ -151,7 +151,7 @@ func TestCreateGas(t *testing.T) {
|
||||||
config.ExtraEips = []int{3860}
|
config.ExtraEips = []int{3860}
|
||||||
}
|
}
|
||||||
|
|
||||||
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config)
|
evm := NewEVM(vmctx, statedb, presets.AllEthashProtocolChanges, config)
|
||||||
var startGas = uint64(testGas)
|
var startGas = uint64(testGas)
|
||||||
ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
|
ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -663,7 +664,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
input = scope.Memory.GetCopy(offset.Uint64(), size.Uint64())
|
||||||
gas = scope.Contract.Gas
|
gas = scope.Contract.Gas
|
||||||
)
|
)
|
||||||
if interpreter.evm.chainRules.IsEIP150 {
|
if interpreter.evm.chainRules.Active(forks.TangerineWhistle) {
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,7 +678,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
|
if interpreter.evm.chainRules.Active(forks.Homestead) && suberr == ErrCodeStoreOutOfGas {
|
||||||
stackvalue.Clear()
|
stackvalue.Clear()
|
||||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
stackvalue.Clear()
|
stackvalue.Clear()
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ func init() {
|
||||||
|
|
||||||
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
|
func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -194,7 +194,7 @@ func TestSAR(t *testing.T) {
|
||||||
|
|
||||||
func TestAddMod(t *testing.T) {
|
func TestAddMod(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -237,7 +237,7 @@ func TestWriteExpectedValues(t *testing.T) {
|
||||||
// getResult is a convenience function to generate the expected values
|
// getResult is a convenience function to generate the expected values
|
||||||
getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
getResult := func(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -281,7 +281,7 @@ func TestJsonTestcases(t *testing.T) {
|
||||||
|
|
||||||
func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
scope = &ScopeContext{nil, stack, nil}
|
scope = &ScopeContext{nil, stack, nil}
|
||||||
)
|
)
|
||||||
|
|
@ -519,7 +519,7 @@ func BenchmarkOpIsZero(b *testing.B) {
|
||||||
|
|
||||||
func TestOpMstore(t *testing.T) {
|
func TestOpMstore(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
)
|
)
|
||||||
|
|
@ -542,7 +542,7 @@ func TestOpMstore(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkOpMstore(bench *testing.B) {
|
func BenchmarkOpMstore(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
)
|
)
|
||||||
|
|
@ -562,7 +562,7 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
func TestOpTstore(t *testing.T) {
|
func TestOpTstore(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
evm = NewEVM(BlockContext{}, statedb, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, statedb, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
caller = common.Address{}
|
caller = common.Address{}
|
||||||
|
|
@ -601,7 +601,7 @@ func TestOpTstore(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkOpKeccak256(bench *testing.B) {
|
func BenchmarkOpKeccak256(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
)
|
)
|
||||||
|
|
@ -703,7 +703,7 @@ func TestRandom(t *testing.T) {
|
||||||
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
|
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
|
||||||
} {
|
} {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{Random: &tt.random}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{Random: &tt.random}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -743,7 +743,7 @@ func TestBlobHash(t *testing.T) {
|
||||||
{name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil},
|
{name: "out-of-bounds (nil)", idx: 25, expect: zero, hashes: nil},
|
||||||
} {
|
} {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -846,7 +846,7 @@ func TestOpMCopy(t *testing.T) {
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
var (
|
var (
|
||||||
evm = NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm = NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
|
@ -974,7 +974,7 @@ func TestPush(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpCLZ(t *testing.T) {
|
func TestOpCLZ(t *testing.T) {
|
||||||
evm := NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
evm := NewEVM(BlockContext{}, nil, presets.TestChainConfig, Config{})
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
inputHex string
|
inputHex string
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -106,34 +107,34 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
|
||||||
// If jump table was not initialised we set the default one.
|
// If jump table was not initialised we set the default one.
|
||||||
var table *JumpTable
|
var table *JumpTable
|
||||||
switch {
|
switch {
|
||||||
case evm.chainRules.IsOsaka:
|
case evm.chainRules.Active(forks.Osaka):
|
||||||
table = &osakaInstructionSet
|
table = &osakaInstructionSet
|
||||||
case evm.chainRules.IsVerkle:
|
case evm.chainRules.Active(forks.Verkle):
|
||||||
// TODO replace with proper instruction set when fork is specified
|
// TODO replace with proper instruction set when fork is specified
|
||||||
table = &verkleInstructionSet
|
table = &verkleInstructionSet
|
||||||
case evm.chainRules.IsPrague:
|
case evm.chainRules.Active(forks.Prague):
|
||||||
table = &pragueInstructionSet
|
table = &pragueInstructionSet
|
||||||
case evm.chainRules.IsCancun:
|
case evm.chainRules.Active(forks.Cancun):
|
||||||
table = &cancunInstructionSet
|
table = &cancunInstructionSet
|
||||||
case evm.chainRules.IsShanghai:
|
case evm.chainRules.Active(forks.Shanghai):
|
||||||
table = &shanghaiInstructionSet
|
table = &shanghaiInstructionSet
|
||||||
case evm.chainRules.IsMerge:
|
case evm.chainRules.Active(forks.Paris):
|
||||||
table = &mergeInstructionSet
|
table = &mergeInstructionSet
|
||||||
case evm.chainRules.IsLondon:
|
case evm.chainRules.Active(forks.London):
|
||||||
table = &londonInstructionSet
|
table = &londonInstructionSet
|
||||||
case evm.chainRules.IsBerlin:
|
case evm.chainRules.Active(forks.Berlin):
|
||||||
table = &berlinInstructionSet
|
table = &berlinInstructionSet
|
||||||
case evm.chainRules.IsIstanbul:
|
case evm.chainRules.Active(forks.Istanbul):
|
||||||
table = &istanbulInstructionSet
|
table = &istanbulInstructionSet
|
||||||
case evm.chainRules.IsConstantinople:
|
case evm.chainRules.Active(forks.Constantinople):
|
||||||
table = &constantinopleInstructionSet
|
table = &constantinopleInstructionSet
|
||||||
case evm.chainRules.IsByzantium:
|
case evm.chainRules.Active(forks.Byzantium):
|
||||||
table = &byzantiumInstructionSet
|
table = &byzantiumInstructionSet
|
||||||
case evm.chainRules.IsEIP158:
|
case evm.chainRules.Active(forks.SpuriousDragon):
|
||||||
table = &spuriousDragonInstructionSet
|
table = &spuriousDragonInstructionSet
|
||||||
case evm.chainRules.IsEIP150:
|
case evm.chainRules.Active(forks.TangerineWhistle):
|
||||||
table = &tangerineWhistleInstructionSet
|
table = &tangerineWhistleInstructionSet
|
||||||
case evm.chainRules.IsHomestead:
|
case evm.chainRules.Active(forks.Homestead):
|
||||||
table = &homesteadInstructionSet
|
table = &homesteadInstructionSet
|
||||||
default:
|
default:
|
||||||
table = &frontierInstructionSet
|
table = &frontierInstructionSet
|
||||||
|
|
@ -237,7 +238,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||||
}
|
}
|
||||||
|
|
||||||
if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall {
|
if in.evm.chainRules.Active(forks.Verkle) && !contract.IsDeployment && !contract.IsSystemCall {
|
||||||
// if the PC ends up in a new "chunk" of verkleized code, charge the
|
// if the PC ends up in a new "chunk" of verkleized code, charge the
|
||||||
// associated costs.
|
// associated costs.
|
||||||
contractAddr := contract.Address()
|
contractAddr := contract.Address()
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ func TestLoopInterrupt(t *testing.T) {
|
||||||
statedb.SetCode(address, common.Hex2Bytes(tt))
|
statedb.SetCode(address, common.Hex2Bytes(tt))
|
||||||
statedb.Finalise(true)
|
statedb.Finalise(true)
|
||||||
|
|
||||||
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{})
|
evm := NewEVM(vmctx, statedb, presets.AllEthashProtocolChanges, Config{})
|
||||||
|
|
||||||
errChannel := make(chan error)
|
errChannel := make(chan error)
|
||||||
timeout := make(chan bool)
|
timeout := make(chan bool)
|
||||||
|
|
@ -79,7 +80,7 @@ func TestLoopInterrupt(t *testing.T) {
|
||||||
func BenchmarkInterpreter(b *testing.B) {
|
func BenchmarkInterpreter(b *testing.B) {
|
||||||
var (
|
var (
|
||||||
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
|
||||||
evm = NewEVM(BlockContext{BlockNumber: big.NewInt(1), Time: 1, Random: &common.Hash{}}, statedb, params.MergedTestChainConfig, Config{})
|
evm = NewEVM(BlockContext{BlockNumber: big.NewInt(1), Time: 1, Random: &common.Hash{}}, statedb, presets.MergedTestChainConfig, Config{})
|
||||||
startGas uint64 = 100_000_000
|
startGas uint64 = 100_000_000
|
||||||
value = uint256.NewInt(0)
|
value = uint256.NewInt(0)
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
|
||||||
73
params/chainparam.go
Normal file
73
params/chainparam.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChainID
|
||||||
|
var ChainID = Define(T[*big.Int]{
|
||||||
|
Name: "chainId",
|
||||||
|
Optional: false,
|
||||||
|
Validate: validateChainID,
|
||||||
|
})
|
||||||
|
|
||||||
|
func validateChainID(v *big.Int, cfg *Config2) error {
|
||||||
|
if v.Sign() <= 0 {
|
||||||
|
return fmt.Errorf("invalid chainID value %v", v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DAOForkSupport is the chain parameter that configures the DAO fork.
|
||||||
|
// true=supports or false=opposes the fork.
|
||||||
|
// The default value is true.
|
||||||
|
var DAOForkSupport = Define(T[bool]{
|
||||||
|
Name: "daoForkSupport",
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// TerminalTotalDifficulty (TTD) is the total difficulty value where
|
||||||
|
var TerminalTotalDifficulty = Define(T[*big.Int]{
|
||||||
|
Name: "terminalTotalDifficulty",
|
||||||
|
Optional: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// DepositContractAddress configures the location of the deposit contract.
|
||||||
|
var DepositContractAddress = Define(T[common.Address]{
|
||||||
|
Name: "depositContractAddress",
|
||||||
|
Optional: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// This configures the EIP-4844 parameters across forks.
|
||||||
|
// There must be an entry for each fork
|
||||||
|
var BlobSchedule = Define(T[map[forks.Fork]BlobConfig]{
|
||||||
|
Name: "blobSchedule",
|
||||||
|
Optional: true,
|
||||||
|
Validate: validateBlobSchedule,
|
||||||
|
})
|
||||||
|
|
||||||
|
// validateBlobSchedule verifies that all forks after cancun explicitly define a blob
|
||||||
|
// schedule configuration.
|
||||||
|
func validateBlobSchedule(schedule map[forks.Fork]BlobConfig, cfg *Config2) error {
|
||||||
|
for f := range forks.All() {
|
||||||
|
if _, defined := schedule[f]; f.BlockBased() && defined {
|
||||||
|
return fmt.Errorf("contains fork %q with block-number based scheduling", f.ConfigName())
|
||||||
|
}
|
||||||
|
if cfg.Scheduled(f) && f.After(forks.Cancun) {
|
||||||
|
bcfg, defined := schedule[f]
|
||||||
|
if !defined {
|
||||||
|
return fmt.Errorf("missing entry for fork %q", f.ConfigName())
|
||||||
|
} else {
|
||||||
|
if err := bcfg.validate(); err != nil {
|
||||||
|
return fmt.Errorf("invalid blob config for fork %q: %v", f.ConfigName(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
424
params/config2.go
Normal file
424
params/config2.go
Normal file
|
|
@ -0,0 +1,424 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"cmp"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Activations contains the block numbers/timestamps where hard forks activate.
|
||||||
|
type Activations map[forks.Fork]uint64
|
||||||
|
|
||||||
|
// Config2 represents the chain configuration.
|
||||||
|
type Config2 struct {
|
||||||
|
activation Activations
|
||||||
|
param map[int]any
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig2(activations Activations, param ...ParamValue) *Config2 {
|
||||||
|
cfg := &Config2{
|
||||||
|
activation: maps.Clone(activations),
|
||||||
|
param: make(map[int]any, len(param)),
|
||||||
|
}
|
||||||
|
for _, pv := range param {
|
||||||
|
cfg.param[pv.id] = pv.value
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active reports whether the given fork is active for a block number/time.
|
||||||
|
func (cfg *Config2) Active(f forks.Fork, block, timestamp uint64) bool {
|
||||||
|
if f == forks.Frontier {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
activation, ok := cfg.activation[f]
|
||||||
|
if f.BlockBased() {
|
||||||
|
return ok && block >= activation
|
||||||
|
}
|
||||||
|
return ok && timestamp >= activation
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActiveAtBlock reports whether the given fork is active for a block number/time.
|
||||||
|
func (cfg *Config2) ActiveAtBlock(f forks.Fork, block *big.Int) bool {
|
||||||
|
if f == forks.Frontier {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !f.BlockBased() {
|
||||||
|
panic(fmt.Sprintf("fork %v has time-based scheduling", f))
|
||||||
|
}
|
||||||
|
activation, ok := cfg.activation[f]
|
||||||
|
return ok && block.Uint64() >= activation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activation returns the activation block/number of a fork.
|
||||||
|
func (cfg *Config2) Activation(f forks.Fork) (uint64, bool) {
|
||||||
|
a, ok := cfg.activation[f]
|
||||||
|
return a, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheduled says whether the fork is scheduled at all.
|
||||||
|
func (cfg *Config2) Scheduled(f forks.Fork) bool {
|
||||||
|
_, ok := cfg.activation[f]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetActivations returns a new configuration with the given forks activated.
|
||||||
|
func (cfg *Config2) SetActivations(forks Activations) *Config2 {
|
||||||
|
newA := maps.Clone(cfg.activation)
|
||||||
|
maps.Copy(newA, forks)
|
||||||
|
return &Config2{activation: newA, param: cfg.param}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetParam returns a new configuration with the given parameter values set.
|
||||||
|
func (cfg *Config2) SetParam(param ...ParamValue) *Config2 {
|
||||||
|
cpy := &Config2{activation: cfg.activation, param: maps.Clone(cfg.param)}
|
||||||
|
for _, pv := range param {
|
||||||
|
cpy.param[pv.id] = pv.value
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
// String encodes the config in a readable way.
|
||||||
|
func (cfg *Config2) String() string {
|
||||||
|
paramList := slices.Sorted(maps.Keys(cfg.param))
|
||||||
|
forkList := make([]forkActivation, 0, len(cfg.activation))
|
||||||
|
for f, a := range cfg.activation {
|
||||||
|
forkList = append(forkList, forkActivation{f, a})
|
||||||
|
}
|
||||||
|
slices.SortFunc(forkList, forkActivation.compare)
|
||||||
|
|
||||||
|
var out strings.Builder
|
||||||
|
var sp bool
|
||||||
|
writeSp := func() {
|
||||||
|
if sp {
|
||||||
|
out.WriteString(" ")
|
||||||
|
}
|
||||||
|
sp = true
|
||||||
|
}
|
||||||
|
out.WriteRune('[')
|
||||||
|
for _, fa := range forkList {
|
||||||
|
writeSp()
|
||||||
|
out.WriteString(fa.fork.ConfigName())
|
||||||
|
out.WriteString(":")
|
||||||
|
out.WriteString(strconv.FormatUint(fa.activation, 10))
|
||||||
|
}
|
||||||
|
for _, p := range paramList {
|
||||||
|
writeSp()
|
||||||
|
out.WriteString(paramRegistry[p].name)
|
||||||
|
out.WriteString(":")
|
||||||
|
fmt.Fprintf(&out, "%v", cfg.param[p])
|
||||||
|
}
|
||||||
|
out.WriteRune(']')
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the config as JSON.
|
||||||
|
func (cfg *Config2) MarshalJSON() ([]byte, error) {
|
||||||
|
m := make(map[string]any)
|
||||||
|
// params
|
||||||
|
for id, value := range cfg.param {
|
||||||
|
info, ok := paramRegistry[id]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("unknown chain parameter id %v", id))
|
||||||
|
}
|
||||||
|
m[info.name] = value
|
||||||
|
}
|
||||||
|
// forks
|
||||||
|
for f, act := range cfg.activation {
|
||||||
|
var name string
|
||||||
|
if f.BlockBased() {
|
||||||
|
name = fmt.Sprintf("%sBlock", f.ConfigName())
|
||||||
|
} else {
|
||||||
|
name = fmt.Sprintf("%sTime", f.ConfigName())
|
||||||
|
}
|
||||||
|
m[name] = act
|
||||||
|
}
|
||||||
|
return json.Marshal(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes the config as JSON.
|
||||||
|
func (cfg *Config2) UnmarshalJSON(input []byte) error {
|
||||||
|
dec := json.NewDecoder(bytes.NewReader(input))
|
||||||
|
tok, err := dec.Token()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if tok != json.Delim('{') {
|
||||||
|
return fmt.Errorf("expected JSON object for chain configuration")
|
||||||
|
}
|
||||||
|
// Now we're in the object.
|
||||||
|
newcfg := Config2{
|
||||||
|
activation: make(Activations),
|
||||||
|
param: make(map[int]any),
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
tok, err = dec.Token()
|
||||||
|
if tok == json.Delim('}') {
|
||||||
|
break
|
||||||
|
} else if key, ok := tok.(string); ok {
|
||||||
|
if strings.HasSuffix(key, "Block") || strings.HasSuffix(key, "Time") {
|
||||||
|
err = newcfg.decodeActivation(key, dec)
|
||||||
|
} else {
|
||||||
|
err = newcfg.decodeParameter(key, dec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*cfg = newcfg
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config2) decodeActivation(key string, dec *json.Decoder) error {
|
||||||
|
var num uint64
|
||||||
|
if err := dec.Decode(&num); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var f forks.Fork
|
||||||
|
name, ok := strings.CutSuffix(key, "Block")
|
||||||
|
if ok {
|
||||||
|
f, ok = forks.ForkByConfigName(name)
|
||||||
|
if !ok || !f.BlockBased() {
|
||||||
|
return fmt.Errorf("unknown block-based fork %q", name)
|
||||||
|
}
|
||||||
|
if f == forks.Frontier {
|
||||||
|
return fmt.Errorf("frontier fork cannot be scheduled")
|
||||||
|
}
|
||||||
|
} else if name, ok = strings.CutSuffix(key, "Time"); ok {
|
||||||
|
f, ok = forks.ForkByConfigName(name)
|
||||||
|
if !ok || f.BlockBased() {
|
||||||
|
return fmt.Errorf("unknown time-based fork %q", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg.activation[f] = num
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config2) decodeParameter(key string, dec *json.Decoder) error {
|
||||||
|
id, ok := paramRegistryByName[key]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unknown chain parameter %q", key)
|
||||||
|
}
|
||||||
|
v := paramRegistry[id].new()
|
||||||
|
if err := dec.Decode(v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.param[id] = reflect.ValueOf(v).Elem().Interface()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate checks the configuration to ensure forks are scheduled in order,
|
||||||
|
// and required settings are present.
|
||||||
|
func (cfg *Config2) Validate() error {
|
||||||
|
for f := range forks.All() {
|
||||||
|
act := "timestamp"
|
||||||
|
if f.BlockBased() {
|
||||||
|
act = "block"
|
||||||
|
}
|
||||||
|
|
||||||
|
for dep := range f.DirectDependencies() {
|
||||||
|
if dep == forks.Frontier {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
// Non-optional forks must all be present in the chain config up to the last defined fork.
|
||||||
|
case !cfg.Scheduled(dep) && cfg.Scheduled(f):
|
||||||
|
return fmt.Errorf("unsupported fork ordering: %v not enabled, but %v enabled at %s %v", dep, f, act, cfg.activation[f])
|
||||||
|
|
||||||
|
// Fork (whether defined by block or timestamp) must follow the fork definition sequence.
|
||||||
|
case cfg.Scheduled(dep) && cfg.Scheduled(f):
|
||||||
|
// Timestamp based forks can follow block based ones, but not the other way around.
|
||||||
|
if !dep.BlockBased() && f.BlockBased() {
|
||||||
|
return fmt.Errorf("unsupported fork ordering: %v used timestamp ordering, but %v reverted to block ordering", dep, f)
|
||||||
|
}
|
||||||
|
if dep.BlockBased() == f.BlockBased() && cfg.activation[dep] > cfg.activation[f] {
|
||||||
|
return fmt.Errorf("unsupported fork ordering: %v enabled at %s %v, but %v enabled at %s %v", dep, act, cfg.activation[dep], f, act, cfg.activation[f])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check parameters.
|
||||||
|
for id, info := range paramRegistry {
|
||||||
|
v, isSet := cfg.param[id]
|
||||||
|
if !isSet {
|
||||||
|
if !info.optional {
|
||||||
|
return fmt.Errorf("required chain parameter %q is not set", info.name)
|
||||||
|
}
|
||||||
|
v = info.defaultValue
|
||||||
|
}
|
||||||
|
if err := info.validate(v, cfg); err != nil {
|
||||||
|
return fmt.Errorf("invalid %s: %w", info.name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCompatible validates chain configuration changes.
|
||||||
|
// This called before applying changes to the 'stored configuration', the config
|
||||||
|
// which is held in the database. The given block number and time represent the current head
|
||||||
|
// of the chain in that database.
|
||||||
|
//
|
||||||
|
// An error is returned when the new configuration attempts to schedule a fork below the
|
||||||
|
// current chain head. The error contains enough information to rewind the chain to a
|
||||||
|
// point where the new config can be applied safely.
|
||||||
|
func (cfg *Config2) CheckCompatible(newcfg *Config2, blocknum uint64, time uint64) *ConfigCompatError {
|
||||||
|
// Gather forks which are active in either config, and sort them by activation.
|
||||||
|
var forkList []forkActivation
|
||||||
|
for f := range forks.All() {
|
||||||
|
a, ok := minActivation(f, cfg, newcfg)
|
||||||
|
if ok {
|
||||||
|
forkList = append(forkList, forkActivation{f, a})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slices.SortFunc(forkList, forkActivation.compare)
|
||||||
|
|
||||||
|
// Iterate checkCompatible to find the lowest conflict.
|
||||||
|
var lasterr *ConfigCompatError
|
||||||
|
bhead, btime := blocknum, time
|
||||||
|
for {
|
||||||
|
err := cfg.checkCompatible(newcfg, forkList, bhead, btime)
|
||||||
|
if err == nil || (lasterr != nil && err.RewindToBlock == lasterr.RewindToBlock && err.RewindToTime == lasterr.RewindToTime) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
lasterr = err
|
||||||
|
|
||||||
|
if err.RewindToTime > 0 {
|
||||||
|
btime = err.RewindToTime
|
||||||
|
} else {
|
||||||
|
bhead = err.RewindToBlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lasterr
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkCompatible checks config compatibility at a specific block height.
|
||||||
|
func (cfg *Config2) checkCompatible(newcfg *Config2, forkList []forkActivation, num uint64, time uint64) *ConfigCompatError {
|
||||||
|
incompatible := func(f forks.Fork) bool {
|
||||||
|
return (cfg.Active(f, num, time) || newcfg.Active(f, num, time)) && !activationEqual(f, cfg, newcfg)
|
||||||
|
}
|
||||||
|
for _, fa := range forkList {
|
||||||
|
f := fa.fork
|
||||||
|
if incompatible(f) {
|
||||||
|
if f.BlockBased() {
|
||||||
|
return newBlockCompatError2(f.ConfigName()+"Block", f, cfg, newcfg)
|
||||||
|
}
|
||||||
|
return newTimestampCompatError2(f.ConfigName()+"Time", f, cfg, newcfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Specialty checks.
|
||||||
|
if cfg.Active(forks.DAO, num, time) && DAOForkSupport.Get(cfg) != DAOForkSupport.Get(newcfg) {
|
||||||
|
return newBlockCompatError2("DAO fork support flag", forks.DAO, cfg, newcfg)
|
||||||
|
}
|
||||||
|
if cfg.Active(forks.TangerineWhistle, num, time) && !configBlockEqual(ChainID.Get(cfg), ChainID.Get(newcfg)) {
|
||||||
|
return newBlockCompatError2("EIP158 chain ID", forks.TangerineWhistle, cfg, newcfg)
|
||||||
|
}
|
||||||
|
// TODO: Something should be checked here for TTD and blobSchedule.
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBlockCompatError2(what string, f forks.Fork, storedcfg, newcfg *Config2) *ConfigCompatError {
|
||||||
|
err := &ConfigCompatError{What: what}
|
||||||
|
if storedcfg.Scheduled(f) {
|
||||||
|
err.StoredBlock = new(big.Int).SetUint64(storedcfg.activation[f])
|
||||||
|
}
|
||||||
|
if newcfg.Scheduled(f) {
|
||||||
|
err.NewBlock = new(big.Int).SetUint64(newcfg.activation[f])
|
||||||
|
}
|
||||||
|
// Need to rewind to one block before the earliest possible activation.
|
||||||
|
rew, _ := minActivation(f, storedcfg, newcfg)
|
||||||
|
if rew > 0 {
|
||||||
|
err.RewindToBlock = rew - 1
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTimestampCompatError2(what string, f forks.Fork, storedcfg, newcfg *Config2) *ConfigCompatError {
|
||||||
|
err := &ConfigCompatError{What: what}
|
||||||
|
if storedcfg.Scheduled(f) {
|
||||||
|
t := storedcfg.activation[f]
|
||||||
|
err.StoredTime = &t
|
||||||
|
}
|
||||||
|
if newcfg.Scheduled(f) {
|
||||||
|
t := newcfg.activation[f]
|
||||||
|
err.NewTime = &t
|
||||||
|
}
|
||||||
|
// Need to rewind to before the earliest possible activation.
|
||||||
|
rew, _ := minActivation(f, storedcfg, newcfg)
|
||||||
|
if rew > 0 {
|
||||||
|
err.RewindToTime = rew - 1
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// minActivation the earliest possible activation block/time for the given fork
|
||||||
|
// across two configurations.
|
||||||
|
func minActivation(f forks.Fork, cfg1, cfg2 *Config2) (act uint64, scheduled bool) {
|
||||||
|
switch {
|
||||||
|
case !cfg1.Scheduled(f):
|
||||||
|
act, scheduled = cfg2.activation[f]
|
||||||
|
case !cfg2.Scheduled(f):
|
||||||
|
act, scheduled = cfg1.activation[f]
|
||||||
|
default:
|
||||||
|
act = min(cfg1.activation[f], cfg2.activation[f])
|
||||||
|
scheduled = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// activationEqual checks whether a fork has the same activation two configurations.
|
||||||
|
// Note this also returns true when it isn't scheduled at all.
|
||||||
|
func activationEqual(f forks.Fork, cfg1, cfg2 *Config2) bool {
|
||||||
|
return cfg1.Scheduled(f) == cfg2.Scheduled(f) && cfg1.activation[f] == cfg2.activation[f]
|
||||||
|
}
|
||||||
|
|
||||||
|
type forkActivation struct {
|
||||||
|
fork forks.Fork
|
||||||
|
activation uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fa forkActivation) compare(other forkActivation) int {
|
||||||
|
// Here we assume block-based forks activate before time-based ones. For forks with
|
||||||
|
// equal activation, the ordering is based on fork name to ensure a consistent result.
|
||||||
|
switch {
|
||||||
|
case fa.fork.BlockBased() && !other.fork.BlockBased():
|
||||||
|
return -1
|
||||||
|
case !fa.fork.BlockBased() && other.fork.BlockBased():
|
||||||
|
return 1
|
||||||
|
case fa.activation == other.activation:
|
||||||
|
return strings.Compare(fa.fork.String(), other.fork.String())
|
||||||
|
default:
|
||||||
|
return cmp.Compare(fa.activation, other.activation)
|
||||||
|
}
|
||||||
|
}
|
||||||
169
params/config2_test.go
Normal file
169
params/config2_test.go
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package params_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
"github.com/ethereum/go-ethereum/params/presets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConfigValidateErrors(t *testing.T) {
|
||||||
|
files, err := filepath.Glob("testdata/invalid-*.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
Config params.Config2 `json:"config"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range files {
|
||||||
|
name := filepath.Base(f)
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
var test test
|
||||||
|
if err := common.LoadJSON(f, &test); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err := test.Config.Validate()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected validation error, got none")
|
||||||
|
}
|
||||||
|
if err.Error() != test.Error {
|
||||||
|
t.Fatal("wrong error:\n got:", err.Error(), "want:", test.Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckCompatible2(t *testing.T) {
|
||||||
|
type test struct {
|
||||||
|
stored, new *params.Config2
|
||||||
|
headBlock uint64
|
||||||
|
headTimestamp uint64
|
||||||
|
wantErr *params.ConfigCompatError
|
||||||
|
}
|
||||||
|
tests := []test{
|
||||||
|
{stored: presets.AllEthashProtocolChanges, new: presets.AllEthashProtocolChanges, headBlock: 0, headTimestamp: 0, wantErr: nil},
|
||||||
|
{stored: presets.AllEthashProtocolChanges, new: presets.AllEthashProtocolChanges, headBlock: 0, headTimestamp: uint64(time.Now().Unix()), wantErr: nil},
|
||||||
|
{stored: presets.AllEthashProtocolChanges, new: presets.AllEthashProtocolChanges, headBlock: 100, wantErr: nil},
|
||||||
|
{
|
||||||
|
// Here we check that it's OK to reschedule a time-based fork that's still in the future.
|
||||||
|
stored: params.NewConfig2(params.Activations{forks.SpuriousDragon: 10}),
|
||||||
|
new: params.NewConfig2(params.Activations{forks.SpuriousDragon: 20}),
|
||||||
|
headBlock: 9,
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stored: presets.AllEthashProtocolChanges,
|
||||||
|
new: params.NewConfig2(params.Activations{}),
|
||||||
|
headBlock: 3,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "arrowGlacierBlock",
|
||||||
|
StoredBlock: big.NewInt(0),
|
||||||
|
NewBlock: nil,
|
||||||
|
RewindToBlock: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stored: presets.AllEthashProtocolChanges,
|
||||||
|
new: params.NewConfig2(params.Activations{forks.ArrowGlacier: 1}),
|
||||||
|
headBlock: 3,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "arrowGlacierBlock",
|
||||||
|
StoredBlock: big.NewInt(0),
|
||||||
|
NewBlock: big.NewInt(1),
|
||||||
|
RewindToBlock: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stored: params.NewConfig2(params.Activations{
|
||||||
|
forks.Homestead: 30,
|
||||||
|
forks.TangerineWhistle: 10,
|
||||||
|
}),
|
||||||
|
new: params.NewConfig2(params.Activations{
|
||||||
|
forks.Homestead: 25,
|
||||||
|
forks.TangerineWhistle: 20,
|
||||||
|
}),
|
||||||
|
headBlock: 25,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "eip150Block",
|
||||||
|
StoredBlock: big.NewInt(10),
|
||||||
|
NewBlock: big.NewInt(20),
|
||||||
|
RewindToBlock: 9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Special case for Petersburg, which activates with Constantinople if undefined.
|
||||||
|
stored: params.NewConfig2(params.Activations{forks.Constantinople: 30}),
|
||||||
|
new: params.NewConfig2(params.Activations{forks.Constantinople: 30, forks.Petersburg: 30}),
|
||||||
|
headBlock: 40,
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If Petersburg and Constantinople are scheduled to different blocks, the compatibility check is stricter.
|
||||||
|
stored: params.NewConfig2(params.Activations{forks.Constantinople: 30}),
|
||||||
|
new: params.NewConfig2(params.Activations{forks.Constantinople: 30, forks.Petersburg: 31}),
|
||||||
|
headBlock: 40,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "petersburgBlock",
|
||||||
|
StoredBlock: nil,
|
||||||
|
NewBlock: big.NewInt(31),
|
||||||
|
RewindToBlock: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// This one checks that it's OK to reschedule a time-based fork that's still in the future.
|
||||||
|
stored: params.NewConfig2(params.Activations{forks.Shanghai: 10}),
|
||||||
|
new: params.NewConfig2(params.Activations{forks.Shanghai: 20}),
|
||||||
|
headTimestamp: 9,
|
||||||
|
wantErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Here's an error for the config from the previous test, the chain has passed the
|
||||||
|
// fork in the stored configuration, so it cannot be rescheduled.
|
||||||
|
stored: params.NewConfig2(params.Activations{forks.Shanghai: 10}),
|
||||||
|
new: params.NewConfig2(params.Activations{forks.Shanghai: 20}),
|
||||||
|
headTimestamp: 25,
|
||||||
|
wantErr: ¶ms.ConfigCompatError{
|
||||||
|
What: "shanghaiTime",
|
||||||
|
StoredTime: newUint64(10),
|
||||||
|
NewTime: newUint64(20),
|
||||||
|
RewindToTime: 9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
err := test.stored.CheckCompatible(test.new, test.headBlock, test.headTimestamp)
|
||||||
|
if !reflect.DeepEqual(err, test.wantErr) {
|
||||||
|
t.Errorf("error mismatch:\nstored: %v\nnew: %v\nheadBlock: %v\nheadTimestamp: %v\nerr: %v\nwant: %v", test.stored, test.new, test.headBlock, test.headTimestamp, err, test.wantErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newUint64(i uint64) *uint64 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,7 +27,7 @@ var DAOForkBlockExtra = common.FromHex("0x64616f2d686172642d666f726b")
|
||||||
|
|
||||||
// DAOForkExtraRange is the number of consecutive blocks from the DAO fork point
|
// DAOForkExtraRange is the number of consecutive blocks from the DAO fork point
|
||||||
// to override the extra-data in to prevent no-fork attacks.
|
// to override the extra-data in to prevent no-fork attacks.
|
||||||
var DAOForkExtraRange = big.NewInt(10)
|
var DAOForkExtraRange = uint64(10)
|
||||||
|
|
||||||
// DAORefundContract is the address of the refund contract to send DAO balances to.
|
// DAORefundContract is the address of the refund contract to send DAO balances to.
|
||||||
var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754")
|
var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d20bca754")
|
||||||
|
|
|
||||||
201
params/forks/forkreg.go
Normal file
201
params/forks/forkreg.go
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package forks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"iter"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fork identifies a specific network upgrade (hard fork).
|
||||||
|
type Fork struct {
|
||||||
|
*forkProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockBased reports whether the fork is scheduled by block number.
|
||||||
|
// If false, it is assumed to be scheduled based on block timestamp.
|
||||||
|
func (d Fork) BlockBased() bool {
|
||||||
|
return d.blockBased
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the fork name.
|
||||||
|
func (d Fork) String() string {
|
||||||
|
return d.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigName returns the fork config name.
|
||||||
|
func (d Fork) ConfigName() string {
|
||||||
|
return d.configName
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectDependencies iterates the fork's direct dependencies.
|
||||||
|
func (f Fork) DirectDependencies() iter.Seq[Fork] {
|
||||||
|
return slices.Values(f.directDeps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requires says whether a fork (transitively) depends on the fork given as parameter.
|
||||||
|
func (f Fork) Requires(other Fork) bool {
|
||||||
|
_, ok := f.deps[other]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f Fork) After(other Fork) bool {
|
||||||
|
return f == other || f.Requires(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText parses a fork name. Note this uses the config name.
|
||||||
|
func (f *Fork) UnmarshalText(v []byte) error {
|
||||||
|
df, ok := ForkByConfigName(string(v))
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unknown fork %q", v)
|
||||||
|
}
|
||||||
|
*f = df
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the fork config name.
|
||||||
|
func (f *Fork) MarshalText() ([]byte, error) {
|
||||||
|
return []byte(f.configName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DependencyOrder computes an ordering of the given forks, according to their dependencies.
|
||||||
|
// Note the resulting ordering may not be unique!
|
||||||
|
func DependencyOrder(list []Fork) []Fork {
|
||||||
|
var (
|
||||||
|
inList = make(map[Fork]bool, len(list))
|
||||||
|
visiting = make(map[Fork]bool, len(list))
|
||||||
|
mark = make(map[Fork]bool, len(list))
|
||||||
|
result = make([]Fork, 0, len(list))
|
||||||
|
)
|
||||||
|
for _, f := range list {
|
||||||
|
inList[f] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var visit func(Fork)
|
||||||
|
visit = func(f Fork) {
|
||||||
|
if mark[f] {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if visiting[f] {
|
||||||
|
// This can't happen because we check for cycles at definition time.
|
||||||
|
panic("fork dependency cycle")
|
||||||
|
}
|
||||||
|
visiting[f] = true
|
||||||
|
for _, dep := range f.directDeps {
|
||||||
|
visit(dep)
|
||||||
|
}
|
||||||
|
mark[f] = true
|
||||||
|
if inList[f] {
|
||||||
|
result = append(result, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, l := range list {
|
||||||
|
visit(l)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
type forkProperties struct {
|
||||||
|
name string
|
||||||
|
configName string
|
||||||
|
blockBased bool
|
||||||
|
directDeps []Fork
|
||||||
|
deps map[Fork]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spec is the definition of a fork.
|
||||||
|
type Spec struct {
|
||||||
|
Name string // the canonical name
|
||||||
|
ConfigName string // the name used in genesis.json
|
||||||
|
BlockBased bool // whether scheduling is based on block number (false == scheduled by timestamp)
|
||||||
|
Requires []Fork // list of forks that must activate at or before this one
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
registry = map[Fork]struct{}{}
|
||||||
|
registryByName = map[string]Fork{}
|
||||||
|
registryByConfigName = map[string]Fork{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Define creates a fork definition in the registry.
|
||||||
|
// This is meant to be called at package initialization time.
|
||||||
|
func Define(ft Spec) Fork {
|
||||||
|
if ft.Name == "" {
|
||||||
|
panic("blank fork name")
|
||||||
|
}
|
||||||
|
if _, ok := registryByName[ft.Name]; ok {
|
||||||
|
panic(fmt.Sprintf("fork %q already defined", ft.Name))
|
||||||
|
}
|
||||||
|
cname := ft.ConfigName
|
||||||
|
if cname == "" {
|
||||||
|
cname = strings.ToLower(ft.Name[:1]) + ft.Name[1:]
|
||||||
|
}
|
||||||
|
if _, ok := registryByConfigName[cname]; ok {
|
||||||
|
panic(fmt.Sprintf("fork config name %q already defined", cname))
|
||||||
|
}
|
||||||
|
|
||||||
|
f := Fork{
|
||||||
|
forkProperties: &forkProperties{
|
||||||
|
name: ft.Name,
|
||||||
|
configName: cname,
|
||||||
|
blockBased: ft.BlockBased,
|
||||||
|
directDeps: slices.Clone(ft.Requires),
|
||||||
|
deps: make(map[Fork]struct{}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the dependency set.
|
||||||
|
for _, dep := range ft.Requires {
|
||||||
|
if dep == f {
|
||||||
|
panic("fork depends on itself")
|
||||||
|
}
|
||||||
|
if dep.Requires(f) {
|
||||||
|
panic(fmt.Sprintf("fork dependency cycle: %v requires %v", dep, f))
|
||||||
|
}
|
||||||
|
maps.Copy(f.deps, dep.deps)
|
||||||
|
f.deps[dep] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to registry.
|
||||||
|
registry[f] = struct{}{}
|
||||||
|
registryByName[f.name] = f
|
||||||
|
registryByConfigName[cname] = f
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// All iterates over defined forks in order of their names.
|
||||||
|
func All() iter.Seq[Fork] {
|
||||||
|
sorted := slices.SortedFunc(maps.Keys(registry), func(f1, f2 Fork) int {
|
||||||
|
return strings.Compare(f1.name, f2.name)
|
||||||
|
})
|
||||||
|
return slices.Values(sorted)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForkByName returns a fork by its canonical name.
|
||||||
|
func ForkByName(name string) (Fork, bool) {
|
||||||
|
f, ok := registryByName[name]
|
||||||
|
return f, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForkByConfigName returns a fork by its configuration name.
|
||||||
|
func ForkByConfigName(name string) (Fork, bool) {
|
||||||
|
f, ok := registryByConfigName[name]
|
||||||
|
return f, ok
|
||||||
|
}
|
||||||
77
params/forks/forkreg_test.go
Normal file
77
params/forks/forkreg_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package forks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestForkDepends(t *testing.T) {
|
||||||
|
assert.True(t, Cancun.Requires(London))
|
||||||
|
assert.True(t, Cancun.Requires(Frontier))
|
||||||
|
assert.False(t, London.Requires(Cancun))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForkName(t *testing.T) {
|
||||||
|
assert.Equal(t, "Cancun", Cancun.String())
|
||||||
|
assert.Equal(t, "cancun", Cancun.ConfigName())
|
||||||
|
|
||||||
|
f, ok := ForkByName("Cancun")
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("cancun fork not found by name")
|
||||||
|
}
|
||||||
|
if f != Cancun {
|
||||||
|
t.Fatal("wrong fork found by name cancun")
|
||||||
|
}
|
||||||
|
|
||||||
|
f, ok = ForkByConfigName("cancun")
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("cancun fork not found by name")
|
||||||
|
}
|
||||||
|
if f != Cancun {
|
||||||
|
t.Fatal("wrong fork found by name cancun")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForkDependencyOrder(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
list, result []Fork
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
list: []Fork{},
|
||||||
|
result: []Fork{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
list: []Fork{BPO2, Homestead, Cancun, London, Paris},
|
||||||
|
result: []Fork{Homestead, London, Paris, Cancun, BPO2},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
list: []Fork{BPO3, Osaka, Cancun, Prague, BPO1, BPO2},
|
||||||
|
result: []Fork{Cancun, Prague, Osaka, BPO1, BPO2, BPO3},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
res := DependencyOrder(test.list)
|
||||||
|
if !slices.Equal(res, test.result) {
|
||||||
|
t.Errorf("DependencyOrder(%v) -> %v\n want: %v", test.list, res, test.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2023 The go-ethereum Authors
|
// Copyright 2025 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -16,60 +16,155 @@
|
||||||
|
|
||||||
package forks
|
package forks
|
||||||
|
|
||||||
// Fork is a numerical identifier of specific network upgrades (forks).
|
// Ethereum mainnet forks.
|
||||||
type Fork int
|
var (
|
||||||
|
Frontier = Define(Spec{
|
||||||
|
Name: "Frontier",
|
||||||
|
BlockBased: true,
|
||||||
|
})
|
||||||
|
|
||||||
const (
|
Homestead = Define(Spec{
|
||||||
Frontier Fork = iota
|
Name: "Homestead",
|
||||||
FrontierThawing
|
BlockBased: true,
|
||||||
Homestead
|
Requires: []Fork{Frontier},
|
||||||
DAO
|
})
|
||||||
TangerineWhistle // a.k.a. the EIP150 fork
|
|
||||||
SpuriousDragon // a.k.a. the EIP155 fork
|
DAO = Define(Spec{
|
||||||
Byzantium
|
Name: "DAO",
|
||||||
Constantinople
|
ConfigName: "daoFork",
|
||||||
Petersburg
|
BlockBased: true,
|
||||||
Istanbul
|
Requires: []Fork{Homestead},
|
||||||
MuirGlacier
|
})
|
||||||
Berlin
|
|
||||||
London
|
TangerineWhistle = Define(Spec{
|
||||||
ArrowGlacier
|
Name: "TangerineWhistle",
|
||||||
GrayGlacier
|
ConfigName: "eip150",
|
||||||
Paris
|
BlockBased: true,
|
||||||
Shanghai
|
Requires: []Fork{Homestead},
|
||||||
Cancun
|
})
|
||||||
Prague
|
|
||||||
Osaka
|
SpuriousDragon = Define(Spec{
|
||||||
|
Name: "SpuriousDragon",
|
||||||
|
ConfigName: "eip155",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{TangerineWhistle},
|
||||||
|
})
|
||||||
|
|
||||||
|
Byzantium = Define(Spec{
|
||||||
|
Name: "Byzantium",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{SpuriousDragon},
|
||||||
|
})
|
||||||
|
|
||||||
|
Constantinople = Define(Spec{
|
||||||
|
Name: "Constantinople",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Byzantium},
|
||||||
|
})
|
||||||
|
|
||||||
|
Petersburg = Define(Spec{
|
||||||
|
Name: "Petersburg",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Constantinople},
|
||||||
|
})
|
||||||
|
|
||||||
|
Istanbul = Define(Spec{
|
||||||
|
Name: "Istanbul",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Petersburg},
|
||||||
|
})
|
||||||
|
|
||||||
|
MuirGlacier = Define(Spec{
|
||||||
|
Name: "MuirGlacier",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Istanbul},
|
||||||
|
})
|
||||||
|
|
||||||
|
Berlin = Define(Spec{
|
||||||
|
Name: "Berlin",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Istanbul},
|
||||||
|
})
|
||||||
|
|
||||||
|
London = Define(Spec{
|
||||||
|
Name: "London",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{Berlin},
|
||||||
|
})
|
||||||
|
|
||||||
|
ArrowGlacier = Define(Spec{
|
||||||
|
Name: "ArrowGlacier",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{London, MuirGlacier},
|
||||||
|
})
|
||||||
|
|
||||||
|
GrayGlacier = Define(Spec{
|
||||||
|
Name: "GrayGlacier",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{London, ArrowGlacier},
|
||||||
|
})
|
||||||
|
|
||||||
|
Paris = Define(Spec{
|
||||||
|
Name: "Paris",
|
||||||
|
ConfigName: "mergeNetsplit",
|
||||||
|
BlockBased: true,
|
||||||
|
Requires: []Fork{London},
|
||||||
|
})
|
||||||
|
|
||||||
|
Shanghai = Define(Spec{
|
||||||
|
Name: "Shanghai",
|
||||||
|
Requires: []Fork{Paris},
|
||||||
|
})
|
||||||
|
|
||||||
|
Cancun = Define(Spec{
|
||||||
|
Name: "Cancun",
|
||||||
|
Requires: []Fork{Shanghai},
|
||||||
|
})
|
||||||
|
|
||||||
|
Prague = Define(Spec{
|
||||||
|
Name: "Prague",
|
||||||
|
Requires: []Fork{Cancun},
|
||||||
|
})
|
||||||
|
|
||||||
|
Osaka = Define(Spec{
|
||||||
|
Name: "Osaka",
|
||||||
|
Requires: []Fork{Prague},
|
||||||
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// String implements fmt.Stringer.
|
// Verkle forks.
|
||||||
func (f Fork) String() string {
|
var (
|
||||||
s, ok := forkToString[f]
|
Verkle = Define(Spec{
|
||||||
if !ok {
|
Name: "Verkle",
|
||||||
return "Unknown fork"
|
Requires: []Fork{Prague},
|
||||||
}
|
})
|
||||||
return s
|
)
|
||||||
}
|
|
||||||
|
|
||||||
var forkToString = map[Fork]string{
|
// BPOs - 'blob parameter only' forks.
|
||||||
Frontier: "Frontier",
|
var (
|
||||||
FrontierThawing: "Frontier Thawing",
|
BPO1 = Define(Spec{
|
||||||
Homestead: "Homestead",
|
Name: "BPO1",
|
||||||
DAO: "DAO",
|
ConfigName: "bpo1",
|
||||||
TangerineWhistle: "Tangerine Whistle",
|
Requires: []Fork{Osaka},
|
||||||
SpuriousDragon: "Spurious Dragon",
|
})
|
||||||
Byzantium: "Byzantium",
|
BPO2 = Define(Spec{
|
||||||
Constantinople: "Constantinople",
|
Name: "BPO2",
|
||||||
Petersburg: "Petersburg",
|
ConfigName: "bpo2",
|
||||||
Istanbul: "Istanbul",
|
Requires: []Fork{BPO1},
|
||||||
MuirGlacier: "Muir Glacier",
|
})
|
||||||
Berlin: "Berlin",
|
BPO3 = Define(Spec{
|
||||||
London: "London",
|
Name: "BPO3",
|
||||||
ArrowGlacier: "Arrow Glacier",
|
ConfigName: "bpo3",
|
||||||
GrayGlacier: "Gray Glacier",
|
Requires: []Fork{BPO2},
|
||||||
Paris: "Paris",
|
})
|
||||||
Shanghai: "Shanghai",
|
BPO4 = Define(Spec{
|
||||||
Cancun: "Cancun",
|
Name: "BPO4",
|
||||||
Prague: "Prague",
|
ConfigName: "bpo4",
|
||||||
Osaka: "Osaka",
|
Requires: []Fork{BPO3},
|
||||||
}
|
})
|
||||||
|
BPO5 = Define(Spec{
|
||||||
|
Name: "BPO5",
|
||||||
|
ConfigName: "bpo5",
|
||||||
|
Requires: []Fork{BPO4},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
|
||||||
162
params/presets/presets.go
Normal file
162
params/presets/presets.go
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package presets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mainnetTD, _ = new(big.Int).SetString("58_750_000_000_000_000_000_000", 0)
|
||||||
|
|
||||||
|
var Mainnet = params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.Homestead: 1_150_000,
|
||||||
|
forks.DAO: 1_920_000,
|
||||||
|
forks.TangerineWhistle: 2_463_000,
|
||||||
|
forks.SpuriousDragon: 2_675_000,
|
||||||
|
forks.Byzantium: 4_370_000,
|
||||||
|
forks.Constantinople: 7_280_000,
|
||||||
|
forks.Petersburg: 7_280_000,
|
||||||
|
forks.Istanbul: 9_069_000,
|
||||||
|
forks.MuirGlacier: 9_200_000,
|
||||||
|
forks.Berlin: 12_244_000,
|
||||||
|
forks.London: 12_965_000,
|
||||||
|
forks.ArrowGlacier: 13_773_000,
|
||||||
|
forks.GrayGlacier: 15_050_000,
|
||||||
|
forks.Paris: 15_537_393,
|
||||||
|
// time-based forks
|
||||||
|
forks.Shanghai: 1681338455,
|
||||||
|
forks.Cancun: 1710338135,
|
||||||
|
forks.Prague: 1746612311,
|
||||||
|
},
|
||||||
|
params.ChainID.V(big.NewInt(1)),
|
||||||
|
params.TerminalTotalDifficulty.V(mainnetTD),
|
||||||
|
params.DepositContractAddress.V(common.HexToAddress("0x00000000219ab540356cbb839cbe05303d7705fa")),
|
||||||
|
params.DAOForkSupport.V(true),
|
||||||
|
params.BlobSchedule.V(map[forks.Fork]params.BlobConfig{
|
||||||
|
forks.Cancun: *params.DefaultCancunBlobConfig,
|
||||||
|
forks.Prague: *params.DefaultPragueBlobConfig,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
var sepoliaTD, _ = new(big.Int).SetString("17_000_000_000_000_000", 0)
|
||||||
|
|
||||||
|
// SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network.
|
||||||
|
var Sepolia = params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.Homestead: 0,
|
||||||
|
forks.TangerineWhistle: 0,
|
||||||
|
forks.SpuriousDragon: 0,
|
||||||
|
forks.Byzantium: 0,
|
||||||
|
forks.Constantinople: 0,
|
||||||
|
forks.Petersburg: 0,
|
||||||
|
forks.Istanbul: 0,
|
||||||
|
forks.MuirGlacier: 0,
|
||||||
|
forks.Berlin: 0,
|
||||||
|
forks.London: 0,
|
||||||
|
forks.Paris: 1735371,
|
||||||
|
// time-based forks
|
||||||
|
forks.Shanghai: 1677557088,
|
||||||
|
forks.Cancun: 1706655072,
|
||||||
|
forks.Prague: 1741159776,
|
||||||
|
},
|
||||||
|
params.ChainID.V(big.NewInt(11155111)),
|
||||||
|
params.TerminalTotalDifficulty.V(sepoliaTD),
|
||||||
|
params.DepositContractAddress.V(common.HexToAddress("0x7f02c3e3c98b133055b8b348b2ac625669ed295d")),
|
||||||
|
params.BlobSchedule.V(map[forks.Fork]params.BlobConfig{
|
||||||
|
forks.Cancun: *params.DefaultCancunBlobConfig,
|
||||||
|
forks.Prague: *params.DefaultPragueBlobConfig,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
// AllEthashProtocolChanges2 contains every protocol change (EIPs) introduced
|
||||||
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
|
var AllEthashProtocolChanges = params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.Homestead: 0,
|
||||||
|
forks.TangerineWhistle: 0,
|
||||||
|
forks.SpuriousDragon: 0,
|
||||||
|
forks.Byzantium: 0,
|
||||||
|
forks.Constantinople: 0,
|
||||||
|
forks.Petersburg: 0,
|
||||||
|
forks.Istanbul: 0,
|
||||||
|
forks.MuirGlacier: 0,
|
||||||
|
forks.Berlin: 0,
|
||||||
|
forks.London: 0,
|
||||||
|
forks.ArrowGlacier: 0,
|
||||||
|
forks.GrayGlacier: 0,
|
||||||
|
},
|
||||||
|
params.ChainID.V(big.NewInt(1337)),
|
||||||
|
params.TerminalTotalDifficulty.V(big.NewInt(math.MaxInt64)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestChainConfig contains every protocol change (EIPs) introduced
|
||||||
|
// and accepted by the Ethereum core developers for testing purposes.
|
||||||
|
var TestChainConfig = params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.Homestead: 0,
|
||||||
|
forks.TangerineWhistle: 0,
|
||||||
|
forks.SpuriousDragon: 0,
|
||||||
|
forks.Byzantium: 0,
|
||||||
|
forks.Constantinople: 0,
|
||||||
|
forks.Petersburg: 0,
|
||||||
|
forks.Istanbul: 0,
|
||||||
|
forks.MuirGlacier: 0,
|
||||||
|
forks.Berlin: 0,
|
||||||
|
forks.London: 0,
|
||||||
|
forks.ArrowGlacier: 0,
|
||||||
|
forks.GrayGlacier: 0,
|
||||||
|
},
|
||||||
|
params.ChainID.V(big.NewInt(1)),
|
||||||
|
params.TerminalTotalDifficulty.V(big.NewInt(math.MaxInt64)),
|
||||||
|
)
|
||||||
|
|
||||||
|
// MergedTestChainConfig2 contains every protocol change (EIPs) introduced
|
||||||
|
// and accepted by the Ethereum core developers for testing purposes.
|
||||||
|
var MergedTestChainConfig = params.NewConfig2(
|
||||||
|
params.Activations{
|
||||||
|
forks.Homestead: 0,
|
||||||
|
forks.TangerineWhistle: 0,
|
||||||
|
forks.SpuriousDragon: 0,
|
||||||
|
forks.Byzantium: 0,
|
||||||
|
forks.Constantinople: 0,
|
||||||
|
forks.Petersburg: 0,
|
||||||
|
forks.Istanbul: 0,
|
||||||
|
forks.MuirGlacier: 0,
|
||||||
|
forks.Berlin: 0,
|
||||||
|
forks.London: 0,
|
||||||
|
forks.ArrowGlacier: 0,
|
||||||
|
forks.GrayGlacier: 0,
|
||||||
|
forks.Paris: 0,
|
||||||
|
forks.Shanghai: 0,
|
||||||
|
forks.Cancun: 0,
|
||||||
|
forks.Prague: 0,
|
||||||
|
forks.Osaka: 0,
|
||||||
|
},
|
||||||
|
params.ChainID.V(big.NewInt(1)),
|
||||||
|
params.TerminalTotalDifficulty.V(big.NewInt(0)),
|
||||||
|
params.BlobSchedule.V(map[forks.Fork]params.BlobConfig{
|
||||||
|
forks.Cancun: *params.DefaultCancunBlobConfig,
|
||||||
|
forks.Prague: *params.DefaultPragueBlobConfig,
|
||||||
|
forks.Osaka: *params.DefaultOsakaBlobConfig,
|
||||||
|
}),
|
||||||
|
)
|
||||||
12
params/presets/presets_test.go
Normal file
12
params/presets/presets_test.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package presets
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestPresetsValidate(t *testing.T) {
|
||||||
|
if err := Mainnet.Validate(); err != nil {
|
||||||
|
t.Fatal("mainnet is invalid:", err)
|
||||||
|
}
|
||||||
|
if err := Sepolia.Validate(); err != nil {
|
||||||
|
t.Fatal("sepolia is invalid:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
125
params/registry.go
Normal file
125
params/registry.go
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parameter represents a chain parameter.
|
||||||
|
// Parameters are globally registered using `Define`.
|
||||||
|
type Parameter[V any] struct {
|
||||||
|
info regInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves the value of a parameter from a config.
|
||||||
|
func (p Parameter[V]) Get(cfg *Config2) V {
|
||||||
|
if p.info.id == 0 {
|
||||||
|
panic("zero parameter")
|
||||||
|
}
|
||||||
|
v, ok := cfg.param[p.info.id]
|
||||||
|
if ok {
|
||||||
|
return v.(V)
|
||||||
|
}
|
||||||
|
return p.info.defaultValue.(V)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defined reports whether the parameter is set in the config.
|
||||||
|
func (p Parameter[V]) Defined(cfg *Config2) bool {
|
||||||
|
if p.info.id == 0 {
|
||||||
|
panic("zero parameter")
|
||||||
|
}
|
||||||
|
_, ok := cfg.param[p.info.id]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// V creates a ParamValue with the given value. You need this to
|
||||||
|
// specify parameter values when constructing a Config in code.
|
||||||
|
func (p Parameter[V]) V(v V) ParamValue {
|
||||||
|
if p.info.id == 0 {
|
||||||
|
panic("zero parameter")
|
||||||
|
}
|
||||||
|
return ParamValue{p.info.id, v}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamValue contains a chain parameter and its value.
|
||||||
|
// This is created by calling `V` on the parameter.
|
||||||
|
type ParamValue struct {
|
||||||
|
id int
|
||||||
|
value any
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
paramCounter = int(1)
|
||||||
|
paramRegistry = map[int]regInfo{}
|
||||||
|
paramRegistryByName = map[string]int{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// T is the definition of a chain parameter type.
|
||||||
|
type T[V any] struct {
|
||||||
|
Name string // the parameter name
|
||||||
|
Optional bool // optional says
|
||||||
|
Default V
|
||||||
|
Validate func(v V, cfg *Config2) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type regInfo struct {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
optional bool
|
||||||
|
defaultValue any
|
||||||
|
new func() any
|
||||||
|
validate func(any, *Config2) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define creates a chain parameter in the registry.
|
||||||
|
// This is meant to be called at package initialization time.
|
||||||
|
func Define[V any](def T[V]) Parameter[V] {
|
||||||
|
if def.Name == "" {
|
||||||
|
panic("blank parameter name")
|
||||||
|
}
|
||||||
|
if id, defined := paramRegistryByName[def.Name]; defined {
|
||||||
|
info := paramRegistry[id]
|
||||||
|
panic(fmt.Sprintf("chain parameter %q already registered with type %T", def.Name, info.defaultValue))
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(def.Name, "Block") || strings.HasSuffix(def.Name, "Time") {
|
||||||
|
panic("chain parameter name cannot end in 'Block' or 'Time'")
|
||||||
|
}
|
||||||
|
|
||||||
|
id := paramCounter
|
||||||
|
paramCounter++
|
||||||
|
|
||||||
|
regInfo := regInfo{
|
||||||
|
id: id,
|
||||||
|
name: def.Name,
|
||||||
|
optional: def.Optional,
|
||||||
|
defaultValue: def.Default,
|
||||||
|
new: func() any {
|
||||||
|
return new(V)
|
||||||
|
},
|
||||||
|
validate: func(v any, cfg *Config2) error {
|
||||||
|
if def.Validate == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return def.Validate(v.(V), cfg)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
paramRegistry[id] = regInfo
|
||||||
|
paramRegistryByName[def.Name] = id
|
||||||
|
return Parameter[V]{info: regInfo}
|
||||||
|
}
|
||||||
38
params/rules2.go
Normal file
38
params/rules2.go
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2025 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/params/forks"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rules captures the activations of forks at a particular block height.
|
||||||
|
type Rules2 struct {
|
||||||
|
active map[forks.Fork]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config2) Rules(blockNum uint64, blockTime uint64) Rules2 {
|
||||||
|
r := Rules2{
|
||||||
|
active: make(map[forks.Fork]bool, len(cfg.activation)),
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Active reports whether the given fork is active.
|
||||||
|
func (r *Rules2) Active(f forks.Fork) bool {
|
||||||
|
return r.active[f]
|
||||||
|
}
|
||||||
24
params/testdata/invalid-blobschedule-blockbased.json
vendored
Normal file
24
params/testdata/invalid-blobschedule-blockbased.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"mergeNetsplitBlock": 0,
|
||||||
|
"shanghaiTime": 900,
|
||||||
|
"chainId": 99,
|
||||||
|
"blobSchedule": {
|
||||||
|
"berlin": {
|
||||||
|
"target": 8,
|
||||||
|
"max": 5,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": "invalid blobSchedule: contains fork \"berlin\" with block-number based scheduling"
|
||||||
|
}
|
||||||
26
params/testdata/invalid-blobschedule-missing.json
vendored
Normal file
26
params/testdata/invalid-blobschedule-missing.json
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"mergeNetsplitBlock": 0,
|
||||||
|
"shanghaiTime": 900,
|
||||||
|
"cancunTime": 1000,
|
||||||
|
"pragueTime": 1100,
|
||||||
|
"chainId": 99,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 8,
|
||||||
|
"max": 5,
|
||||||
|
"baseFeeUpdateFraction": 3338477
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": "invalid blobSchedule: missing entry for fork \"prague\""
|
||||||
|
}
|
||||||
24
params/testdata/invalid-blobschedule-validation.json
vendored
Normal file
24
params/testdata/invalid-blobschedule-validation.json
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"mergeNetsplitBlock": 0,
|
||||||
|
"shanghaiTime": 900,
|
||||||
|
"cancunTime": 1000,
|
||||||
|
"chainId": 99,
|
||||||
|
"blobSchedule": {
|
||||||
|
"cancun": {
|
||||||
|
"target": 8,
|
||||||
|
"max": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": "invalid blobSchedule: invalid blob config for fork \"cancun\": update fraction must be defined and non-zero"
|
||||||
|
}
|
||||||
7
params/testdata/invalid-forkorder.json
vendored
Normal file
7
params/testdata/invalid-forkorder.json
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"homesteadBlock": 10,
|
||||||
|
"eip150Block": 8
|
||||||
|
},
|
||||||
|
"error": "unsupported fork ordering: Homestead enabled at block 10, but TangerineWhistle enabled at block 8"
|
||||||
|
}
|
||||||
8
params/testdata/invalid-missingChainID.json
vendored
Normal file
8
params/testdata/invalid-missingChainID.json
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"homesteadBlock": 7,
|
||||||
|
"eip150Block": 8,
|
||||||
|
"eip155Block": 9
|
||||||
|
},
|
||||||
|
"error": "required chain parameter \"chainId\" is not set"
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue