mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-03-01 17:13:45 +00:00
Compare commits
9 commits
master
...
fusaka-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3168b3e56 | ||
|
|
9859e6d62a | ||
|
|
18e79fdd7e | ||
|
|
4a4dc08ab1 | ||
|
|
404baa9b27 | ||
|
|
b58f8b3a5f | ||
|
|
8ec1db1a4a | ||
|
|
a3f2cb14a2 | ||
|
|
e96f887e73 |
37 changed files with 6330 additions and 75 deletions
|
|
@ -180,9 +180,12 @@ 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 {
|
||||||
|
r.Error = errors.New("gas limit exceeds maximum")
|
||||||
|
}
|
||||||
results = append(results, r)
|
results = append(results, r)
|
||||||
}
|
}
|
||||||
out, err := json.MarshalIndent(results, "", " ")
|
out, err := json.MarshalIndent(results, "", " ")
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ 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"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -71,48 +70,76 @@ func CalcExcessBlobGas(config *params.ChainConfig, parent *types.Header, headTim
|
||||||
parentExcessBlobGas = *parent.ExcessBlobGas
|
parentExcessBlobGas = *parent.ExcessBlobGas
|
||||||
parentBlobGasUsed = *parent.BlobGasUsed
|
parentBlobGasUsed = *parent.BlobGasUsed
|
||||||
}
|
}
|
||||||
excessBlobGas := parentExcessBlobGas + parentBlobGasUsed
|
var (
|
||||||
targetGas := uint64(targetBlobsPerBlock(config, headTimestamp)) * params.BlobTxBlobGasPerBlob
|
excessBlobGas = parentExcessBlobGas + parentBlobGasUsed
|
||||||
|
target = targetBlobsPerBlock(config, headTimestamp)
|
||||||
|
targetGas = uint64(target) * params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
if excessBlobGas < targetGas {
|
if excessBlobGas < targetGas {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
if !config.IsOsaka(config.LondonBlock, headTimestamp) {
|
||||||
|
return excessBlobGas - targetGas
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIP-7918 (post-Osaka).
|
||||||
|
var (
|
||||||
|
reservePrice = new(big.Int).Mul(parent.BaseFee, big.NewInt(params.BlobBaseCost))
|
||||||
|
blobPrice = calcBlobPrice(config, parent)
|
||||||
|
)
|
||||||
|
if reservePrice.Cmp(blobPrice) > 0 {
|
||||||
|
max := MaxBlobsPerBlock(config, headTimestamp)
|
||||||
|
scaledExcess := parentBlobGasUsed * uint64(max-target) / uint64(max)
|
||||||
|
return parentExcessBlobGas + scaledExcess
|
||||||
|
}
|
||||||
return excessBlobGas - targetGas
|
return excessBlobGas - targetGas
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.ChainConfig, header *types.Header) *big.Int {
|
||||||
var frac uint64
|
blobConfig := latestBlobConfig(config, header.Time)
|
||||||
switch config.LatestFork(header.Time) {
|
if blobConfig == nil {
|
||||||
case forks.Osaka:
|
|
||||||
frac = config.BlobScheduleConfig.Osaka.UpdateFraction
|
|
||||||
case forks.Prague:
|
|
||||||
frac = config.BlobScheduleConfig.Prague.UpdateFraction
|
|
||||||
case forks.Cancun:
|
|
||||||
frac = config.BlobScheduleConfig.Cancun.UpdateFraction
|
|
||||||
default:
|
|
||||||
panic("calculating blob fee on unsupported fork")
|
panic("calculating blob fee on unsupported fork")
|
||||||
}
|
}
|
||||||
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(frac))
|
return fakeExponential(minBlobGasPrice, new(big.Int).SetUint64(*header.ExcessBlobGas), new(big.Int).SetUint64(blobConfig.UpdateFraction))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.ChainConfig, time uint64) int {
|
||||||
if cfg.BlobScheduleConfig == nil {
|
blobConfig := latestBlobConfig(cfg, time)
|
||||||
|
if blobConfig == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
return blobConfig.Max
|
||||||
|
}
|
||||||
|
|
||||||
|
func latestBlobConfig(cfg *params.ChainConfig, time uint64) *params.BlobConfig {
|
||||||
|
if cfg.BlobScheduleConfig == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
london = cfg.LondonBlock
|
london = cfg.LondonBlock
|
||||||
s = cfg.BlobScheduleConfig
|
s = cfg.BlobScheduleConfig
|
||||||
)
|
)
|
||||||
switch {
|
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:
|
case cfg.IsOsaka(london, time) && s.Osaka != nil:
|
||||||
return s.Osaka.Max
|
return s.Osaka
|
||||||
case cfg.IsPrague(london, time) && s.Prague != nil:
|
case cfg.IsPrague(london, time) && s.Prague != nil:
|
||||||
return s.Prague.Max
|
return s.Prague
|
||||||
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
||||||
return s.Cancun.Max
|
return s.Cancun
|
||||||
default:
|
default:
|
||||||
return 0
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,6 +156,16 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
switch {
|
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:
|
case s.Osaka != nil:
|
||||||
return s.Osaka.Max
|
return s.Osaka.Max
|
||||||
case s.Prague != nil:
|
case s.Prague != nil:
|
||||||
|
|
@ -142,23 +179,11 @@ func LatestMaxBlobsPerBlock(cfg *params.ChainConfig) int {
|
||||||
|
|
||||||
// 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.ChainConfig, time uint64) int {
|
||||||
if cfg.BlobScheduleConfig == nil {
|
blobConfig := latestBlobConfig(cfg, time)
|
||||||
return 0
|
if blobConfig == nil {
|
||||||
}
|
|
||||||
var (
|
|
||||||
london = cfg.LondonBlock
|
|
||||||
s = cfg.BlobScheduleConfig
|
|
||||||
)
|
|
||||||
switch {
|
|
||||||
case cfg.IsOsaka(london, time) && s.Osaka != nil:
|
|
||||||
return s.Osaka.Target
|
|
||||||
case cfg.IsPrague(london, time) && s.Prague != nil:
|
|
||||||
return s.Prague.Target
|
|
||||||
case cfg.IsCancun(london, time) && s.Cancun != nil:
|
|
||||||
return s.Cancun.Target
|
|
||||||
default:
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
return blobConfig.Target
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
// fakeExponential approximates factor * e ** (numerator / denominator) using
|
||||||
|
|
@ -177,3 +202,9 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
|
||||||
}
|
}
|
||||||
return output.Div(output, denominator)
|
return output.Div(output, denominator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calcBlobPrice calculates the blob price for a block.
|
||||||
|
func calcBlobPrice(config *params.ChainConfig, header *types.Header) *big.Int {
|
||||||
|
blobBaseFee := CalcBlobFee(config, header)
|
||||||
|
return new(big.Int).Mul(blobBaseFee, big.NewInt(params.BlobTxBlobGasPerBlob))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,3 +127,43 @@ func TestFakeExponential(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalcExcessBlobGasEIP7918(t *testing.T) {
|
||||||
|
var (
|
||||||
|
cfg = params.MergedTestChainConfig
|
||||||
|
targetBlobs = targetBlobsPerBlock(cfg, *cfg.CancunTime)
|
||||||
|
blobGasTarget = uint64(targetBlobs) * params.BlobTxBlobGasPerBlob
|
||||||
|
)
|
||||||
|
makeHeader := func(parentExcess, parentBaseFee uint64, blobsUsed int) *types.Header {
|
||||||
|
blobGasUsed := uint64(blobsUsed) * params.BlobTxBlobGasPerBlob
|
||||||
|
return &types.Header{
|
||||||
|
BaseFee: big.NewInt(int64(parentBaseFee)),
|
||||||
|
ExcessBlobGas: &parentExcess,
|
||||||
|
BlobGasUsed: &blobGasUsed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
header *types.Header
|
||||||
|
wantExcessGas uint64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "BelowReservePrice",
|
||||||
|
header: makeHeader(0, 1_000_000_000, targetBlobs),
|
||||||
|
wantExcessGas: blobGasTarget * 3 / 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AboveReservePrice",
|
||||||
|
header: makeHeader(0, 1, targetBlobs),
|
||||||
|
wantExcessGas: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range tests {
|
||||||
|
got := CalcExcessBlobGas(cfg, tc.header, *cfg.CancunTime)
|
||||||
|
if got != tc.wantExcessGas {
|
||||||
|
t.Fatalf("%s: excess-blob-gas mismatch – have %d, want %d",
|
||||||
|
tc.name, got, tc.wantExcessGas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *Bloc
|
||||||
// header's transaction and uncle roots. The headers are assumed to be already
|
// header's transaction and uncle roots. The headers are assumed to be already
|
||||||
// validated at this point.
|
// validated at this point.
|
||||||
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
|
// check EIP 7934 RLP-encoded block size cap
|
||||||
|
if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.BlockRLPSizeCap {
|
||||||
|
return ErrBlockOversized
|
||||||
|
}
|
||||||
// Check whether the block is already imported.
|
// Check whether the block is already imported.
|
||||||
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
return ErrKnownBlock
|
return ErrKnownBlock
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,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"
|
||||||
|
|
@ -4515,3 +4516,76 @@ func TestGetCanonicalReceipt(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ var (
|
||||||
|
|
||||||
// ErrNoGenesis is returned when there is no Genesis Block.
|
// ErrNoGenesis is returned when there is no Genesis Block.
|
||||||
ErrNoGenesis = errors.New("genesis not found in chain")
|
ErrNoGenesis = errors.New("genesis not found in chain")
|
||||||
|
|
||||||
|
// ErrBlockOversized is returned if the size of the RLP-encoded block
|
||||||
|
// exceeds the cap established by EIP 7934
|
||||||
|
ErrBlockOversized = errors.New("block RLP-encoded size exceeds maximum")
|
||||||
)
|
)
|
||||||
|
|
||||||
// List of evm-call-message pre-checking errors. All state transition messages will
|
// List of evm-call-message pre-checking errors. All state transition messages will
|
||||||
|
|
@ -122,6 +126,9 @@ var (
|
||||||
// Message validation errors:
|
// Message validation errors:
|
||||||
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
|
||||||
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
|
||||||
|
|
||||||
|
// -- EIP-7825 errors --
|
||||||
|
ErrGasLimitTooHigh = errors.New("transaction gas limit too high")
|
||||||
)
|
)
|
||||||
|
|
||||||
// EIP-7702 state transition errors.
|
// EIP-7702 state transition errors.
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,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 {
|
||||||
|
|
@ -91,12 +101,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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,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.
|
||||||
|
|
@ -244,6 +245,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) {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ 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) {
|
||||||
|
|
@ -56,6 +63,7 @@ func (al *accessList) Contains(address common.Address, slot common.Hash) (addres
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1381,6 +1381,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 {
|
||||||
|
|
@ -1422,11 +1426,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()
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,10 @@ func (st *stateTransition) preCheck() error {
|
||||||
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Verify tx gas limit does not exceed EIP-7825 cap.
|
||||||
|
if st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) && msg.GasLimit > params.MaxTxGas {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit)
|
||||||
|
}
|
||||||
return st.buyGas()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,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:
|
||||||
|
|
|
||||||
|
|
@ -1638,6 +1638,11 @@ func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*tx
|
||||||
break // blobfee too low, cannot be included, discard rest of txs from the account
|
break // blobfee too low, cannot be included, discard rest of txs from the account
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.execGas > filter.GasLimitCap {
|
||||||
|
break // execution gas limit is too high
|
||||||
|
}
|
||||||
|
}
|
||||||
// Transaction was accepted according to the filter, append to the pending list
|
// Transaction was accepted according to the filter, append to the pending list
|
||||||
lazies = append(lazies, &txpool.LazyTransaction{
|
lazies = append(lazies, &txpool.LazyTransaction{
|
||||||
Pool: p,
|
Pool: p,
|
||||||
|
|
|
||||||
|
|
@ -530,13 +530,21 @@ func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address]
|
||||||
txs := list.Flatten()
|
txs := list.Flatten()
|
||||||
|
|
||||||
// If the miner requests tip enforcement, cap the lists now
|
// If the miner requests tip enforcement, cap the lists now
|
||||||
if minTipBig != nil {
|
if minTipBig != nil || filter.GasLimitCap != 0 {
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
|
if minTipBig != nil {
|
||||||
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
|
||||||
txs = txs[:i]
|
txs = txs[:i]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if filter.GasLimitCap != 0 {
|
||||||
|
if tx.Gas() > filter.GasLimitCap {
|
||||||
|
txs = txs[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(txs) > 0 {
|
if len(txs) > 0 {
|
||||||
lazies := make([]*txpool.LazyTransaction, len(txs))
|
lazies := make([]*txpool.LazyTransaction, len(txs))
|
||||||
|
|
@ -1255,6 +1263,21 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
|
||||||
}
|
}
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
if reset != nil {
|
if reset != nil {
|
||||||
|
if reset.newHead != nil && reset.oldHead != nil {
|
||||||
|
// Discard the transactions with the gas limit higher than the cap.
|
||||||
|
if pool.chainconfig.IsOsaka(reset.newHead.Number, reset.newHead.Time) && !pool.chainconfig.IsOsaka(reset.oldHead.Number, reset.oldHead.Time) {
|
||||||
|
var hashes []common.Hash
|
||||||
|
pool.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
|
||||||
|
if tx.Gas() > params.MaxTxGas {
|
||||||
|
hashes = append(hashes, hash)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
for _, hash := range hashes {
|
||||||
|
pool.removeTx(hash, true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Reset from the old head to the new, rescheduling any reorged transactions
|
// Reset from the old head to the new, rescheduling any reorged transactions
|
||||||
pool.reset(reset.oldHead, reset.newHead)
|
pool.reset(reset.oldHead, reset.newHead)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ type PendingFilter struct {
|
||||||
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
MinTip *uint256.Int // Minimum miner tip required to include a transaction
|
||||||
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
|
||||||
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
|
||||||
|
GasLimitCap uint64 // Maximum gas can be used for a single transaction execution (0 means no limit)
|
||||||
|
|
||||||
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
|
||||||
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,11 @@ 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 {
|
||||||
|
return fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
|
||||||
}
|
}
|
||||||
// Transactions can't be negative. This may never happen using RLP decoded
|
// Transactions can't be negative. This may never happen using RLP decoded
|
||||||
// transactions but may occur for transactions created using the RPC.
|
// transactions but may occur for transactions created using the RPC.
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
"github.com/ethereum/go-ethereum/crypto/blake2b"
|
||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"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/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
)
|
)
|
||||||
|
|
@ -161,6 +162,14 @@ var PrecompiledContractsOsaka = PrecompiledContracts{
|
||||||
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
|
common.BytesToAddress([]byte{0x0f}): &bls12381Pairing{},
|
||||||
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
|
common.BytesToAddress([]byte{0x10}): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
|
common.BytesToAddress([]byte{0x11}): &bls12381MapG2{},
|
||||||
|
|
||||||
|
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrecompiledContractsP256Verify contains the precompiled Ethereum
|
||||||
|
// contract specified in EIP-7212. This is exported for testing purposes.
|
||||||
|
var PrecompiledContractsP256Verify = PrecompiledContracts{
|
||||||
|
common.BytesToAddress([]byte{0x1, 0x00}): &p256Verify{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -1232,3 +1241,31 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// P256VERIFY (secp256r1 signature verification)
|
||||||
|
// implemented as a native contract
|
||||||
|
type p256Verify struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the precompiled contract
|
||||||
|
func (c *p256Verify) RequiredGas(input []byte) uint64 {
|
||||||
|
return params.P256VerifyGas
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run executes the precompiled contract with given 160 bytes of param, returning the output and the used gas
|
||||||
|
func (c *p256Verify) Run(input []byte) ([]byte, error) {
|
||||||
|
const p256VerifyInputLength = 160
|
||||||
|
if len(input) != p256VerifyInputLength {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract hash, r, s, x, y from the input.
|
||||||
|
hash := input[0:32]
|
||||||
|
r, s := new(big.Int).SetBytes(input[32:64]), new(big.Int).SetBytes(input[64:96])
|
||||||
|
x, y := new(big.Int).SetBytes(input[96:128]), new(big.Int).SetBytes(input[128:160])
|
||||||
|
|
||||||
|
// Verify the signature.
|
||||||
|
if secp256r1.Verify(hash, r, s, x, y) {
|
||||||
|
return true32Byte, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
|
common.BytesToAddress([]byte{0x0f, 0x0e}): &bls12381Pairing{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
|
common.BytesToAddress([]byte{0x0f, 0x0f}): &bls12381MapG1{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
|
common.BytesToAddress([]byte{0x0f, 0x10}): &bls12381MapG2{},
|
||||||
|
|
||||||
|
common.BytesToAddress([]byte{0x0b}): &p256Verify{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP-152 test vectors
|
// EIP-152 test vectors
|
||||||
|
|
@ -397,3 +399,15 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
|
||||||
}
|
}
|
||||||
benchmarkPrecompiled("f0d", testcase, b)
|
benchmarkPrecompiled("f0d", testcase, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Benchmarks the sample inputs from the P256VERIFY precompile.
|
||||||
|
func BenchmarkPrecompiledP256Verify(bench *testing.B) {
|
||||||
|
t := precompiledTest{
|
||||||
|
Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e",
|
||||||
|
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
Name: "p256Verify",
|
||||||
|
}
|
||||||
|
benchmarkPrecompiled("0b", t, bench)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "0b", t) }
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ var activators = map[int]func(*JumpTable){
|
||||||
1153: enable1153,
|
1153: enable1153,
|
||||||
4762: enable4762,
|
4762: enable4762,
|
||||||
7702: enable7702,
|
7702: enable7702,
|
||||||
|
7907: enable7907,
|
||||||
|
7939: enable7939,
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableEIP enables the given EIP on the config.
|
// EnableEIP enables the given EIP on the config.
|
||||||
|
|
@ -293,6 +295,13 @@ func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
x := scope.Stack.pop()
|
||||||
|
// count leading zero bits in x
|
||||||
|
scope.Stack.push(new(uint256.Int).SetUint64(256 - uint64(x.BitLen())))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// enable4844 applies EIP-4844 (BLOBHASH opcode)
|
// enable4844 applies EIP-4844 (BLOBHASH opcode)
|
||||||
func enable4844(jt *JumpTable) {
|
func enable4844(jt *JumpTable) {
|
||||||
jt[BLOBHASH] = &operation{
|
jt[BLOBHASH] = &operation{
|
||||||
|
|
@ -303,6 +312,15 @@ func enable4844(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func enable7939(jt *JumpTable) {
|
||||||
|
jt[CLZ] = &operation{
|
||||||
|
execute: opCLZ,
|
||||||
|
constantGas: GasFastestStep,
|
||||||
|
minStack: minStack(1, 1),
|
||||||
|
maxStack: maxStack(1, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
|
// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
|
||||||
func enable7516(jt *JumpTable) {
|
func enable7516(jt *JumpTable) {
|
||||||
jt[BLOBBASEFEE] = &operation{
|
jt[BLOBBASEFEE] = &operation{
|
||||||
|
|
@ -538,3 +556,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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,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
|
||||||
|
|
@ -331,7 +331,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
|
||||||
|
|
|
||||||
|
|
@ -972,3 +972,47 @@ func TestPush(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpCLZ(t *testing.T) {
|
||||||
|
// set up once
|
||||||
|
evm := NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputHex string // hexadecimal input for clarity
|
||||||
|
want uint64 // expected CLZ result
|
||||||
|
}{
|
||||||
|
{"zero", "0x0", 256},
|
||||||
|
{"one", "0x1", 255},
|
||||||
|
{"all-ones (256 bits)", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0},
|
||||||
|
{"low-10-bytes ones", "0xffffffffff", 216}, // 10 bytes = 80 bits, so 256-80=176? Actually input is 0xffffffffff = 40 bits so 256-40=216
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
// prepare a fresh stack and PC
|
||||||
|
stack := newstack()
|
||||||
|
pc := uint64(0)
|
||||||
|
|
||||||
|
// parse input
|
||||||
|
val := new(uint256.Int)
|
||||||
|
if _, err := fmt.Sscan(tc.inputHex, val); err != nil {
|
||||||
|
// fallback: try hex
|
||||||
|
val.SetFromHex(tc.inputHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.push(val)
|
||||||
|
opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack})
|
||||||
|
|
||||||
|
if gotLen := stack.len(); gotLen != 1 {
|
||||||
|
t.Fatalf("stack length = %d; want 1", gotLen)
|
||||||
|
}
|
||||||
|
result := stack.pop()
|
||||||
|
|
||||||
|
if got := result.Uint64(); got != tc.want {
|
||||||
|
t.Fatalf("clz(%q) = %d; want %d", tc.inputHex, got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,13 @@ 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:
|
||||||
|
table = &osakaInstructionSet
|
||||||
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,13 @@ func newVerkleInstructionSet() JumpTable {
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newOsakaInstructionSet() JumpTable {
|
||||||
|
instructionSet := newPragueInstructionSet()
|
||||||
|
enable7907(&instructionSet)
|
||||||
|
enable7939(&instructionSet) // EIP-7939 (CLZ opcode)
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
|
||||||
case rules.IsVerkle:
|
case rules.IsVerkle:
|
||||||
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
|
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
|
||||||
case rules.IsOsaka:
|
case rules.IsOsaka:
|
||||||
return newPragueInstructionSet(), errors.New("osaka-fork not defined yet")
|
return newOsakaInstructionSet(), nil
|
||||||
case rules.IsPrague:
|
case rules.IsPrague:
|
||||||
return newPragueInstructionSet(), nil
|
return newPragueInstructionSet(), nil
|
||||||
case rules.IsCancun:
|
case rules.IsCancun:
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ const (
|
||||||
SHL OpCode = 0x1b
|
SHL OpCode = 0x1b
|
||||||
SHR OpCode = 0x1c
|
SHR OpCode = 0x1c
|
||||||
SAR OpCode = 0x1d
|
SAR OpCode = 0x1d
|
||||||
|
CLZ OpCode = 0x1e
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0x20 range - crypto.
|
// 0x20 range - crypto.
|
||||||
|
|
@ -282,6 +283,7 @@ var opCodeToString = [256]string{
|
||||||
SHL: "SHL",
|
SHL: "SHL",
|
||||||
SHR: "SHR",
|
SHR: "SHR",
|
||||||
SAR: "SAR",
|
SAR: "SAR",
|
||||||
|
CLZ: "CLZ",
|
||||||
ADDMOD: "ADDMOD",
|
ADDMOD: "ADDMOD",
|
||||||
MULMOD: "MULMOD",
|
MULMOD: "MULMOD",
|
||||||
|
|
||||||
|
|
@ -484,6 +486,7 @@ var stringToOp = map[string]OpCode{
|
||||||
"SHL": SHL,
|
"SHL": SHL,
|
||||||
"SHR": SHR,
|
"SHR": SHR,
|
||||||
"SAR": SAR,
|
"SAR": SAR,
|
||||||
|
"CLZ": CLZ,
|
||||||
"ADDMOD": ADDMOD,
|
"ADDMOD": ADDMOD,
|
||||||
"MULMOD": MULMOD,
|
"MULMOD": MULMOD,
|
||||||
"KECCAK256": KECCAK256,
|
"KECCAK256": KECCAK256,
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -309,3 +310,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
|
||||||
|
}
|
||||||
|
|
|
||||||
5476
core/vm/testdata/precompiles/p256Verify.json
vendored
Normal file
5476
core/vm/testdata/precompiles/p256Verify.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
33
crypto/secp256r1/verifier.go
Normal file
33
crypto/secp256r1/verifier.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright 2024 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 secp256r1 implements signature verification for the P256VERIFY precompile.
|
||||||
|
package secp256r1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Verify checks the given signature (r, s) for the given hash and public key (x, y).
|
||||||
|
func Verify(hash []byte, r, s, x, y *big.Int) bool {
|
||||||
|
if x == nil || y == nil || !elliptic.P256().IsOnCurve(x, y) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
pk := &ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
|
||||||
|
return ecdsa.Verify(pk, hash, r, s)
|
||||||
|
}
|
||||||
|
|
@ -535,9 +535,15 @@ func (d *Downloader) syncToHead() (err error) {
|
||||||
|
|
||||||
// If a part of blockchain data has already been written into active store,
|
// If a part of blockchain data has already been written into active store,
|
||||||
// disable the ancient style insertion explicitly.
|
// disable the ancient style insertion explicitly.
|
||||||
if origin >= frozen && frozen != 0 {
|
if origin >= frozen && origin != 0 {
|
||||||
d.ancientLimit = 0
|
d.ancientLimit = 0
|
||||||
log.Info("Disabling direct-ancient mode", "origin", origin, "ancient", frozen-1)
|
var ancient string
|
||||||
|
if frozen == 0 {
|
||||||
|
ancient = "null"
|
||||||
|
} else {
|
||||||
|
ancient = fmt.Sprintf("%d", frozen-1)
|
||||||
|
}
|
||||||
|
log.Info("Disabling direct-ancient mode", "origin", origin, "ancient", ancient)
|
||||||
} else if d.ancientLimit > 0 {
|
} else if d.ancientLimit > 0 {
|
||||||
log.Debug("Enabling direct-ancient mode", "ancient", d.ancientLimit)
|
log.Debug("Enabling direct-ancient mode", "ancient", d.ancientLimit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ type environment struct {
|
||||||
signer types.Signer
|
signer types.Signer
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
tcount int // tx count in cycle
|
tcount int // tx count in cycle
|
||||||
|
size uint64 // size of the block we are building
|
||||||
gasPool *core.GasPool // available gas used to pack transactions
|
gasPool *core.GasPool // available gas used to pack transactions
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
|
|
@ -68,6 +69,11 @@ const (
|
||||||
commitInterruptNewHead
|
commitInterruptNewHead
|
||||||
commitInterruptResubmit
|
commitInterruptResubmit
|
||||||
commitInterruptTimeout
|
commitInterruptTimeout
|
||||||
|
|
||||||
|
// cap the size of blocks we will produce below the max allowed by
|
||||||
|
// EIP-7934. This gives us buffer room if the estimated size of the
|
||||||
|
// block we are building is off from the actual encoded size.
|
||||||
|
blockRLPSizeCapBuffer = 1_000_000
|
||||||
)
|
)
|
||||||
|
|
||||||
// newPayloadResult is the result of payload generation.
|
// newPayloadResult is the result of payload generation.
|
||||||
|
|
@ -95,12 +101,37 @@ type generateParams struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateWork generates a sealing block based on the given parameters.
|
// generateWork generates a sealing block based on the given parameters.
|
||||||
func (miner *Miner) generateWork(params *generateParams, witness bool) *newPayloadResult {
|
func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPayloadResult {
|
||||||
work, err := miner.prepareWork(params, witness)
|
work, err := miner.prepareWork(genParam, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
if !params.noTxs {
|
var includedWithdrawals types.Withdrawals
|
||||||
|
|
||||||
|
// If we are post-osaka, incorporate the requested withdrawals into the
|
||||||
|
// block size calculation up-front to ensure that all requested withdrawals
|
||||||
|
// can be included even if we hit the size cap when filling the block with
|
||||||
|
// txs.
|
||||||
|
//
|
||||||
|
// Also, ensure that including all requested withdrawals wouldn't bring us
|
||||||
|
// over the block size cap limit. The withdrawal cap ensures that this can't
|
||||||
|
// actually happen right now, but it doesn't hurt to make this code
|
||||||
|
// future-proof for a situation where the withdrawal cap is lifted.
|
||||||
|
if miner.chainConfig.IsOsaka(work.header.Number, work.header.Time) {
|
||||||
|
maxBlockSize := params.BlockRLPSizeCap - blockRLPSizeCapBuffer
|
||||||
|
|
||||||
|
for _, withdrawal := range genParam.withdrawals {
|
||||||
|
if int(work.size)+params.WithdrawalSize > maxBlockSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
work.size += params.WithdrawalSize
|
||||||
|
includedWithdrawals = append(includedWithdrawals, withdrawal)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
includedWithdrawals = genParam.withdrawals
|
||||||
|
}
|
||||||
|
|
||||||
|
if !genParam.noTxs {
|
||||||
interrupt := new(atomic.Int32)
|
interrupt := new(atomic.Int32)
|
||||||
timer := time.AfterFunc(miner.config.Recommit, func() {
|
timer := time.AfterFunc(miner.config.Recommit, func() {
|
||||||
interrupt.Store(commitInterruptTimeout)
|
interrupt.Store(commitInterruptTimeout)
|
||||||
|
|
@ -112,8 +143,8 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
body := types.Body{Transactions: work.txs, Withdrawals: includedWithdrawals}
|
||||||
|
|
||||||
body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
|
|
||||||
allLogs := make([]*types.Log, 0)
|
allLogs := make([]*types.Log, 0)
|
||||||
for _, r := range work.receipts {
|
for _, r := range work.receipts {
|
||||||
allLogs = append(allLogs, r.Logs...)
|
allLogs = append(allLogs, r.Logs...)
|
||||||
|
|
@ -256,6 +287,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
|
||||||
return &environment{
|
return &environment{
|
||||||
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),
|
||||||
state: state,
|
state: state,
|
||||||
|
size: uint64(header.Size()),
|
||||||
coinbase: coinbase,
|
coinbase: coinbase,
|
||||||
header: header,
|
header: header,
|
||||||
witness: state.Witness(),
|
witness: state.Witness(),
|
||||||
|
|
@ -273,6 +305,7 @@ func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) e
|
||||||
}
|
}
|
||||||
env.txs = append(env.txs, tx)
|
env.txs = append(env.txs, tx)
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
|
env.size += tx.Size()
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -298,6 +331,7 @@ func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transactio
|
||||||
env.receipts = append(env.receipts, receipt)
|
env.receipts = append(env.receipts, receipt)
|
||||||
env.sidecars = append(env.sidecars, sc)
|
env.sidecars = append(env.sidecars, sc)
|
||||||
env.blobs += len(sc.Blobs)
|
env.blobs += len(sc.Blobs)
|
||||||
|
env.size += tx.WithoutBlobTxSidecar().Size()
|
||||||
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
*env.header.BlobGasUsed += receipt.BlobGasUsed
|
||||||
env.tcount++
|
env.tcount++
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -318,7 +352,11 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
|
||||||
gasLimit := env.header.GasLimit
|
var (
|
||||||
|
isOsaka = miner.chainConfig.IsOsaka(env.header.Number, env.header.Time)
|
||||||
|
isCancun = miner.chainConfig.IsCancun(env.header.Number, env.header.Time)
|
||||||
|
gasLimit = env.header.GasLimit
|
||||||
|
)
|
||||||
if env.gasPool == nil {
|
if env.gasPool == nil {
|
||||||
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||||
}
|
}
|
||||||
|
|
@ -374,7 +412,7 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
// Most of the blob gas logic here is agnostic as to if the chain supports
|
// Most of the blob gas logic here is agnostic as to if the chain supports
|
||||||
// blobs or not, however the max check panics when called on a chain without
|
// blobs or not, however the max check panics when called on a chain without
|
||||||
// a defined schedule, so we need to verify it's safe to call.
|
// a defined schedule, so we need to verify it's safe to call.
|
||||||
if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
|
if isCancun {
|
||||||
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
|
||||||
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
|
||||||
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
|
||||||
|
|
@ -391,8 +429,14 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if inclusion of the transaction would put the block size over the
|
||||||
|
// maximum we allow, don't add any more txs to the payload.
|
||||||
|
if isOsaka && env.size+tx.Size() > params.BlockRLPSizeCap-blockRLPSizeCapBuffer {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure all transactions after osaka have cell proofs
|
// Make sure all transactions after osaka have cell proofs
|
||||||
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
if isOsaka {
|
||||||
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
if sidecar := tx.BlobTxSidecar(); sidecar != nil {
|
||||||
if sidecar.Version == 0 {
|
if sidecar.Version == 0 {
|
||||||
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
|
||||||
|
|
@ -462,6 +506,9 @@ func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment)
|
||||||
if env.header.ExcessBlobGas != nil {
|
if env.header.ExcessBlobGas != nil {
|
||||||
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
|
||||||
}
|
}
|
||||||
|
if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
|
||||||
|
filter.GasLimitCap = params.MaxTxGas
|
||||||
|
}
|
||||||
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
|
||||||
pendingPlainTxs := miner.txpool.Pending(filter)
|
pendingPlainTxs := miner.txpool.Pending(filter)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,11 @@ type ChainConfig struct {
|
||||||
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
||||||
OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka)
|
OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka)
|
||||||
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
||||||
|
BPO1Time *uint64 `json:"bpo1Time,omitempty"` // BPO1 switch time (nil = no fork, 0 = already on bpo1)
|
||||||
|
BPO2Time *uint64 `json:"bpo2Time,omitempty"` // BPO2 switch time (nil = no fork, 0 = already on bpo2)
|
||||||
|
BPO3Time *uint64 `json:"bpo3Time,omitempty"` // BPO3 switch time (nil = no fork, 0 = already on bpo3)
|
||||||
|
BPO4Time *uint64 `json:"bpo4Time,omitempty"` // BPO4 switch time (nil = no fork, 0 = already on bpo4)
|
||||||
|
BPO5Time *uint64 `json:"bpo5Time,omitempty"` // BPO5 switch time (nil = no fork, 0 = already on bpo5)
|
||||||
|
|
||||||
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
// TerminalTotalDifficulty is the amount of total difficulty reached by
|
||||||
// the network that triggers the consensus upgrade.
|
// the network that triggers the consensus upgrade.
|
||||||
|
|
@ -531,6 +536,21 @@ func (c *ChainConfig) Description() string {
|
||||||
if c.VerkleTime != nil {
|
if c.VerkleTime != nil {
|
||||||
banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime)
|
banner += fmt.Sprintf(" - Verkle: @%-10v\n", *c.VerkleTime)
|
||||||
}
|
}
|
||||||
|
if c.BPO1Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - BPO1: @%-10v\n", *c.BPO1Time)
|
||||||
|
}
|
||||||
|
if c.BPO2Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - BPO2: @%-10v\n", *c.BPO2Time)
|
||||||
|
}
|
||||||
|
if c.BPO3Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - BPO3: @%-10v\n", *c.BPO3Time)
|
||||||
|
}
|
||||||
|
if c.BPO4Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - BPO4: @%-10v\n", *c.BPO4Time)
|
||||||
|
}
|
||||||
|
if c.BPO5Time != nil {
|
||||||
|
banner += fmt.Sprintf(" - BPO5: @%-10v\n", *c.BPO5Time)
|
||||||
|
}
|
||||||
return banner
|
return banner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -547,6 +567,11 @@ type BlobScheduleConfig struct {
|
||||||
Prague *BlobConfig `json:"prague,omitempty"`
|
Prague *BlobConfig `json:"prague,omitempty"`
|
||||||
Osaka *BlobConfig `json:"osaka,omitempty"`
|
Osaka *BlobConfig `json:"osaka,omitempty"`
|
||||||
Verkle *BlobConfig `json:"verkle,omitempty"`
|
Verkle *BlobConfig `json:"verkle,omitempty"`
|
||||||
|
BPO1 *BlobConfig `json:"bpo1,omitempty"`
|
||||||
|
BPO2 *BlobConfig `json:"bpo2,omitempty"`
|
||||||
|
BPO3 *BlobConfig `json:"bpo3,omitempty"`
|
||||||
|
BPO4 *BlobConfig `json:"bpo4,omitempty"`
|
||||||
|
BPO5 *BlobConfig `json:"bpo5,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
||||||
|
|
@ -654,6 +679,31 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsBPO1 returns whether time is either equal to the BPO1 fork time or greater.
|
||||||
|
func (c *ChainConfig) IsBPO1(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsLondon(num) && isTimestampForked(c.BPO1Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBPO2 returns whether time is either equal to the BPO2 fork time or greater.
|
||||||
|
func (c *ChainConfig) IsBPO2(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsLondon(num) && isTimestampForked(c.BPO2Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBPO3 returns whether time is either equal to the BPO3 fork time or greater.
|
||||||
|
func (c *ChainConfig) IsBPO3(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsLondon(num) && isTimestampForked(c.BPO3Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBPO4 returns whether time is either equal to the BPO4 fork time or greater.
|
||||||
|
func (c *ChainConfig) IsBPO4(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsLondon(num) && isTimestampForked(c.BPO4Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBPO5 returns whether time is either equal to the BPO5 fork time or greater.
|
||||||
|
func (c *ChainConfig) IsBPO5(num *big.Int, time uint64) bool {
|
||||||
|
return c.IsLondon(num) && isTimestampForked(c.BPO5Time, time)
|
||||||
|
}
|
||||||
|
|
||||||
// IsVerkleGenesis checks whether the verkle fork is activated at the genesis block.
|
// IsVerkleGenesis checks whether the verkle fork is activated at the genesis block.
|
||||||
//
|
//
|
||||||
// Verkle mode is considered enabled if the verkle fork time is configured,
|
// Verkle mode is considered enabled if the verkle fork time is configured,
|
||||||
|
|
@ -778,6 +828,11 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
||||||
{name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun},
|
{name: "cancun", timestamp: c.CancunTime, config: bsc.Cancun},
|
||||||
{name: "prague", timestamp: c.PragueTime, config: bsc.Prague},
|
{name: "prague", timestamp: c.PragueTime, config: bsc.Prague},
|
||||||
{name: "osaka", timestamp: c.OsakaTime, config: bsc.Osaka},
|
{name: "osaka", timestamp: c.OsakaTime, config: bsc.Osaka},
|
||||||
|
{name: "bpo1", timestamp: c.BPO1Time, config: bsc.BPO1},
|
||||||
|
{name: "bpo2", timestamp: c.BPO2Time, config: bsc.BPO2},
|
||||||
|
{name: "bpo3", timestamp: c.BPO3Time, config: bsc.BPO3},
|
||||||
|
{name: "bpo4", timestamp: c.BPO4Time, config: bsc.BPO4},
|
||||||
|
{name: "bpo5", timestamp: c.BPO5Time, config: bsc.BPO5},
|
||||||
} {
|
} {
|
||||||
if cur.config != nil {
|
if cur.config != nil {
|
||||||
if err := cur.config.validate(); err != nil {
|
if err := cur.config.validate(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const (
|
||||||
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
|
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
|
||||||
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
|
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
|
||||||
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
|
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
|
||||||
|
MaxTxGas uint64 = 30_000_000 // eip-7825 maximum transaction gas limit
|
||||||
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
|
||||||
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
|
||||||
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
QuadCoeffDiv uint64 = 512 // Divisor for the quadratic particle of the memory cost equation.
|
||||||
|
|
@ -132,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
|
||||||
|
|
||||||
|
|
@ -163,6 +168,8 @@ const (
|
||||||
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
||||||
Bls12381MapG2Gas uint64 = 23800 // Gas price for BLS12-381 mapping field element to G2 operation
|
Bls12381MapG2Gas uint64 = 23800 // Gas price for BLS12-381 mapping field element to G2 operation
|
||||||
|
|
||||||
|
P256VerifyGas uint64 = 3450 // secp256r1 elliptic curve signature verifier gas price
|
||||||
|
|
||||||
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
||||||
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
||||||
RefundQuotient uint64 = 2
|
RefundQuotient uint64 = 2
|
||||||
|
|
@ -173,8 +180,12 @@ const (
|
||||||
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
BlobTxBlobGasPerBlob = 1 << 17 // Gas consumption of a single data blob (== blob byte size)
|
||||||
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
BlobTxMinBlobGasprice = 1 // Minimum gas price for data blobs
|
||||||
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
BlobTxPointEvaluationPrecompileGas = 50000 // Gas price for the point evaluation precompile.
|
||||||
|
BlobBaseCost = 1 << 14 // Base execution gas cost for a blob.
|
||||||
|
|
||||||
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
|
|
||||||
|
WithdrawalSize = 23 // size of a withdrawal
|
||||||
|
BlockRLPSizeCap = 8_388_608 // maximum size of an RLP-encoded block
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
// Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue