Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions chain/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ const (
Petersburg = "petersburg"
Istanbul = "istanbul"
London = "london"
Paris = "paris"
Shanghai = "shanghai"
EIP150 = "EIP150"
EIP158 = "EIP158"
EIP155 = "EIP155"
Expand Down Expand Up @@ -123,6 +125,8 @@ func (f *Forks) At(block uint64) ForksInTime {
Petersburg: f.IsActive(Petersburg, block),
Istanbul: f.IsActive(Istanbul, block),
London: f.IsActive(London, block),
Paris: f.IsActive(Paris, block),
Shanghai: f.IsActive(Shanghai, block),
EIP150: f.IsActive(EIP150, block),
EIP158: f.IsActive(EIP158, block),
EIP155: f.IsActive(EIP155, block),
Expand Down Expand Up @@ -177,6 +181,8 @@ type ForksInTime struct {
Petersburg,
Istanbul,
London,
Paris,
Shanghai,
EIP150,
EIP158,
EIP155,
Expand All @@ -197,6 +203,8 @@ var AllForksEnabled = &Forks{
Petersburg: NewFork(0),
Istanbul: NewFork(0),
London: NewFork(0),
Paris: NewFork(0),
Shanghai: NewFork(0),
QuorumCalcAlignment: NewFork(0),
TxHashWithType: NewFork(0),
LondonFix: NewFork(0),
Expand Down
2 changes: 1 addition & 1 deletion jsonrpc/eth_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ func (e *Eth) EstimateGas(arg *txnArgs, rawNum *BlockNumber) (interface{}, error
if transaction.IsValueTransfer() {
// if it is a simple value transfer or a contract creation,
// we already know what is the transaction gas cost, no need to apply transaction
gasCost, err := state.TransactionGasCost(transaction, forksInTime.Homestead, forksInTime.Istanbul)
gasCost, err := state.TransactionGasCost(transaction, forksInTime.Homestead, forksInTime.Istanbul, forksInTime.Shanghai)
if err != nil {
return nil, err
}
Expand Down
76 changes: 56 additions & 20 deletions state/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const (
SpuriousDragonMaxCodeSize = 24576
TxPoolMaxInitCodeSize = 2 * SpuriousDragonMaxCodeSize

// EIP-3860: Limit and meter initcode
EIP3860MaxInitCodeSize = 49152 // 48KB limit for initcode
EIP3860InitCodeWordGas uint64 = 2 // 2 gas per 32-byte word for initcode

TxGas uint64 = 21000 // Per transaction not creating a contract
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract
)
Expand Down Expand Up @@ -584,7 +588,7 @@ func (t *Transition) apply(msg *types.Transaction) (*runtime.ExecutionResult, er
}

// 4. there is no overflow when calculating intrinsic gas
intrinsicGasCost, err := TransactionGasCost(msg, t.config.Homestead, t.config.Istanbul)
intrinsicGasCost, err := TransactionGasCost(msg, t.config.Homestead, t.config.Istanbul, t.config.Shanghai)
if err != nil {
return nil, NewTransitionApplicationError(err, false)
}
Expand Down Expand Up @@ -1009,6 +1013,19 @@ func (t *Transition) GetBlockHash(number int64) (res types.Hash) {
return t.getHash(uint64(number)) //nolint:gosec
}

func (t *Transition) GetPrevBlockHash() types.Hash {
// Get the previous block's hash (current block number - 1)
prevBlockNumber := t.ctx.Number - 1

// Safety check: ensure we don't have negative block numbers
if prevBlockNumber < 0 {
// Return zero hash for genesis block (block 0)
return types.ZeroHash
}

return t.getHash(uint64(prevBlockNumber))
}

func (t *Transition) EmitLog(addr types.Address, topics []types.Hash, data []byte) {
t.state.EmitLog(addr, topics, data)
}
Expand Down Expand Up @@ -1112,7 +1129,7 @@ func (t *Transition) GetRefund() uint64 {
return t.state.GetRefund()
}

func TransactionGasCost(msg *types.Transaction, isHomestead, isIstanbul bool) (uint64, error) {
func TransactionGasCost(msg *types.Transaction, isHomestead, isIstanbul, isShanghai bool) (uint64, error) {
cost := uint64(0)

// Contract creation is only paid on the homestead fork
Expand All @@ -1124,32 +1141,51 @@ func TransactionGasCost(msg *types.Transaction, isHomestead, isIstanbul bool) (u

payload := msg.Input
if len(payload) > 0 {
zeros := uint64(0)
// EIP-3860: Limit and meter initcode for Shanghai fork
if msg.IsContractCreation() && isShanghai {
// Check initcode size limit
if len(payload) > EIP3860MaxInitCodeSize {
return 0, runtime.ErrMaxCodeSizeExceeded
}

// Calculate gas cost for initcode: 2 gas per 32-byte word
wordCount := (uint64(len(payload)) + 31) / 32
initcodeGasCost := wordCount * EIP3860InitCodeWordGas

for i := 0; i < len(payload); i++ {
if payload[i] == 0 {
zeros++
if (math.MaxUint64-cost)/EIP3860InitCodeWordGas < wordCount {
return 0, ErrIntrinsicGasOverflow
}
}

nonZeros := uint64(len(payload)) - zeros
nonZeroCost := uint64(68)
cost += initcodeGasCost
} else {
// Pre-Shanghai gas calculation for non-initcode data
zeros := uint64(0)

if isIstanbul {
nonZeroCost = 16
}
for i := 0; i < len(payload); i++ {
if payload[i] == 0 {
zeros++
}
}

if (math.MaxUint64-cost)/nonZeroCost < nonZeros {
return 0, ErrIntrinsicGasOverflow
}
nonZeros := uint64(len(payload)) - zeros
nonZeroCost := uint64(68)

cost += nonZeros * nonZeroCost
if isIstanbul {
nonZeroCost = 16
}

if (math.MaxUint64-cost)/4 < zeros {
return 0, ErrIntrinsicGasOverflow
}
if (math.MaxUint64-cost)/nonZeroCost < nonZeros {
return 0, ErrIntrinsicGasOverflow
}

cost += nonZeros * nonZeroCost

cost += zeros * 4
if (math.MaxUint64-cost)/4 < zeros {
return 0, ErrIntrinsicGasOverflow
}

cost += zeros * 4
}
}

return cost, nil
Expand Down
Loading