feat: feynman upgrade vm changes (#1193)

* add Feynman to chain spec

* remove input size limit from ecPairing

* restore original behavior for blockhash opcode

* eip-2935: manually cherry-pick upstream commit a223efc

* eip-7623: manually cherry-pick upstream commit 0e1a19d

* add note about L1 messages

* nit

* add history storage to dev genesis

* EIP-2935: adopt tracer changes from upstream a223efcf

* remove todos

* update protocol params

* add block hash to witness, plus various cleanups
This commit is contained in:
Péter Garamvölgyi 2025-06-11 14:34:40 +02:00 committed by GitHub
parent 00c5c2bd3e
commit 5148229082
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 393 additions and 48 deletions

View file

@ -152,6 +152,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
if chainConfig.CurieBlock != nil && chainConfig.CurieBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
misc.ApplyCurieHardFork(statedb)
}
// Apply EIP-2935
if pre.Env.BlockHashes != nil && chainConfig.IsFeynman(pre.Env.Timestamp) {
var (
prevNumber = pre.Env.Number - 1
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
)
core.ProcessParentBlockHash(prevHash, evm, statedb)
}
for i, tx := range txs {
msg, err := tx.AsMessage(signer, pre.Env.BaseFee)

View file

@ -140,18 +140,32 @@ func Transaction(ctx *cli.Context) error {
r.Address = sender
}
// Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int))); err != nil {
rules := chainConfig.Rules(common.Big0, 0)
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
if err != nil {
r.Error = err
results = append(results, r)
continue
} else {
}
r.IntrinsicGas = gas
if tx.Gas() < gas {
r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas)
results = append(results, r)
continue
}
// For Feynman txs, validate the floor data gas.
if rules.IsFeynman {
floorDataGas, err := core.FloorDataGas(tx.Data())
if err != nil {
r.Error = err
results = append(results, r)
continue
}
if tx.Gas() < floorDataGas {
r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrFloorDataGas, tx.Gas(), floorDataGas)
results = append(results, r)
continue
}
}
// Validate <256bit fields
switch {

View file

@ -81,6 +81,10 @@ var (
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")
// ErrFloorDataGas is returned if the transaction is specified to use less gas
// than required for the data floor cost.
ErrFloorDataGas = errors.New("insufficient gas for floor data gas cost")
// ErrTxTypeNotSupported is returned if a transaction is not supported in the
// current network configuration.
ErrTxTypeNotSupported = types.ErrTxTypeNotSupported

View file

@ -500,6 +500,8 @@ func DeveloperGenesisBlock(period uint64, gasLimit uint64, faucet common.Address
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
// Pre-deploy EIP-2935 history contract.
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0},
// LSH 250 due to finite field limitation
faucet: {Balance: new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 250), big.NewInt(9))},
},

View file

@ -167,6 +167,11 @@ func (s *StateDB) WithWitness(witness *stateless.Witness) {
s.witness = witness
}
// Witness returns the current witness for the state database.
func (s *StateDB) Witness() *stateless.Witness {
return s.witness
}
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot.

View file

@ -94,6 +94,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
blockContext := NewEVMBlockContext(header, p.bc, p.config, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg)
processorBlockTransactionGauge.Update(int64(block.Transactions().Len()))
// Apply EIP-2935
if p.config.IsFeynman(block.Time()) {
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number, header.Time), header.BaseFee)
@ -199,3 +203,30 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
}
// ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935.
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM, statedb *state.StateDB) {
msg := types.NewMessage(
params.SystemAddress, // from
&params.HistoryStorageAddress, // to
0, // nonce
common.Big0, // amount
30_000_000, // gasLimit
common.Big0, // gasPrice
common.Big0, // gasFeeCap
common.Big0, // gasTipCap
prevHash.Bytes(), // data
nil, // accessList
false, // isFake
nil, // setCodeAuthorizations
)
evm.Reset(NewEVMTxContext(msg), statedb)
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
_, _, err := evm.Call(vm.AccountRef(msg.From()), *msg.To(), msg.Data(), 30_000_000, common.Big0, nil)
if err != nil {
panic(err)
}
statedb.Finalise(true)
}

View file

@ -18,6 +18,7 @@ package core
import (
"crypto/ecdsa"
"encoding/binary"
"math/big"
"testing"
@ -31,9 +32,11 @@ import (
"github.com/scroll-tech/go-ethereum/consensus/ethash"
"github.com/scroll-tech/go-ethereum/consensus/misc"
"github.com/scroll-tech/go-ethereum/core/rawdb"
"github.com/scroll-tech/go-ethereum/core/state"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/core/vm"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/ethdb/memorydb"
"github.com/scroll-tech/go-ethereum/params"
"github.com/scroll-tech/go-ethereum/trie"
)
@ -64,6 +67,7 @@ func TestStateProcessorErrors(t *testing.T) {
DarwinV2Time: new(uint64),
EuclidTime: new(uint64),
EuclidV2Time: new(uint64),
FeynmanTime: new(uint64),
Ethash: new(params.EthashConfig),
}
signer = types.LatestSigner(config)
@ -387,9 +391,9 @@ func TestStateProcessorErrors(t *testing.T) {
}{
{ // ErrMaxInitCodeSizeExceeded
txs: []*types.Transaction{
mkDynamicCreationTx(0, 500000, common.Big0, misc.CalcBaseFee(config, genesis.Header(), parentL1BaseFee), tooBigInitCode[:]),
mkDynamicCreationTx(0, 520000, common.Big0, misc.CalcBaseFee(config, genesis.Header(), parentL1BaseFee), tooBigInitCode[:]),
},
want: "could not apply tx 0 [0x7b33776d375660694a23ef992c090265682f3687607e0099b14503fdb65d73e3]: max initcode size exceeded: code size 49153 limit 49152",
want: "could not apply tx 0 [0xe0d03426cecc04467410064cb4de02012fc069d2462282735d7dfcb9dea9f63b]: max initcode size exceeded: code size 49153 limit 49152",
},
{ // ErrIntrinsicGas: Not enough gas to cover init code
txs: []*types.Transaction{
@ -453,3 +457,68 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr
// Assemble and return the final block for sealing
return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil))
}
func TestProcessParentBlockHash(t *testing.T) {
var (
chainConfig = &params.ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ShanghaiBlock: big.NewInt(0),
BernoulliBlock: big.NewInt(0),
CurieBlock: big.NewInt(0),
DarwinTime: new(uint64),
DarwinV2Time: new(uint64),
EuclidTime: new(uint64),
EuclidV2Time: new(uint64),
FeynmanTime: new(uint64),
Ethash: new(params.EthashConfig),
}
hashA = common.Hash{0x01}
hashB = common.Hash{0x02}
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
coinbase = common.Address{}
)
test := func(statedb *state.StateDB) {
statedb.SetNonce(params.HistoryStorageAddress, 1)
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
statedb.IntermediateRoot(true)
vmContext := NewEVMBlockContext(header, nil, chainConfig, &coinbase)
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
ProcessParentBlockHash(header.ParentHash, evm, statedb)
vmContext = NewEVMBlockContext(parent, nil, chainConfig, &coinbase)
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
// make sure that the state is correct
if have := getParentBlockHash(statedb, 1); have != hashA {
t.Errorf("want parent hash %v, have %v", hashA, have)
}
if have := getParentBlockHash(statedb, 0); have != hashB {
t.Errorf("want parent hash %v, have %v", hashB, have)
}
}
t.Run("MPT", func(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
test(statedb)
})
}
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
ringIndex := number % params.HistoryServeWindow
var key common.Hash
binary.BigEndian.PutUint64(key[24:], ringIndex)
return statedb.GetState(params.HistoryStorageAddress, key)
}

View file

@ -17,6 +17,7 @@
package core
import (
"bytes"
"fmt"
"math"
"math/big"
@ -141,12 +142,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
// Bump the required gas by the amount of transactional data
if dataLen > 0 {
// Zero and non-zero bytes are priced differently
var nz uint64
for _, byt := range data {
if byt != 0 {
nz++
}
}
z := uint64(bytes.Count(data, []byte{0}))
nz := dataLen - z
// Make sure we don't exceed uint64 for all data combinations
nonZeroGas := params.TxDataNonZeroGasFrontier
if isEIP2028 {
@ -157,7 +155,6 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
}
gas += nz * nonZeroGas
z := dataLen - nz
if (math.MaxUint64-gas)/params.TxDataZeroGas < z {
return 0, ErrGasUintOverflow
}
@ -181,6 +178,21 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
return gas, nil
}
// FloorDataGas computes the minimum gas required for a transaction based on its data tokens (EIP-7623).
func FloorDataGas(data []byte) (uint64, error) {
var (
z = uint64(bytes.Count(data, []byte{0}))
nz = uint64(len(data)) - z
tokens = nz*params.TxTokenPerNonZeroByte + z
)
// Check for overflow
if (math.MaxUint64-params.TxGas)/params.TxCostFloorPerToken < tokens {
return 0, ErrGasUintOverflow
}
// Minimum gas required for a transaction based on its data tokens (EIP-7623).
return params.TxGas + tokens*params.TxCostFloorPerToken, nil
}
// toWordSize returns the ceiled word size required for init code payment calculation.
func toWordSize(size uint64) uint64 {
if size > math.MaxUint64-31 {
@ -380,16 +392,30 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
sender = vm.AccountRef(msg.From())
rules = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Time.Uint64())
contractCreation = msg.To() == nil
floorDataGas uint64
)
// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), st.msg.SetCodeAuthorizations(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
if err != nil {
// Note: The L1 message queue contract ensures that this cannot happen for L1 messages.
return nil, err
}
if st.gas < gas {
// Note: The L1 message queue contract ensures that this cannot happen for L1 messages.
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
}
// Gas limit suffices for the floor data cost (EIP-7623)
if rules.IsFeynman {
floorDataGas, err = FloorDataGas(st.data)
if err != nil {
return nil, err
}
if st.gas < floorDataGas {
// Note: The L1 message queue contract ensures that this cannot happen for L1 messages.
return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, st.gas, floorDataGas)
}
}
st.gas -= gas
// Check clause 6
@ -455,13 +481,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}, nil
}
if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2
st.refundGas(params.RefundQuotient)
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
st.refundGas(params.RefundQuotientEIP3529)
// Compute refund counter, capped to a refund quotient.
st.gas += st.calcRefund()
if rules.IsFeynman {
// After EIP-7623: Data-heavy transactions pay the floor gas.
if st.gasUsed() < floorDataGas {
st.gas = st.initialGas - floorDataGas
}
}
st.returnGas()
effectiveTip := st.gasPrice
// only burn the base fee if the fee vault is not enabled
@ -545,14 +574,25 @@ func (st *StateTransition) applyAuthorization(auth *types.SetCodeAuthorization)
return types.AuthorizationResult{Authority: authority, PreCode: preCode, Success: true}
}
func (st *StateTransition) refundGas(refundQuotient uint64) {
// Apply refund counter, capped to a refund quotient
refund := st.gasUsed() / refundQuotient
// calcRefund computes refund counter, capped to a refund quotient.
func (st *StateTransition) calcRefund() uint64 {
var refund uint64
if !st.evm.ChainConfig().IsLondon(st.evm.Context.BlockNumber) {
// Before EIP-3529: refunds were capped to gasUsed / 2
refund = st.gasUsed() / params.RefundQuotient
} else {
// After EIP-3529: refunds are capped to gasUsed / 5
refund = st.gasUsed() / params.RefundQuotientEIP3529
}
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
st.gas += refund
return refund
}
// returnGas returns ETH for remaining gas,
// exchanged at the original rate.
func (st *StateTransition) returnGas() {
// Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
st.state.AddBalance(st.msg.From(), remaining)

View file

@ -297,6 +297,7 @@ type TxPool struct {
eip1559 bool // Fork indicator whether we are using EIP-1559 type transactions.
shanghai bool // Fork indicator whether we are in the Shanghai stage.
eip7702 bool // Fork indicator whether we are using EIP-7702 type transactions.
feynman bool // Fork indicator whether we are in the Feynman stage.
currentState *state.StateDB // Current state in the blockchain head
currentHead *big.Int // Current blockchain head
@ -855,6 +856,16 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if tx.Gas() < intrGas {
return ErrIntrinsicGas
}
// Ensure the transaction can cover floor data gas.
if pool.feynman {
floorDataGas, err := FloorDataGas(tx.Data())
if err != nil {
return err
}
if tx.Gas() < floorDataGas {
return fmt.Errorf("%w: gas %v, minimum needed %v", ErrFloorDataGas, tx.Gas(), floorDataGas)
}
}
return nil
}
@ -1583,6 +1594,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
pool.eip1559 = pool.chainconfig.IsCurie(next)
pool.shanghai = pool.chainconfig.IsShanghai(next)
pool.eip7702 = pool.chainconfig.IsEuclidV2(newHead.Time)
pool.feynman = pool.chainconfig.IsFeynman(newHead.Time)
// Update current head
pool.currentHead = next

View file

@ -80,7 +80,7 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: false},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
common.BytesToAddress([]byte{9}): &blake2F{},
}
@ -94,7 +94,7 @@ var PrecompiledContractsBerlin = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
common.BytesToAddress([]byte{9}): &blake2F{},
}
@ -108,7 +108,7 @@ var PrecompiledContractsArchimedes = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
common.BytesToAddress([]byte{9}): &blake2FDisabled{},
}
@ -122,7 +122,7 @@ var PrecompiledContractsBernoulli = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
common.BytesToAddress([]byte{9}): &blake2FDisabled{},
}
@ -136,7 +136,22 @@ var PrecompiledContractsEuclidV2 = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: true},
common.BytesToAddress([]byte{9}): &blake2FDisabled{},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
}
// PrecompiledContractsFeynman contains the default set of pre-compiled Ethereum
// contracts used in the Feynman release.
var PrecompiledContractsFeynman = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hashDisabled{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{limitInputLength: false},
common.BytesToAddress([]byte{9}): &blake2FDisabled{},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
}
@ -156,6 +171,7 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
}
var (
PrecompiledAddressesFeynman []common.Address
PrecompiledAddressesEuclidV2 []common.Address
PrecompiledAddressesBernoulli []common.Address
PrecompiledAddressesArchimedes []common.Address
@ -187,11 +203,16 @@ func init() {
for k := range PrecompiledContractsEuclidV2 {
PrecompiledAddressesEuclidV2 = append(PrecompiledAddressesEuclidV2, k)
}
for k := range PrecompiledContractsFeynman {
PrecompiledAddressesFeynman = append(PrecompiledAddressesFeynman, k)
}
}
// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
switch {
case rules.IsFeynman:
return PrecompiledAddressesFeynman
case rules.IsEuclidV2:
return PrecompiledAddressesEuclidV2
case rules.IsBernoulli:
@ -600,10 +621,6 @@ var (
// runBn256Pairing implements the Bn256Pairing precompile, referenced by both
// Byzantium and Istanbul operations.
func runBn256Pairing(input []byte) ([]byte, error) {
// Allow at most 4 inputs
if len(input) > 4*192 {
return nil, errBadPairingInput
}
// Handle some corner cases cheaply
if len(input)%192 > 0 {
return nil, errBadPairingInput
@ -634,7 +651,9 @@ func runBn256Pairing(input []byte) ([]byte, error) {
// bn256PairingIstanbul implements a pairing pre-compile for the bn256 curve
// conforming to Istanbul consensus rules.
type bn256PairingIstanbul struct{}
type bn256PairingIstanbul struct {
limitInputLength bool
}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
@ -642,6 +661,13 @@ func (c *bn256PairingIstanbul) RequiredGas(input []byte) uint64 {
}
func (c *bn256PairingIstanbul) Run(input []byte) ([]byte, error) {
if c.limitInputLength {
// Allow at most 4 inputs
if len(input) > 4*192 {
return nil, errBadPairingInput
}
}
return runBn256Pairing(input)
}

View file

@ -65,6 +65,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{16}): &bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
common.BytesToAddress([]byte{0xf8}): &bn256PairingIstanbul{limitInputLength: true},
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
}
@ -264,7 +265,7 @@ func BenchmarkPrecompiledBn256ScalarMul(b *testing.B) { benchJson("bn256ScalarMu
// Tests the sample inputs from the elliptic curve pairing check EIP 197.
func TestPrecompiledBn256Pairing(t *testing.T) { testJson("bn256Pairing", "08", t) }
func TestPrecompiledBn256PairingFail(t *testing.T) { testJsonFail("bn256Pairing", "08", t) }
func TestPrecompiledBn256PairingFail(t *testing.T) { testJsonFail("bn256Pairing", "f8", t) }
func BenchmarkPrecompiledBn256Pairing(b *testing.B) { benchJson("bn256Pairing", "08", b) }
func TestPrecompiledBlake2F(t *testing.T) { testJson("blake2F", "09", t) }

View file

@ -47,6 +47,8 @@ type (
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsFeynman:
precompiles = PrecompiledContractsFeynman
case evm.chainRules.IsEuclidV2:
precompiles = PrecompiledContractsEuclidV2
case evm.chainRules.IsBernoulli:

View file

@ -470,6 +470,32 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
return nil, nil
}
func opBlockhashPostFeynman(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
num := scope.Stack.peek()
num64, overflow := num.Uint64WithOverflow()
if overflow {
num.Clear()
return nil, nil
}
var upper, lower uint64
upper = interpreter.evm.Context.BlockNumber.Uint64()
if upper < 257 {
lower = 0
} else {
lower = upper - 256
}
if num64 >= lower && num64 < upper {
res := interpreter.evm.Context.GetHash(num64)
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
witness.AddBlockHash(num64)
}
num.SetBytes(res[:])
} else {
num.Clear()
}
return nil, nil
}
func opCoinbase(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.FeeRecipient().Bytes()))
return nil, nil

View file

@ -20,6 +20,7 @@ import (
"math/big"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/core/stateless"
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/params"
)
@ -85,6 +86,8 @@ type StateDB interface {
AddPreimage(common.Hash, []byte)
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
Witness() *stateless.Witness
}
// CallContext provides a basic interface for the EVM calling conventions. The EVM

View file

@ -74,6 +74,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
case evm.chainRules.IsFeynman:
jt = feynmanInstructionSet
case evm.chainRules.IsEuclidV2:
jt = euclidV2InstructionSet
case evm.chainRules.IsDarwin:

View file

@ -62,11 +62,24 @@ var (
curieInstructionSet = newCurieInstructionSet()
darwinInstructionSet = newDarwinInstructionSet()
euclidV2InstructionSet = newEuclidV2InstructionSet()
feynmanInstructionSet = newFeynmanInstructionSet()
)
// JumpTable contains the EVM opcodes supported at a given fork.
type JumpTable [256]*operation
// newFeynmanInstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin, euclidV2,
// and feynman instructions.
func newFeynmanInstructionSet() JumpTable {
instructionSet := newEuclidV2InstructionSet()
// change block hash opcode implementation
instructionSet[BLOCKHASH].execute = opBlockhashPostFeynman
return instructionSet
}
// newEuclidV2InstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin and euclidV2 instructions.
func newEuclidV2InstructionSet() JumpTable {

View file

@ -74,6 +74,8 @@ func setDefaults(cfg *Config) {
CurieBlock: new(big.Int),
DarwinTime: new(uint64),
DarwinV2Time: new(uint64),
EuclidV2Time: new(uint64),
FeynmanTime: new(uint64),
}
}

View file

@ -337,17 +337,13 @@ func TestBlockhash(t *testing.T) {
if zero.BitLen() != 0 {
t.Fatalf("expected zeroes, got %x", ret[0:32])
}
firstExpectedHash := new(big.Int)
firstExpectedHash.SetString("13215081625009140218242111988507489764601005198286886925088730931502473149599", 10)
if first.Uint64() != firstExpectedHash.Uint64() {
t.Fatalf("first hash should be 13215081625009140218242111988507489764601005198286886925088730931502473149599, got %d (%x)", first, ret[32:64])
if first.Uint64() != 999 {
t.Fatalf("second block should be 999, got %d (%x)", first, ret[32:64])
}
lastExpectedHash := new(big.Int)
lastExpectedHash.SetString("2851160567348483005169712516804956111111231427377973738952179767509712807467", 10)
if last.Uint64() != lastExpectedHash.Uint64() {
t.Fatalf("last hash should be 2851160567348483005169712516804956111111231427377973738952179767509712807467, got %d (%x)", last, ret[64:96])
if last.Uint64() != 744 {
t.Fatalf("last block should be 744, got %d (%x)", last, ret[64:96])
}
if exp, got := 0, chain.counter; exp != got {
if exp, got := 255, chain.counter; exp != got {
t.Errorf("suboptimal; too much chain iteration, expected %d, got %d", exp, got)
}
}

View file

@ -76,6 +76,20 @@
"Gas": 113000,
"NoBenchmark": false
},
{
"Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "ten_point_match_1",
"Gas": 385000,
"NoBenchmark": false
},
{
"Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "ten_point_match_2",
"Gas": 385000,
"NoBenchmark": false
},
{
"Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",

View file

@ -176,6 +176,12 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
if err != nil {
return nil, vm.BlockContext{}, nil, err
}
// If feynman hardfork, insert parent block hash in the state as per EIP-2935.
if eth.blockchain.Config().IsFeynman(block.Time()) {
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, eth.blockchain.Config(), nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, nil
}

View file

@ -277,6 +277,11 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
for task := range tasks {
signer := types.MakeSigner(api.backend.ChainConfig(), task.block.Number(), task.block.Time())
blockCtx := core.NewEVMBlockContext(task.block.Header(), api.chainContext(localctx), api.backend.ChainConfig(), nil)
// EIP-2935: Insert parent hash in history contract.
if api.backend.ChainConfig().IsFeynman(task.block.Time()) {
evm := vm.NewEVM(blockCtx, vm.TxContext{}, task.statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessParentBlockHash(task.block.ParentHash(), evm, task.statedb)
}
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
@ -539,6 +544,11 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
)
// EIP-2935: Insert parent hash in history contract.
if api.backend.ChainConfig().IsFeynman(block.Time()) {
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
}
for i, tx := range block.Transactions() {
var (
msg, _ = tx.AsMessage(signer, block.BaseFee())
@ -614,6 +624,11 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
threads = len(txs)
}
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), api.backend.ChainConfig(), nil)
// EIP-2935: Insert parent hash in history contract.
if api.backend.ChainConfig().IsFeynman(block.Time()) {
evm := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
}
blockHash := block.Hash()
blockNumber := block.NumberU64()
for th := 0; th < threads; th++ {
@ -748,6 +763,13 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
canon = false
}
}
// EIP-2935: Insert parent hash in history contract.
if api.backend.ChainConfig().IsFeynman(block.Time()) {
evm := vm.NewEVM(vmctx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), evm, statedb)
}
for i, tx := range block.Transactions() {
// Prepare the trasaction for un-traced execution
var (

View file

@ -627,15 +627,25 @@ func (w *worker) tryCommitNewWork(now time.Time, parent common.Hash, reorging bo
// handleForks
func (w *worker) handleForks() (bool, error) {
// Apply Curie predeployed contract update
if w.chainConfig.CurieBlock != nil && w.chainConfig.CurieBlock.Cmp(w.current.header.Number) == 0 {
misc.ApplyCurieHardFork(w.current.state)
return true, nil
}
// Stop/start miner at Euclid fork boundary on zktrie/mpt nodes
if w.chainConfig.IsEuclid(w.current.header.Time) {
parent := w.chain.GetBlockByHash(w.current.header.ParentHash)
return parent != nil && !w.chainConfig.IsEuclid(parent.Time()), nil
}
// Apply EIP-2935
if w.chainConfig.IsFeynman(w.current.header.Time) {
context := core.NewEVMBlockContext(w.current.header, w.chain, w.chainConfig, nil)
vmenv := vm.NewEVM(context, vm.TxContext{}, w.current.state, w.chainConfig, vm.Config{})
core.ProcessParentBlockHash(w.current.header.ParentHash, vmenv, w.current.state)
}
return false, nil
}

View file

@ -1404,6 +1404,7 @@ func TestEuclidV2TransitionVerification(t *testing.T) {
chainConfig := params.AllCliqueProtocolChanges.Clone()
chainConfig.EuclidTime = newUint64(0)
chainConfig.EuclidV2Time = newUint64(10000)
chainConfig.FeynmanTime = nil
chainConfig.Clique = &params.CliqueConfig{Period: 1, Epoch: 30000}
chainConfig.SystemContract = &params.SystemContractConfig{Period: 1}

View file

@ -330,6 +330,7 @@ var (
DarwinV2Time: newUint64(1724832000),
EuclidTime: newUint64(1741680000),
EuclidV2Time: newUint64(1741852800),
FeynmanTime: nil,
Clique: &CliqueConfig{
Period: 3,
Epoch: 30000,
@ -381,6 +382,7 @@ var (
DarwinV2Time: newUint64(1725264000),
EuclidTime: newUint64(1744815600),
EuclidV2Time: newUint64(1745305200),
FeynmanTime: nil,
Clique: &CliqueConfig{
Period: 3,
Epoch: 30000,
@ -521,6 +523,7 @@ var (
DarwinV2Time: new(uint64),
EuclidTime: new(uint64),
EuclidV2Time: new(uint64),
FeynmanTime: new(uint64),
TerminalTotalDifficulty: nil,
Ethash: new(EthashConfig),
Clique: nil,
@ -662,6 +665,7 @@ type ChainConfig struct {
DarwinV2Time *uint64 `json:"darwinv2Time,omitempty"` // DarwinV2 switch time (nil = no fork, 0 = already on darwinv2)
EuclidTime *uint64 `json:"euclidTime,omitempty"` // Euclid switch time (nil = no fork, 0 = already on euclid)
EuclidV2Time *uint64 `json:"euclidv2Time,omitempty"` // EuclidV2 switch time (nil = no fork, 0 = already on euclidv2)
FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already on feynman)
// TerminalTotalDifficulty is the amount of total difficulty reached by
// the network that triggers the consensus upgrade.
@ -852,7 +856,11 @@ func (c *ChainConfig) String() string {
if c.EuclidV2Time != nil {
euclidV2Time = fmt.Sprintf("@%v", *c.EuclidV2Time)
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Archimedes: %v, Shanghai: %v, Bernoulli: %v, Curie: %v, Darwin: %v, DarwinV2: %v, Euclid: %v, EuclidV2: %v, Engine: %v, Scroll config: %v}",
feynmanTime := "<nil>"
if c.FeynmanTime != nil {
feynmanTime = fmt.Sprintf("@%v", *c.FeynmanTime)
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, Archimedes: %v, Shanghai: %v, Bernoulli: %v, Curie: %v, Darwin: %v, DarwinV2: %v, Euclid: %v, EuclidV2: %v, Feynman: %v, Engine: %v, Scroll config: %v}",
c.ChainID,
c.HomesteadBlock,
c.DAOForkBlock,
@ -876,6 +884,7 @@ func (c *ChainConfig) String() string {
darwinV2Time,
euclidTime,
euclidV2Time,
feynmanTime,
engine,
c.Scroll,
)
@ -988,6 +997,11 @@ func (c *ChainConfig) IsEuclidV2(now uint64) bool {
return isForkedTime(now, c.EuclidV2Time)
}
// IsFeynman returns whether time is either equal to the Feynman fork time or greater.
func (c *ChainConfig) IsFeynman(now uint64) bool {
return isForkedTime(now, c.FeynmanTime)
}
// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool {
if c.TerminalTotalDifficulty == nil {
@ -1201,6 +1215,7 @@ type Rules struct {
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon, IsArchimedes, IsShanghai bool
IsBernoulli, IsCurie, IsDarwin, IsEuclid, IsEuclidV2 bool
IsFeynman bool
}
// Rules ensures c's ChainID is not nil.
@ -1228,5 +1243,6 @@ func (c *ChainConfig) Rules(num *big.Int, time uint64) Rules {
IsDarwin: c.IsDarwin(time),
IsEuclid: c.IsEuclid(time),
IsEuclidV2: c.IsEuclidV2(time),
IsFeynman: c.IsFeynman(time),
}
}

View file

@ -16,7 +16,11 @@
package params
import "math/big"
import (
"math/big"
"github.com/scroll-tech/go-ethereum/common"
)
const (
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
@ -87,6 +91,8 @@ const (
TxDataNonZeroGasFrontier uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions.
TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul)
TxTokenPerNonZeroByte uint64 = 4 // Token cost per non-zero byte as specified by EIP-7623.
TxCostFloorPerToken uint64 = 10 // Cost floor per byte of data as specified by EIP-7623.
TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list
TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702
@ -168,14 +174,27 @@ const (
BlobTxBlobGaspriceUpdateFraction = 5007716 // Controls the maximum rate of change for blob gas price, using Prague parameters
BlobTxTargetBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing), using Prague parameters
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
)
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
var Bls12381MultiExpDiscountTable = [128]uint64{1200, 888, 764, 641, 594, 547, 500, 453, 438, 423, 408, 394, 379, 364, 349, 334, 330, 326, 322, 318, 314, 310, 306, 302, 298, 294, 289, 285, 281, 277, 273, 269, 268, 266, 265, 263, 262, 260, 259, 257, 256, 254, 253, 251, 250, 248, 247, 245, 244, 242, 241, 239, 238, 236, 235, 233, 232, 231, 229, 228, 226, 225, 223, 222, 221, 220, 219, 219, 218, 217, 216, 216, 215, 214, 213, 213, 212, 211, 211, 210, 209, 208, 208, 207, 206, 205, 205, 204, 203, 202, 202, 201, 200, 199, 199, 198, 197, 196, 196, 195, 194, 193, 193, 192, 191, 191, 190, 189, 188, 188, 187, 186, 185, 185, 184, 183, 182, 182, 181, 180, 179, 179, 178, 177, 176, 176, 175, 174}
// Difficulty parameters.
var (
DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations.
GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block.
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
)
// System contracts.
var (
// SystemAddress is where the system-transaction is sent from as per EIP-4788
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
// EIP-2935 - Serve historical block hashes from state
HistoryStorageAddress = common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935")
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500")
)

View file

@ -24,7 +24,7 @@ import (
const (
VersionMajor = 5 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release
VersionPatch = 53 // Patch version component of the current release
VersionPatch = 54 // Patch version component of the current release
VersionMeta = "mainnet" // Version metadata to append to the version string
)