mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-03 14:52:55 +00:00
all: add eip-7907 base without db table
Co-authored-by: lightclient <lightclient@proton.com> Co-authored-by: Qi Zhou <qizhou@ethstorage.io>
This commit is contained in:
parent
5ddd08720b
commit
32b2d3e51d
20 changed files with 406 additions and 14 deletions
|
|
@ -180,7 +180,7 @@ func Transaction(ctx *cli.Context) error {
|
||||||
r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits")
|
r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits")
|
||||||
}
|
}
|
||||||
// Check whether the init code size has been exceeded.
|
// Check whether the init code size has been exceeded.
|
||||||
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSizeEIP3860 {
|
||||||
r.Error = errors.New("max initcode size exceeded")
|
r.Error = errors.New("max initcode size exceeded")
|
||||||
}
|
}
|
||||||
if chainConfig.IsOsaka(new(big.Int), 0) && tx.Gas() > params.MaxTxGas {
|
if chainConfig.IsOsaka(new(big.Int), 0) && tx.Gas() > params.MaxTxGas {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb/pebble"
|
"github.com/ethereum/go-ethereum/ethdb/pebble"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -4407,3 +4408,76 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEIP7907(t *testing.T) {
|
||||||
|
glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||||
|
glogger.Verbosity(3)
|
||||||
|
log.SetDefault(log.NewLogger(glogger))
|
||||||
|
|
||||||
|
junk := make([]byte, 1024*250) // 250kb
|
||||||
|
for i := range junk {
|
||||||
|
junk[i] = byte(i)
|
||||||
|
}
|
||||||
|
code := program.New().Op(vm.ADDRESS).Op(vm.POP).ReturnViaCodeCopy(junk).Bytes()
|
||||||
|
var (
|
||||||
|
config = *params.MergedTestChainConfig
|
||||||
|
signer = types.LatestSigner(&config)
|
||||||
|
engine = beacon.New(ethash.NewFaker())
|
||||||
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||||
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
|
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||||
|
bb = common.HexToAddress("0x000000000000000000000000000000000000bbbb")
|
||||||
|
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||||
|
)
|
||||||
|
gspec := &Genesis{
|
||||||
|
Config: &config,
|
||||||
|
GasLimit: 70000000,
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
addr1: {Balance: funds},
|
||||||
|
addr2: {Balance: funds},
|
||||||
|
aa: { // The address 0xAAAA calls into addr2
|
||||||
|
Code: code,
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: big.NewInt(0),
|
||||||
|
},
|
||||||
|
bb: { // The address 0xBBBB copies and deploys the contract.
|
||||||
|
Code: program.New().ExtcodeCopy(aa, 0, 0, len(code)).Push0().Push(len(code)).Push0().Push0().Op(vm.CREATE).Op(vm.EXTCODESIZE).Bytes(),
|
||||||
|
Nonce: 0,
|
||||||
|
Balance: big.NewInt(0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
|
||||||
|
b.SetCoinbase(aa)
|
||||||
|
txdata := &types.DynamicFeeTx{
|
||||||
|
ChainID: gspec.Config.ChainID,
|
||||||
|
Nonce: 0,
|
||||||
|
To: &bb,
|
||||||
|
Gas: 70000000,
|
||||||
|
GasFeeCap: newGwei(5),
|
||||||
|
GasTipCap: big.NewInt(2),
|
||||||
|
}
|
||||||
|
tx := types.MustSignNewTx(key1, signer, txdata)
|
||||||
|
b.AddTx(tx)
|
||||||
|
})
|
||||||
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
defer chain.Stop()
|
||||||
|
if n, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify delegation designations were deployed.
|
||||||
|
created := crypto.CreateAddress(bb, 0)
|
||||||
|
fmt.Println(created.Hex())
|
||||||
|
state, _ := chain.State()
|
||||||
|
code, want := state.GetCode(created), junk
|
||||||
|
if !bytes.Equal(code, want) {
|
||||||
|
t.Fatalf("created code incorrect: got %d, want %d", len(code), len(want))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,16 @@ func ReadCodeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) []byte {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadCodeWithPrefix retrieves the contract code of the provided code hash.
|
||||||
|
// Return -1 if not found for legacy db.
|
||||||
|
func ReadCodeSizeWithPrefix(db ethdb.KeyValueReader, hash common.Hash) int {
|
||||||
|
data, _ := db.Get(codeSizeKey(hash))
|
||||||
|
if len(data) != 4 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int(binary.BigEndian.Uint32(data))
|
||||||
|
}
|
||||||
|
|
||||||
// HasCode checks if the contract code corresponding to the
|
// HasCode checks if the contract code corresponding to the
|
||||||
// provided code hash is present in the db.
|
// provided code hash is present in the db.
|
||||||
func HasCode(db ethdb.KeyValueReader, hash common.Hash) bool {
|
func HasCode(db ethdb.KeyValueReader, hash common.Hash) bool {
|
||||||
|
|
@ -90,12 +100,19 @@ func WriteCode(db ethdb.KeyValueWriter, hash common.Hash, code []byte) {
|
||||||
if err := db.Put(codeKey(hash), code); err != nil {
|
if err := db.Put(codeKey(hash), code); err != nil {
|
||||||
log.Crit("Failed to store contract code", "err", err)
|
log.Crit("Failed to store contract code", "err", err)
|
||||||
}
|
}
|
||||||
|
var sizeData [4]byte
|
||||||
|
binary.BigEndian.PutUint32(sizeData[:], uint32(len(code)))
|
||||||
|
if err := db.Put(codeSizeKey(hash), sizeData[:]); err != nil {
|
||||||
|
log.Crit("Failed to store contract code size", "err", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteCode deletes the specified contract code from the database.
|
// DeleteCode deletes the specified contract code from the database.
|
||||||
func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) {
|
func DeleteCode(db ethdb.KeyValueWriter, hash common.Hash) {
|
||||||
if err := db.Delete(codeKey(hash)); err != nil {
|
if err := db.Delete(codeKey(hash)); err != nil {
|
||||||
log.Crit("Failed to delete contract code", "err", err)
|
log.Crit("Failed to delete contract code", "err", err)
|
||||||
|
// Ignore error since the legacy db may not contain the size.
|
||||||
|
db.Delete(codeSizeKey(hash))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ var (
|
||||||
SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value
|
SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value
|
||||||
SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
|
SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
|
||||||
CodePrefix = []byte("c") // CodePrefix + code hash -> account code
|
CodePrefix = []byte("c") // CodePrefix + code hash -> account code
|
||||||
|
CodeSizePrefix = []byte("s") /// CodeSizePrefx + code hash -> code size
|
||||||
skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header
|
skeletonHeaderPrefix = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header
|
||||||
|
|
||||||
// Path-based storage scheme of merkle patricia trie.
|
// Path-based storage scheme of merkle patricia trie.
|
||||||
|
|
@ -233,6 +234,11 @@ func codeKey(hash common.Hash) []byte {
|
||||||
return append(CodePrefix, hash.Bytes()...)
|
return append(CodePrefix, hash.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codeSizeKey = CodeSizePrefix + hash
|
||||||
|
func codeSizeKey(hash common.Hash) []byte {
|
||||||
|
return append(CodeSizePrefix, hash.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
// IsCodeKey reports whether the given byte slice is the key of contract code,
|
// IsCodeKey reports whether the given byte slice is the key of contract code,
|
||||||
// if so return the raw code hash as well.
|
// if so return the raw code hash as well.
|
||||||
func IsCodeKey(key []byte) (bool, []byte) {
|
func IsCodeKey(key []byte) (bool, []byte) {
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type accessList struct {
|
type accessList struct {
|
||||||
addresses map[common.Address]int
|
addresses map[common.Address]int
|
||||||
slots []map[common.Hash]struct{}
|
slots []map[common.Hash]struct{}
|
||||||
|
addressCodes map[common.Address]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainsAddress returns true if the address is in the access list.
|
// ContainsAddress returns true if the address is in the access list.
|
||||||
|
|
@ -36,6 +37,12 @@ func (al *accessList) ContainsAddress(address common.Address) bool {
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainsAddress returns true if the address is in the access list.
|
||||||
|
func (al *accessList) ContainsAddressCode(address common.Address) bool {
|
||||||
|
_, ok := al.addressCodes[address]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// Contains checks if a slot within an account is present in the access list, returning
|
// Contains checks if a slot within an account is present in the access list, returning
|
||||||
// separate flags for the presence of the account and the slot respectively.
|
// separate flags for the presence of the account and the slot respectively.
|
||||||
func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
|
func (al *accessList) Contains(address common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
|
||||||
|
|
@ -55,7 +62,8 @@ func (al *accessList) Contains(address common.Address, slot common.Hash) (addres
|
||||||
// newAccessList creates a new accessList.
|
// newAccessList creates a new accessList.
|
||||||
func newAccessList() *accessList {
|
func newAccessList() *accessList {
|
||||||
return &accessList{
|
return &accessList{
|
||||||
addresses: make(map[common.Address]int),
|
addresses: make(map[common.Address]int),
|
||||||
|
addressCodes: make(map[common.Address]struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,6 +75,10 @@ func (al *accessList) Copy() *accessList {
|
||||||
for i, slotMap := range al.slots {
|
for i, slotMap := range al.slots {
|
||||||
cp.slots[i] = maps.Clone(slotMap)
|
cp.slots[i] = maps.Clone(slotMap)
|
||||||
}
|
}
|
||||||
|
cp.addressCodes = make(map[common.Address]struct{}, len(al.addressCodes))
|
||||||
|
for addr := range al.addressCodes {
|
||||||
|
cp.addressCodes[addr] = struct{}{}
|
||||||
|
}
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,6 +92,16 @@ func (al *accessList) AddAddress(address common.Address) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddAddressCode adds an address code to the access list, and returns 'true' if
|
||||||
|
// the operation caused a change (addr was not previously in the list).
|
||||||
|
func (al *accessList) AddAddressCode(address common.Address) bool {
|
||||||
|
if _, present := al.addressCodes[address]; present {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
al.addressCodes[address] = struct{}{}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// AddSlot adds the specified (addr, slot) combo to the access list.
|
// AddSlot adds the specified (addr, slot) combo to the access list.
|
||||||
// Return values are:
|
// Return values are:
|
||||||
// - address added
|
// - address added
|
||||||
|
|
@ -142,6 +164,11 @@ func (al *accessList) Equal(other *accessList) bool {
|
||||||
return slices.EqualFunc(al.slots, other.slots, maps.Equal)
|
return slices.EqualFunc(al.slots, other.slots, maps.Equal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteAddressCode removes an address code from the access list.
|
||||||
|
func (al *accessList) DeleteAddressCode(address common.Address) {
|
||||||
|
delete(al.addressCodes, address)
|
||||||
|
}
|
||||||
|
|
||||||
// PrettyPrint prints the contents of the access list in a human-readable form
|
// PrettyPrint prints the contents of the access list in a human-readable form
|
||||||
func (al *accessList) PrettyPrint() string {
|
func (al *accessList) PrettyPrint() string {
|
||||||
out := new(strings.Builder)
|
out := new(strings.Builder)
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,10 @@ func (j *journal) accessListAddAccount(addr common.Address) {
|
||||||
j.append(accessListAddAccountChange{addr})
|
j.append(accessListAddAccountChange{addr})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *journal) accessListAddAccountCode(addr common.Address) {
|
||||||
|
j.append(accessListAddAccountCodeChange{addr})
|
||||||
|
}
|
||||||
|
|
||||||
func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) {
|
func (j *journal) accessListAddSlot(addr common.Address, slot common.Hash) {
|
||||||
j.append(accessListAddSlotChange{
|
j.append(accessListAddSlotChange{
|
||||||
address: addr,
|
address: addr,
|
||||||
|
|
@ -282,6 +286,9 @@ type (
|
||||||
address common.Address
|
address common.Address
|
||||||
slot common.Hash
|
slot common.Hash
|
||||||
}
|
}
|
||||||
|
accessListAddAccountCodeChange struct {
|
||||||
|
address common.Address
|
||||||
|
}
|
||||||
|
|
||||||
// Changes to transient storage
|
// Changes to transient storage
|
||||||
transientStorageChange struct {
|
transientStorageChange struct {
|
||||||
|
|
@ -485,6 +492,20 @@ func (ch accessListAddAccountChange) copy() journalEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ch accessListAddAccountCodeChange) revert(s *StateDB) {
|
||||||
|
s.accessList.DeleteAddressCode(ch.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch accessListAddAccountCodeChange) dirtied() *common.Address {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ch accessListAddAccountCodeChange) copy() journalEntry {
|
||||||
|
return accessListAddAccountCodeChange{
|
||||||
|
address: ch.address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
func (ch accessListAddSlotChange) revert(s *StateDB) {
|
||||||
s.accessList.DeleteSlot(ch.address, ch.slot)
|
s.accessList.DeleteSlot(ch.address, ch.slot)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,11 @@ func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash)
|
||||||
if cached, ok := r.codeSizeCache.Get(codeHash); ok {
|
if cached, ok := r.codeSizeCache.Get(codeHash); ok {
|
||||||
return cached, nil
|
return cached, nil
|
||||||
}
|
}
|
||||||
|
codeSize := rawdb.ReadCodeSizeWithPrefix(r.db, codeHash)
|
||||||
|
if codeSize != -1 {
|
||||||
|
r.codeSizeCache.Add(codeHash, codeSize)
|
||||||
|
return codeSize, nil
|
||||||
|
}
|
||||||
code, err := r.Code(addr, codeHash)
|
code, err := r.Code(addr, codeHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
||||||
|
|
@ -1361,6 +1361,10 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d
|
||||||
al.AddAddress(sender)
|
al.AddAddress(sender)
|
||||||
if dst != nil {
|
if dst != nil {
|
||||||
al.AddAddress(*dst)
|
al.AddAddress(*dst)
|
||||||
|
// TODO: add for devnet-3
|
||||||
|
// if rules.IsOsaka {
|
||||||
|
// al.AddAddressCode(*dst)
|
||||||
|
// }
|
||||||
// If it's a create-tx, the destination will be added inside evm.create
|
// If it's a create-tx, the destination will be added inside evm.create
|
||||||
}
|
}
|
||||||
for _, addr := range precompiles {
|
for _, addr := range precompiles {
|
||||||
|
|
@ -1402,11 +1406,23 @@ func (s *StateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddAddressCodeToAccessList adds the given address to the access list
|
||||||
|
func (s *StateDB) AddAddressCodeToAccessList(addr common.Address) {
|
||||||
|
if s.accessList.AddAddressCode(addr) {
|
||||||
|
s.journal.accessListAddAccountCode(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddressInAccessList returns true if the given address is in the access list.
|
// AddressInAccessList returns true if the given address is in the access list.
|
||||||
func (s *StateDB) AddressInAccessList(addr common.Address) bool {
|
func (s *StateDB) AddressInAccessList(addr common.Address) bool {
|
||||||
return s.accessList.ContainsAddress(addr)
|
return s.accessList.ContainsAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddressCodeInAccessList returns true if the given address code is in the access list.
|
||||||
|
func (s *StateDB) AddressCodeInAccessList(addr common.Address) bool {
|
||||||
|
return s.accessList.ContainsAddressCode(addr)
|
||||||
|
}
|
||||||
|
|
||||||
// SlotInAccessList returns true if the given (address, slot)-tuple is in the access list.
|
// SlotInAccessList returns true if the given (address, slot)-tuple is in the access list.
|
||||||
func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
|
func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressPresent bool, slotPresent bool) {
|
||||||
return s.accessList.Contains(addr, slot)
|
return s.accessList.Contains(addr, slot)
|
||||||
|
|
|
||||||
|
|
@ -125,10 +125,18 @@ func (s *hookedStateDB) SlotInAccessList(addr common.Address, slot common.Hash)
|
||||||
return s.inner.SlotInAccessList(addr, slot)
|
return s.inner.SlotInAccessList(addr, slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *hookedStateDB) AddressCodeInAccessList(addr common.Address) bool {
|
||||||
|
return s.inner.AddressCodeInAccessList(addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *hookedStateDB) AddAddressToAccessList(addr common.Address) {
|
func (s *hookedStateDB) AddAddressToAccessList(addr common.Address) {
|
||||||
s.inner.AddAddressToAccessList(addr)
|
s.inner.AddAddressToAccessList(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *hookedStateDB) AddAddressCodeToAccessList(addr common.Address) {
|
||||||
|
s.inner.AddAddressCodeToAccessList(addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *hookedStateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
func (s *hookedStateDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
|
||||||
s.inner.AddSlotToAccessList(addr, slot)
|
s.inner.AddSlotToAccessList(addr, slot)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
blockchain, _ = NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), nil)
|
blockchain, _ = NewBlockChain(db, gspec, beacon.New(ethash.NewFaker()), nil)
|
||||||
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
tooBigInitCode = [params.MaxInitCodeSizeEIP3860 + 1]byte{}
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
|
||||||
|
|
@ -475,8 +475,11 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the init code size has been exceeded.
|
// Check whether the init code size has been exceeded.
|
||||||
if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
|
if rules.IsOsaka && contractCreation && len(msg.Data) > params.MaxInitCodeSizeEIP7907 {
|
||||||
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
|
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSizeEIP7907)
|
||||||
|
}
|
||||||
|
if !rules.IsOsaka && rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSizeEIP3860 {
|
||||||
|
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSizeEIP3860)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the preparatory steps for state transition which includes:
|
// Execute the preparatory steps for state transition which includes:
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,8 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||||
return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type())
|
return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type())
|
||||||
}
|
}
|
||||||
// Check whether the init code size has been exceeded
|
// Check whether the init code size has been exceeded
|
||||||
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
|
if rules.IsShanghai && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSizeEIP7907 {
|
||||||
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize)
|
return fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSizeEIP7907)
|
||||||
}
|
}
|
||||||
if rules.IsOsaka && tx.Gas() > params.MaxTxGas {
|
if rules.IsOsaka && tx.Gas() > params.MaxTxGas {
|
||||||
return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
|
return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ var activators = map[int]func(*JumpTable){
|
||||||
1153: enable1153,
|
1153: enable1153,
|
||||||
4762: enable4762,
|
4762: enable4762,
|
||||||
7702: enable7702,
|
7702: enable7702,
|
||||||
|
7907: enable7907,
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableEIP enables the given EIP on the config.
|
// EnableEIP enables the given EIP on the config.
|
||||||
|
|
@ -538,3 +539,14 @@ func enable7702(jt *JumpTable) {
|
||||||
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
|
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
|
||||||
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
|
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable7907 the EIP-7907 changes to support large contracts.
|
||||||
|
func enable7907(jt *JumpTable) {
|
||||||
|
jt[CALL].dynamicGas = gasCallEIP7907
|
||||||
|
jt[CALLCODE].dynamicGas = gasCallCodeEIP7907
|
||||||
|
jt[STATICCALL].dynamicGas = gasStaticCallEIP7907
|
||||||
|
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7907
|
||||||
|
jt[EXTCODECOPY].dynamicGas = gasExtCodeCopyEIP7907
|
||||||
|
jt[CREATE].dynamicGas = gasCreateEip7907
|
||||||
|
jt[CREATE2].dynamicGas = gasCreate2Eip7907
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,10 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
||||||
}
|
}
|
||||||
gas = gas - consumed
|
gas = gas - consumed
|
||||||
}
|
}
|
||||||
|
// The contract code is added to the access list _after_ the contract code is successfully deployed.
|
||||||
|
if evm.chainRules.IsOsaka {
|
||||||
|
evm.StateDB.AddAddressCodeToAccessList(address)
|
||||||
|
}
|
||||||
evm.Context.Transfer(evm.StateDB, caller, address, value)
|
evm.Context.Transfer(evm.StateDB, caller, address, value)
|
||||||
|
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||||
|
|
@ -526,7 +530,10 @@ 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.IsOsaka && len(ret) > params.MaxCodeSizeEIP7907 {
|
||||||
|
return ret, ErrMaxCodeSizeExceeded
|
||||||
|
}
|
||||||
|
if !evm.chainRules.IsOsaka && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSizeEIP170 {
|
||||||
return ret, ErrMaxCodeSizeExceeded
|
return ret, ErrMaxCodeSizeExceeded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if size > params.MaxInitCodeSize {
|
if size > params.MaxInitCodeSizeEIP3860 {
|
||||||
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||||
}
|
}
|
||||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||||
|
|
@ -333,7 +333,46 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, ErrGasUintOverflow
|
return 0, ErrGasUintOverflow
|
||||||
}
|
}
|
||||||
if size > params.MaxInitCodeSize {
|
if size > params.MaxInitCodeSizeEIP3860 {
|
||||||
|
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||||
|
}
|
||||||
|
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||||
|
moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32)
|
||||||
|
if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasCreateEip7907(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
size, overflow := stack.Back(2).Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
if size > params.MaxInitCodeSizeEIP7907 {
|
||||||
|
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||||
|
}
|
||||||
|
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||||
|
moreGas := params.InitCodeWordGas * ((size + 31) / 32)
|
||||||
|
if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
func gasCreate2Eip7907(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
size, overflow := stack.Back(2).Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
if size > params.MaxInitCodeSizeEIP7907 {
|
||||||
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
|
||||||
}
|
}
|
||||||
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ type StateDB interface {
|
||||||
Empty(common.Address) bool
|
Empty(common.Address) bool
|
||||||
|
|
||||||
AddressInAccessList(addr common.Address) bool
|
AddressInAccessList(addr common.Address) bool
|
||||||
|
AddressCodeInAccessList(addr common.Address) bool
|
||||||
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
|
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
|
||||||
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
|
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
|
||||||
// even if the feature/fork is not active yet
|
// even if the feature/fork is not active yet
|
||||||
|
|
@ -83,6 +84,9 @@ type StateDB interface {
|
||||||
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
|
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
|
||||||
// even if the feature/fork is not active yet
|
// even if the feature/fork is not active yet
|
||||||
AddSlotToAccessList(addr common.Address, slot common.Hash)
|
AddSlotToAccessList(addr common.Address, slot common.Hash)
|
||||||
|
// AddAddressCodeToAccessList adds the given address code to the access list. This operation is safe to perform
|
||||||
|
// even if the feature/fork is not active yet
|
||||||
|
AddAddressCodeToAccessList(addr common.Address)
|
||||||
|
|
||||||
// PointCache returns the point cache used in computations
|
// PointCache returns the point cache used in computations
|
||||||
PointCache() *utils.PointCache
|
PointCache() *utils.PointCache
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
|
||||||
case evm.chainRules.IsVerkle:
|
case evm.chainRules.IsVerkle:
|
||||||
// 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.IsOsaka:
|
||||||
|
table = &osakaInstructionSet
|
||||||
case evm.chainRules.IsPrague:
|
case evm.chainRules.IsPrague:
|
||||||
table = &pragueInstructionSet
|
table = &pragueInstructionSet
|
||||||
case evm.chainRules.IsCancun:
|
case evm.chainRules.IsCancun:
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ var (
|
||||||
cancunInstructionSet = newCancunInstructionSet()
|
cancunInstructionSet = newCancunInstructionSet()
|
||||||
verkleInstructionSet = newVerkleInstructionSet()
|
verkleInstructionSet = newVerkleInstructionSet()
|
||||||
pragueInstructionSet = newPragueInstructionSet()
|
pragueInstructionSet = newPragueInstructionSet()
|
||||||
|
osakaInstructionSet = newOsakaInstructionSet()
|
||||||
)
|
)
|
||||||
|
|
||||||
// JumpTable contains the EVM opcodes supported at a given fork.
|
// JumpTable contains the EVM opcodes supported at a given fork.
|
||||||
|
|
@ -91,6 +92,12 @@ func newVerkleInstructionSet() JumpTable {
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newOsakaInstructionSet() JumpTable {
|
||||||
|
instructionSet := newPragueInstructionSet()
|
||||||
|
enable7907(&instructionSet)
|
||||||
|
return validate(instructionSet)
|
||||||
|
}
|
||||||
|
|
||||||
func newPragueInstructionSet() JumpTable {
|
func newPragueInstructionSet() JumpTable {
|
||||||
instructionSet := newCancunInstructionSet()
|
instructionSet := newCancunInstructionSet()
|
||||||
enable7702(&instructionSet) // EIP-7702 Setcode transaction type
|
enable7702(&instructionSet) // EIP-7702 Setcode transaction type
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"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"
|
||||||
|
|
@ -310,3 +311,142 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
||||||
return total, nil
|
return total, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
gasCallEIP7907 = makeCallVariantGasCallEIP7907(gasCall)
|
||||||
|
gasDelegateCallEIP7907 = makeCallVariantGasCallEIP7907(gasDelegateCall)
|
||||||
|
gasStaticCallEIP7907 = makeCallVariantGasCallEIP7907(gasStaticCall)
|
||||||
|
gasCallCodeEIP7907 = makeCallVariantGasCallEIP7907(gasCallCode)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rounds n up to the nearest multiple of 32.
|
||||||
|
func ceil32(n int) uint64 {
|
||||||
|
r := n % 32
|
||||||
|
if r == 0 {
|
||||||
|
return uint64(n)
|
||||||
|
} else {
|
||||||
|
return uint64(n + 32 - r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcColdCodeAccessGasCost(evm *EVM, addr common.Address) uint64 {
|
||||||
|
size := evm.StateDB.GetCodeSize(addr)
|
||||||
|
// Only charge additional access cost for contracts larger than old limit.
|
||||||
|
if size <= params.MaxCodeSizeEIP170 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
excess := ceil32(size - params.MaxCodeSizeEIP170)
|
||||||
|
fmt.Println("excess", excess, "cost", (excess*params.CodeReadPerWordGasEIP7907)/32)
|
||||||
|
return (excess * params.CodeReadPerWordGasEIP7907) / 32
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCallVariantGasCallEIP7907(oldCalculator gasFunc) gasFunc {
|
||||||
|
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
var (
|
||||||
|
total uint64 // total dynamic gas used
|
||||||
|
addr = common.Address(stack.Back(1).Bytes20())
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check slot presence in the access list
|
||||||
|
if !evm.StateDB.AddressInAccessList(addr) {
|
||||||
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
|
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
|
||||||
|
// the cost to charge for cold access, if any, is Cold - Warm
|
||||||
|
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
|
||||||
|
// Charge the remaining difference here already, to correctly calculate available
|
||||||
|
// gas for call
|
||||||
|
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
|
return 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
total += coldCost
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check code presence in the access list
|
||||||
|
if !evm.StateDB.AddressCodeInAccessList(addr) {
|
||||||
|
cost := calcColdCodeAccessGasCost(evm, addr)
|
||||||
|
evm.StateDB.AddAddressCodeToAccessList(addr)
|
||||||
|
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
|
return 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
total += cost
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: reading code here would defeat the purpose of separate charging, so
|
||||||
|
// we should first see if the code size is 23 bytes before parsing.
|
||||||
|
|
||||||
|
// Check if code is a delegation and if so, charge for resolution.
|
||||||
|
if target, ok := types.ParseDelegation(evm.StateDB.GetCode(addr)); ok {
|
||||||
|
var cost uint64
|
||||||
|
if evm.StateDB.AddressInAccessList(target) {
|
||||||
|
cost = params.WarmStorageReadCostEIP2929
|
||||||
|
} else {
|
||||||
|
evm.StateDB.AddAddressToAccessList(target)
|
||||||
|
cost = params.ColdAccountAccessCostEIP2929
|
||||||
|
}
|
||||||
|
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
|
return 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
total += cost
|
||||||
|
if !evm.StateDB.AddressCodeInAccessList(target) {
|
||||||
|
cost = calcColdCodeAccessGasCost(evm, target)
|
||||||
|
evm.StateDB.AddAddressCodeToAccessList(target)
|
||||||
|
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||||
|
return 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
total += cost
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now call the old calculator, which takes into account
|
||||||
|
// - create new account
|
||||||
|
// - transfer value
|
||||||
|
// - memory expansion
|
||||||
|
// - 63/64ths rule
|
||||||
|
old, err := oldCalculator(evm, contract, stack, mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return old, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily add the gas charge back to the contract and return value. By
|
||||||
|
// adding it to the return, it will be charged outside of this function, as
|
||||||
|
// part of the dynamic gas. This will ensure it is correctly reported to
|
||||||
|
// tracers.
|
||||||
|
contract.Gas += total
|
||||||
|
|
||||||
|
var overflow bool
|
||||||
|
if total, overflow = math.SafeAdd(old, total); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gasExtCodeCopyEIP7907(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
// memory expansion first (dynamic part of pre-2929 implementation)
|
||||||
|
gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
addr := common.Address(stack.peek().Bytes20())
|
||||||
|
// Check slot presence in the access list
|
||||||
|
if !evm.StateDB.AddressInAccessList(addr) {
|
||||||
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
|
var overflow bool
|
||||||
|
// We charge (cold-warm), since 'warm' is already charged as constantGas
|
||||||
|
if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check address code presence in the access list
|
||||||
|
if !evm.StateDB.AddressCodeInAccessList(addr) {
|
||||||
|
cost := calcColdCodeAccessGasCost(evm, addr)
|
||||||
|
evm.StateDB.AddAddressCodeToAccessList(addr)
|
||||||
|
var overflow bool
|
||||||
|
// We charge (cold-warm), since 'warm' is already charged as constantGas
|
||||||
|
if gas, overflow = math.SafeAdd(gas, cost); overflow {
|
||||||
|
return 0, ErrGasUintOverflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,8 +133,12 @@ const (
|
||||||
DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
|
DefaultElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
|
||||||
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.
|
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.
|
||||||
|
|
||||||
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
|
MaxCodeSizeEIP170 = 24576 // Maximum bytecode to permit for a contract
|
||||||
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
|
MaxInitCodeSizeEIP3860 = 2 * MaxCodeSizeEIP170 // Maximum initcode to permit in a creation transaction and create instructions
|
||||||
|
|
||||||
|
MaxCodeSizeEIP7907 = 262144 // Maximum bytecode permitted per contract after EIP-7907
|
||||||
|
MaxInitCodeSizeEIP7907 = 2 * MaxCodeSizeEIP7907 // Maximum initcode to permit in a creation transaction and create instructions
|
||||||
|
CodeReadPerWordGasEIP7907 = 2 // Cost per word to read code from disk.
|
||||||
|
|
||||||
// Precompiled contract gas prices
|
// Precompiled contract gas prices
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue