Skip to content

Commit

Permalink
Merge pull request #200 from 2dvorak/2dvorak/eip7623-calldata-cost
Browse files Browse the repository at this point in the history
Bring geth updates for EIP-7623
  • Loading branch information
blukat29 authored Jan 8, 2025
2 parents 5e1acaf + 677854d commit 2f5633c
Show file tree
Hide file tree
Showing 51 changed files with 245 additions and 192 deletions.
4 changes: 2 additions & 2 deletions accounts/abi/bind/backends/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ func (b *BlockchainContractBackend) callContract(call kaia.CallMsg, block *types
if call.AccessList != nil {
accessList = *call.AccessList
}
intrinsicGas, err := types.IntrinsicGas(call.Data, accessList, nil, call.To == nil, b.bc.Config().Rules(block.Number()))
intrinsicGas, dataTokens, err := types.IntrinsicGas(call.Data, accessList, nil, call.To == nil, b.bc.Config().Rules(block.Number()))
if err != nil {
return nil, err
}

msg := types.NewMessage(call.From, call.To, 0, call.Value, call.Gas, gasPrice, nil, nil, call.Data,
false, intrinsicGas, accessList, nil)
false, intrinsicGas, dataTokens, accessList, nil)

txContext := blockchain.NewEVMTxContext(msg, block.Header(), b.bc.Config())
blockContext := blockchain.NewEVMBlockContext(block.Header(), b.bc, nil)
Expand Down
4 changes: 2 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ func (b *SimulatedBackend) callContract(_ context.Context, call kaia.CallMsg, bl
if call.AccessList != nil {
accessList = *call.AccessList
}
intrinsicGas, _ := types.IntrinsicGas(call.Data, accessList, nil, call.To == nil, b.config.Rules(block.Number()))
msg := types.NewMessage(call.From, call.To, nonce, call.Value, call.Gas, gasPrice, nil, nil, call.Data, true, intrinsicGas, accessList, nil)
intrinsicGas, dataTokens, _ := types.IntrinsicGas(call.Data, accessList, nil, call.To == nil, b.config.Rules(block.Number()))
msg := types.NewMessage(call.From, call.To, nonce, call.Value, call.Gas, gasPrice, nil, nil, call.Data, true, intrinsicGas, dataTokens, accessList, nil)

txContext := blockchain.NewEVMTxContext(msg, block.Header(), b.config)
blockContext := blockchain.NewEVMBlockContext(block.Header(), b.blockchain, nil)
Expand Down
8 changes: 4 additions & 4 deletions api/api_ethereum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1413,11 +1413,11 @@ func EthDoCall(ctx context.Context, b Backend, args EthTransactionArgs, blockNrO
} else {
baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
}
intrinsicGas, err := types.IntrinsicGas(args.data(), args.GetAccessList(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
intrinsicGas, dataTokens, err := types.IntrinsicGas(args.data(), args.GetAccessList(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
if err != nil {
return nil, err
}
msg, err := args.ToMessage(globalGasCap, baseFee, intrinsicGas)
msg, err := args.ToMessage(globalGasCap, baseFee, intrinsicGas, dataTokens)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1570,11 +1570,11 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
precompiles := vm.ActivePrecompiles(rules)

toMsg := func() (*types.Transaction, error) {
intrinsicGas, err := types.IntrinsicGas(args.data(), nil, nil, args.To == nil, rules)
intrinsicGas, dataTokens, err := types.IntrinsicGas(args.data(), nil, nil, args.To == nil, rules)
if err != nil {
return nil, err
}
return args.ToMessage(gasCap, header.BaseFee, intrinsicGas)
return args.ToMessage(gasCap, header.BaseFee, intrinsicGas, dataTokens)
}

if args.Gas == nil {
Expand Down
8 changes: 4 additions & 4 deletions api/api_public_blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
// this makes sure resources are cleaned up.
defer cancel()

intrinsicGas, err := types.IntrinsicGas(args.InputData(), args.GetAccessList(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
intrinsicGas, dataTokens, err := types.IntrinsicGas(args.InputData(), args.GetAccessList(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
if err != nil {
return nil, 0, err
}
Expand All @@ -344,7 +344,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
} else {
baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
}
msg, err := args.ToMessage(globalGasCap.Uint64(), baseFee, intrinsicGas)
msg, err := args.ToMessage(globalGasCap.Uint64(), baseFee, intrinsicGas, dataTokens)
if err != nil {
return nil, 0, err
}
Expand Down Expand Up @@ -694,7 +694,7 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *pa
return nil
}

func (args *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64) (*types.Transaction, error) {
func (args *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64, dataTokens uint64) (*types.Transaction, error) {
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} else if args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil {
Expand Down Expand Up @@ -742,5 +742,5 @@ func (args *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsic
if args.AccessList != nil {
accessList = *args.AccessList
}
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, args.InputData(), false, intrinsicGas, accessList, nil), nil
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, args.InputData(), false, intrinsicGas, dataTokens, accessList, nil), nil
}
4 changes: 2 additions & 2 deletions api/tx_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ func (args *EthTransactionArgs) setDefaults(ctx context.Context, b Backend) erro
}

// ToMessage change EthTransactionArgs to types.Transaction in Kaia.
func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64) (*types.Transaction, error) {
func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64, dataTokens uint64) (*types.Transaction, error) {
// Reject invalid combinations of pre- and post-1559 fee styles
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
Expand Down Expand Up @@ -780,7 +780,7 @@ func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int,
if args.AccessList != nil {
accessList = *args.AccessList
}
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, false, intrinsicGas, accessList, nil), nil
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, false, intrinsicGas, dataTokens, accessList, nil), nil
}

// toTransaction converts the arguments to a transaction.
Expand Down
2 changes: 1 addition & 1 deletion blockchain/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := types.IntrinsicGas(data, nil, nil, false, params.TestChainConfig.Rules(big.NewInt(0)))
gas, _, _ := types.IntrinsicGas(data, nil, nil, false, params.TestChainConfig.Rules(big.NewInt(0)))
signer := types.LatestSignerForChainID(params.TestChainConfig.ChainID)
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), signer, benchRootKey)
gen.AddTx(tx)
Expand Down
12 changes: 6 additions & 6 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1461,8 +1461,8 @@ func TestAccessListTx(t *testing.T) {
b.SetRewardbase(common.Address{1})

// One transaction to 0xAAAA
intrinsicGas, _ := types.IntrinsicGas([]byte{}, list, nil, false, gspec.Config.Rules(block.Number()))
tx, _ := types.SignTx(types.NewMessage(senderAddr, &contractAddr, senderNonce, big.NewInt(0), 30000, big.NewInt(1), nil, nil, []byte{}, false, intrinsicGas, list, nil), signer, senderKey)
intrinsicGas, dataTokens, _ := types.IntrinsicGas([]byte{}, list, nil, false, gspec.Config.Rules(block.Number()))
tx, _ := types.SignTx(types.NewMessage(senderAddr, &contractAddr, senderNonce, big.NewInt(0), 30000, big.NewInt(1), nil, nil, []byte{}, false, intrinsicGas, dataTokens, list, nil), signer, senderKey)
b.AddTx(tx)
})
if n, err := chain.InsertChain(blocks); err != nil {
Expand Down Expand Up @@ -2345,13 +2345,13 @@ func TestEIP7702(t *testing.T) {
b.SetRewardbase(common.Address{1})

authorizationList := []types.Authorization{*auth1, *auth2}
intrinsicGas, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
intrinsicGas, dataTokens, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
if err != nil {
t.Fatalf("failed to run intrinsic gas: %v", err)
}

tx, err := types.SignTx(types.NewMessage(addr1, &addr1, uint64(0), nil, 500000, nil, newGkei(50),
big.NewInt(20), nil, false, intrinsicGas, nil, authorizationList), signer, key1)
big.NewInt(20), nil, false, intrinsicGas, dataTokens, nil, authorizationList), signer, key1)
if err != nil {
t.Fatalf("failed to sign tx: %v", err)
}
Expand Down Expand Up @@ -2426,13 +2426,13 @@ func TestEIP7702(t *testing.T) {
}, key1)

authorizationList := []types.Authorization{*authForEmpty}
intrinsicGas, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
intrinsicGas, dataTokens, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
if err != nil {
t.Fatalf("failed to run intrinsic gas: %v", err)
}

tx, err := types.SignTx(types.NewMessage(addr1, &addr1, state.GetNonce(addr1), nil, 500000, nil, newGkei(50),
big.NewInt(20), nil, false, intrinsicGas, nil, authorizationList), signer, key1)
big.NewInt(20), nil, false, intrinsicGas, dataTokens, nil, authorizationList), signer, key1)
if err != nil {
t.Fatalf("failed to sign tx: %v", err)
}
Expand Down
4 changes: 4 additions & 0 deletions blockchain/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ var (
// than required to start the invocation.
ErrIntrinsicGas = errors.New("intrinsic gas too low")

// ErrDataFloorGas is returned if the transaction is specified to use less gas
// than required for the data floor cost.
ErrDataFloorGas = errors.New("insufficient gas for data floor cost")

// ErrGasLimit is returned if a transaction's requested gas limit exceeds the
// maximum allowance of the current block.
ErrGasLimit = errors.New("exceeds block gas limit")
Expand Down
3 changes: 2 additions & 1 deletion blockchain/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func ProcessParentBlockHash(header *types.Header, vmenv *vm.EVM, statedb vm.Stat
gasLimit = uint64(30_000_000)
)

intrinsicGas, err := types.IntrinsicGas(data, nil, nil, false, rules)
intrinsicGas, dataTokens, err := types.IntrinsicGas(data, nil, nil, false, rules)
if err != nil {
return err
}
Expand All @@ -129,6 +129,7 @@ func ProcessParentBlockHash(header *types.Header, vmenv *vm.EVM, statedb vm.Stat
data,
false,
intrinsicGas,
dataTokens,
nil,
nil,
)
Expand Down
42 changes: 35 additions & 7 deletions blockchain/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package blockchain
import (
"errors"
"fmt"
"math"
"math/big"

"github.com/kaiachain/kaia/blockchain/types"
Expand Down Expand Up @@ -83,7 +84,7 @@ type Message interface {

// ValidatedIntrinsicGas returns the intrinsic gas of the transaction.
// The returned intrinsic gas should be derived by calling AsMessageAccountKeyPicker().
ValidatedIntrinsicGas() uint64
ValidatedIntrinsicGas() *types.ValidatedIntrinsicGas

// FeeRatio returns a ratio of tx fee paid by the fee payer in percentage.
// For example, if it is 30, 30% of tx fee will be paid by the fee payer.
Expand Down Expand Up @@ -111,7 +112,7 @@ type Message interface {

// IntrinsicGas returns `intrinsic gas` based on the tx type.
// This value is used to differentiate tx fee based on the tx type.
IntrinsicGas(currentBlockNumber uint64) (uint64, error)
IntrinsicGas(currentBlockNumber uint64) (uint64, uint64, error)

// Type returns the transaction type of the message.
Type() types.TxType
Expand Down Expand Up @@ -345,19 +346,27 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}

// Check clauses 4-5, subtract intrinsic gas if everything is correct
amount := msg.ValidatedIntrinsicGas()
if st.gas < amount {
validatedGas := msg.ValidatedIntrinsicGas()
if st.gas < validatedGas.Gas {
return nil, ErrIntrinsicGas
}
st.gas -= amount
rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)
if rules.IsPrague {
floorGas, err := FloorDataGas(validatedGas.Tokens)
if err != nil {
return nil, err
}
if st.gas < floorGas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gas, floorGas)
}
}
st.gas -= validatedGas.Gas

// Check clause 6
if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.ValidatedSender(), msg.Value()) {
return nil, vm.ErrInsufficientBalance
}

rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)

// Verify authorization list is not empty.
if msg.AuthorizationList() != nil && len(msg.AuthorizationList()) == 0 {
return nil, fmt.Errorf("%w: address %v", ErrEmptyAuthList, msg.ValidatedSender())
Expand Down Expand Up @@ -408,6 +417,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, vm.ErrTotalTimeLimitReached
}

if rules.IsPrague {
// After EIP-7623: Data-heavy transactions pay the floor gas.
// Overflow error has already been checked and can be ignored here.
floorGas, _ := FloorDataGas(validatedGas.Tokens)
if st.gasUsed() < floorGas {
st.gas = st.initialGas - floorGas
}
}

if rules.IsKore {
// After EIP-3529: refunds are capped to gasUsed / 5
st.refundGas(params.RefundQuotientEIP3529)
Expand Down Expand Up @@ -582,3 +600,13 @@ func (st *StateTransition) processAuthorizationList(authList types.Authorization
}
}
}

// FloorDataGas calculates the minimum gas required for a transaction
// based on its data tokens (EIP-7623).
func FloorDataGas(tokens uint64) (uint64, error) {
// Check for overflow
if (math.MaxUint64-params.TxGas)/params.CostFloorPerToken7623 < tokens {
return 0, types.ErrGasUintOverflow
}
return params.TxGas + tokens*params.CostFloorPerToken7623, nil
}
3 changes: 2 additions & 1 deletion blockchain/system/multicall.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func (caller *ContractCallerForMultiCall) CallContract(ctx context.Context, call
gasPrice := big.NewInt(0) // execute call regardless of the balance of the sender
gasLimit := uint64(1e8) // enough gas limit to execute multicall contract functions
intrinsicGas := uint64(0) // read operation doesn't require intrinsicGas
dataTokens := uint64(0) // read operation doesn't require intrinsicGas

// call.From: zero address will be assigned if nothing is specified
// call.To: the target contract address will be assigned by `BoundContract`
Expand All @@ -63,7 +64,7 @@ func (caller *ContractCallerForMultiCall) CallContract(ctx context.Context, call
}

msg := types.NewMessage(call.From, call.To, caller.state.GetNonce(call.From),
call.Value, gasLimit, gasPrice, nil, nil, call.Data, false, intrinsicGas, nil, nil)
call.Value, gasLimit, gasPrice, nil, nil, call.Data, false, intrinsicGas, dataTokens, nil, nil)

blockContext := blockchain.NewEVMBlockContext(caller.header, caller.chain, nil)
txContext := blockchain.NewEVMTxContext(msg, caller.header, caller.chain.Config())
Expand Down
3 changes: 2 additions & 1 deletion blockchain/system/rebalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ func (caller *Kip103ContractCaller) CallContract(ctx context.Context, call kaia.
gasPrice := big.NewInt(0) // execute call regardless of the balance of the sender
gasLimit := uint64(1e8) // enough gas limit to execute kip103 contract functions
intrinsicGas := uint64(0) // read operation doesn't require intrinsicGas
dataTokens := uint64(0) // read operation doesn't require intrinsicGas

// call.From: zero address will be assigned if nothing is specified
// call.To: the target contract address will be assigned by `BoundContract`
Expand All @@ -122,7 +123,7 @@ func (caller *Kip103ContractCaller) CallContract(ctx context.Context, call kaia.
// return nil, err
//}
msg := types.NewMessage(call.From, call.To, caller.state.GetNonce(call.From),
call.Value, gasLimit, gasPrice, nil, nil, call.Data, false, intrinsicGas, nil, nil)
call.Value, gasLimit, gasPrice, nil, nil, call.Data, false, intrinsicGas, dataTokens, nil, nil)

blockContext := blockchain.NewEVMBlockContext(caller.header, caller.chain, nil)
txContext := blockchain.NewEVMTxContext(msg, caller.header, caller.chain.Config())
Expand Down
12 changes: 11 additions & 1 deletion blockchain/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +836,24 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
}
}

intrGas, err := tx.IntrinsicGas(pool.currentBlockNumber)
intrGas, dataTokens, err := tx.IntrinsicGas(pool.currentBlockNumber)
intrGas += gasFrom + gasFeePayer
if err != nil {
return err
}
if tx.Gas() < intrGas {
return ErrIntrinsicGas
}
// Ensure the transaction can cover floor data gas.
if pool.rules.IsPrague {
floorGas, err := FloorDataGas(dataTokens)
if err != nil {
return err
}
if tx.Gas() < floorGas {
return fmt.Errorf("%w: gas %v, minimum needed %v", ErrDataFloorGas, tx.Gas(), floorGas)
}
}

// "tx.Validate()" conducts additional validation for each new txType.
// Validate humanReadable address when this tx has "true" in the humanReadable field.
Expand Down
Loading

0 comments on commit 2f5633c

Please sign in to comment.