From 3cecc4339151e7cedbdd570e8a07fbbab2c53501 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:23:41 +0900 Subject: [PATCH 1/8] Fix gas calcuation for EIP-7623 and its tests --- blockchain/state_transition.go | 36 +++--- blockchain/tx_pool.go | 10 +- blockchain/types/transaction.go | 32 ++++-- blockchain/types/tx_internal_data.go | 58 ++++++++++ tests/tx_gas_calculation_test.go | 166 +++++++++++++-------------- tests/tx_gas_overflow_test.go | 44 +++---- 6 files changed, 212 insertions(+), 134 deletions(-) diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index 6f42eab81..1e4bbafd0 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -75,16 +75,16 @@ type StateTransition struct { // Message represents a message sent to a contract. type Message interface { // ValidatedSender returns the sender of the transaction. - // The returned sender should be derived by calling AsMessageAccountKeyPicker(). + // It should be set by calling AsMessageAccountKeyPicker(). ValidatedSender() common.Address // ValidatedFeePayer returns the fee payer of the transaction. - // The returned fee payer should be derived by calling AsMessageAccountKeyPicker(). + // It should be set by calling AsMessageAccountKeyPicker(). ValidatedFeePayer() common.Address - // ValidatedIntrinsicGas returns the intrinsic gas of the transaction. - // The returned intrinsic gas should be derived by calling AsMessageAccountKeyPicker(). - ValidatedIntrinsicGas() *types.ValidatedIntrinsicGas + // ValidatedGas holds the intrinsic gas, sig validation gas, and number of data tokens for the transaction. + // It should be set by calling AsMessageAccountKeyPicker(). + ValidatedGas() *types.ValidatedGas // 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. @@ -346,21 +346,25 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } // Check clauses 4-5, subtract intrinsic gas if everything is correct - validatedGas := msg.ValidatedIntrinsicGas() - if st.gas < validatedGas.Gas { + validatedGas := msg.ValidatedGas() + if st.gas < validatedGas.IntrinsicGas+validatedGas.SigValidateGas { return nil, ErrIntrinsicGas } rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber) if rules.IsPrague { - floorGas, err := FloorDataGas(validatedGas.Tokens) + floorGas, err := FloorDataGas(st.msg.Type(), validatedGas.Tokens) if err != nil { return nil, err } + // Some of Kaia's tx type has sig validation gas. + // The sig validation gas is not included in the floor gas comparison, + // however we need to check if the gas is enough to pay the sig validation gas too. + floorGas += validatedGas.SigValidateGas if st.gas < floorGas { return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gas, floorGas) } } - st.gas -= validatedGas.Gas + st.gas -= (validatedGas.IntrinsicGas + validatedGas.SigValidateGas) // Check clause 6 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.ValidatedSender(), msg.Value()) { @@ -432,7 +436,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 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) + floorGas, _ := FloorDataGas(st.msg.Type(), validatedGas.Tokens) + // Remember that the sig validation gas is included in used gas. + // So we need to add it to the floor gas to make sure the floor gas comparison is correct. + floorGas += validatedGas.SigValidateGas if st.gasUsed() < floorGas { st.gas = st.initialGas - floorGas } @@ -624,10 +631,13 @@ func (st *StateTransition) gasUsed() uint64 { // FloorDataGas calculates the minimum gas required for a transaction // based on its data tokens (EIP-7623). -func FloorDataGas(tokens uint64) (uint64, error) { +func FloorDataGas(txType types.TxType, tokens uint64) (uint64, error) { // Check for overflow - if (math.MaxUint64-params.TxGas)/params.CostFloorPerToken7623 < tokens { + // Instead of using parmas.TxGas, we should consider the tx type + // because Kaia tx type has different tx gas (e.g., fee delegated tx). + txGas := types.GetTxGasForTxType(txType) + if (math.MaxUint64-txGas)/params.CostFloorPerToken7623 < tokens { return 0, types.ErrGasUintOverflow } - return params.TxGas + tokens*params.CostFloorPerToken7623, nil + return txGas + tokens*params.CostFloorPerToken7623, nil } diff --git a/blockchain/tx_pool.go b/blockchain/tx_pool.go index 7c3d748fc..bf0e74737 100644 --- a/blockchain/tx_pool.go +++ b/blockchain/tx_pool.go @@ -837,19 +837,23 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { } intrGas, dataTokens, err := tx.IntrinsicGas(pool.currentBlockNumber) - intrGas += gasFrom + gasFeePayer + sigValGas := gasFrom + gasFeePayer if err != nil { return err } - if tx.Gas() < intrGas { + if tx.Gas() < intrGas+sigValGas { return ErrIntrinsicGas } // Ensure the transaction can cover floor data gas. if pool.rules.IsPrague { - floorGas, err := FloorDataGas(dataTokens) + floorGas, err := FloorDataGas(tx.Type(), dataTokens) if err != nil { return err } + // Some of Kaia's tx type has sig validation gas. + // The sig validation gas is not included in the floor gas comparison, + // however we need to check if the gas is enough to pay the sig validation gas too. + floorGas += sigValGas if tx.Gas() < floorGas { return fmt.Errorf("%w: gas %v, minimum needed %v", ErrDataFloorGas, tx.Gas(), floorGas) } diff --git a/blockchain/types/transaction.go b/blockchain/types/transaction.go index 488c444ea..93f63f6a1 100644 --- a/blockchain/types/transaction.go +++ b/blockchain/types/transaction.go @@ -72,9 +72,17 @@ func ErrFeePayer(err error) error { return fmt.Errorf("invalid fee payer: %s", err) } -type ValidatedIntrinsicGas struct { - Gas uint64 - Tokens uint64 +// ValidatedGas holds the intrinsic gas, sig validation gas, and data tokens. +// - Intrinsic gas is the gas for the tx type + data. +// After Prague, floor gas would be used if intrinsic gas < floor gas. +// - Sig validation gas is the gas for validating sender and feePayer. +// It is related to Kaia-specific tx types, so it is not part of the floor gas comparison. +// - Tokens is the number of tokens for the data. +// It is used for the floor gas calculation. +type ValidatedGas struct { + IntrinsicGas uint64 + SigValidateGas uint64 + Tokens uint64 } type Transaction struct { @@ -93,9 +101,9 @@ type Transaction struct { // validatedFeePayer represents the fee payer of the transaction to be used for ApplyTransaction(). // This value is set in AsMessageWithAccountKeyPicker(). validatedFeePayer common.Address - // validatedIntrinsicGas represents intrinsic gas of the transaction to be used for ApplyTransaction(). + // validatedGas holds intrinsic gas, sig validation gas, and number of tokens for the transaction to be used for ApplyTransaction(). // This value is set in AsMessageWithAccountKeyPicker(). - validatedIntrinsicGas *ValidatedIntrinsicGas + validatedGas *ValidatedGas // The account's nonce is checked only if `checkNonce` is true. checkNonce bool // This value is set when the tx is invalidated in block tx validation, and is used to remove pending tx in txPool. @@ -390,10 +398,10 @@ func (tx *Transaction) ValidatedFeePayer() common.Address { return tx.validatedFeePayer } -func (tx *Transaction) ValidatedIntrinsicGas() *ValidatedIntrinsicGas { +func (tx *Transaction) ValidatedGas() *ValidatedGas { tx.mu.RLock() defer tx.mu.RUnlock() - return tx.validatedIntrinsicGas + return tx.validatedGas } func (tx *Transaction) MakeRPCOutput() map[string]interface{} { return tx.data.MakeRPCOutput() } func (tx *Transaction) GetTxInternalData() TxInternalData { return tx.data } @@ -612,7 +620,7 @@ func (tx *Transaction) AsMessageWithAccountKeyPicker(s Signer, picker AccountKey } tx.mu.Lock() - tx.validatedIntrinsicGas = &ValidatedIntrinsicGas{Gas: intrinsicGas + gasFrom + gasFeePayer, Tokens: dataTokens} + tx.validatedGas = &ValidatedGas{IntrinsicGas: intrinsicGas, SigValidateGas: gasFrom + gasFeePayer, Tokens: dataTokens} tx.mu.Unlock() return tx, err @@ -1086,10 +1094,10 @@ func (t *TransactionsByPriceAndNonce) Clear() { // NewMessage returns a `*Transaction` object with the given arguments. func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice, gasFeeCap, gasTipCap *big.Int, data []byte, checkNonce bool, intrinsicGas uint64, dataTokens uint64, list AccessList, auth []SetCodeAuthorization) *Transaction { transaction := &Transaction{ - validatedIntrinsicGas: &ValidatedIntrinsicGas{Gas: intrinsicGas, Tokens: dataTokens}, - validatedFeePayer: from, - validatedSender: from, - checkNonce: checkNonce, + validatedGas: &ValidatedGas{IntrinsicGas: intrinsicGas, SigValidateGas: 0, Tokens: dataTokens}, + validatedFeePayer: from, + validatedSender: from, + checkNonce: checkNonce, } // Call supports EthereumAccessList, EthereumSetCode and Legacy txTypes only. diff --git a/blockchain/types/tx_internal_data.go b/blockchain/types/tx_internal_data.go index dbc038732..9cafd2cab 100644 --- a/blockchain/types/tx_internal_data.go +++ b/blockchain/types/tx_internal_data.go @@ -697,6 +697,64 @@ func IntrinsicGas(data []byte, accessList AccessList, authorizationList []SetCod return gasPayloadWithGas, tokens, nil } +func GetTxGasForTxType(txType TxType) uint64 { + switch txType { + case TxTypeLegacyTransaction: + return params.TxGas + case TxTypeValueTransfer: + return params.TxGasValueTransfer + case TxTypeFeeDelegatedValueTransfer: + return params.TxGasValueTransfer + params.TxGasFeeDelegated + case TxTypeFeeDelegatedValueTransferWithRatio: + return params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio + case TxTypeValueTransferMemo: + return params.TxGasValueTransfer + case TxTypeFeeDelegatedValueTransferMemo: + return params.TxGasValueTransfer + params.TxGasFeeDelegated + case TxTypeFeeDelegatedValueTransferMemoWithRatio: + return params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio + case TxTypeAccountCreation: + return params.TxGasAccountCreation + case TxTypeAccountUpdate: + return params.TxGasAccountUpdate + case TxTypeFeeDelegatedAccountUpdate: + return params.TxGasAccountUpdate + params.TxGasFeeDelegated + case TxTypeFeeDelegatedAccountUpdateWithRatio: + return params.TxGasAccountUpdate + params.TxGasFeeDelegatedWithRatio + case TxTypeSmartContractDeploy: + return params.TxGasContractCreation + case TxTypeFeeDelegatedSmartContractDeploy: + return params.TxGasContractCreation + params.TxGasFeeDelegated + case TxTypeFeeDelegatedSmartContractDeployWithRatio: + return params.TxGasContractCreation + params.TxGasFeeDelegatedWithRatio + case TxTypeSmartContractExecution: + return params.TxGasContractExecution + case TxTypeFeeDelegatedSmartContractExecution: + return params.TxGasContractExecution + params.TxGasFeeDelegated + case TxTypeFeeDelegatedSmartContractExecutionWithRatio: + return params.TxGasContractExecution + params.TxGasFeeDelegatedWithRatio + case TxTypeCancel: + return params.TxGasCancel + case TxTypeFeeDelegatedCancel: + return params.TxGasCancel + params.TxGasFeeDelegated + case TxTypeFeeDelegatedCancelWithRatio: + return params.TxGasCancel + params.TxGasFeeDelegatedWithRatio + case TxTypeChainDataAnchoring: + return params.TxChainDataAnchoringGas + case TxTypeFeeDelegatedChainDataAnchoring: + return params.TxChainDataAnchoringGas + params.TxGasFeeDelegated + case TxTypeFeeDelegatedChainDataAnchoringWithRatio: + return params.TxChainDataAnchoringGas + params.TxGasFeeDelegatedWithRatio + case TxTypeEthereumAccessList: + return params.TxGas + case TxTypeEthereumDynamicFee: + return params.TxGas + case TxTypeEthereumSetCode: + return params.TxGas + } + panic("unexpected tx type: " + txType.String()) +} + // CalcFeeWithRatio returns feePayer's fee and sender's fee based on feeRatio. // For example, if fee = 100 and feeRatio = 30, feePayer = 30 and feeSender = 70. func CalcFeeWithRatio(feeRatio FeeRatio, fee *big.Int) (*big.Int, *big.Int) { diff --git a/tests/tx_gas_calculation_test.go b/tests/tx_gas_calculation_test.go index e88151591..5680cb62b 100644 --- a/tests/tx_gas_calculation_test.go +++ b/tests/tx_gas_calculation_test.go @@ -19,6 +19,7 @@ package tests import ( + "bytes" "crypto/ecdsa" "math/big" "strings" @@ -26,6 +27,7 @@ import ( "time" "github.com/kaiachain/kaia/accounts/abi" + "github.com/kaiachain/kaia/blockchain" "github.com/kaiachain/kaia/blockchain/types" "github.com/kaiachain/kaia/blockchain/types/accountkey" "github.com/kaiachain/kaia/common" @@ -103,7 +105,7 @@ func TestGasCalculation(t *testing.T) { // Initialize blockchain start := time.Now() - bcdata, err := NewBCDataWithForkConfig(6, 4, Forks["Shanghai"]) + bcdata, err := NewBCDataWithForkConfig(6, 4, Forks["Prague"]) assert.Equal(t, nil, err) prof.Profile("main_init_blockchain", time.Now().Sub(start)) @@ -272,7 +274,6 @@ func TestGasCalculation(t *testing.T) { }) } } - } } } @@ -287,7 +288,7 @@ func testGasValidation(t *testing.T, bcdata *BCData, tx *types.Transaction, vali } func genLegacyTransaction(t *testing.T, signer types.Signer, from TestAccount, to TestAccount, payer TestAccount, gasPrice *big.Int) (*types.Transaction, uint64) { - intrinsic := getIntrinsicGas(types.TxTypeLegacyTransaction) + intrinsic := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) amount := big.NewInt(100000) tx := types.NewTransaction(from.GetNonce(), to.GetAddr(), amount, gasLimit, gasPrice, []byte{}) @@ -666,10 +667,11 @@ func genFeeDelegatedWithRatioChainDataAnchoring(t *testing.T, signer types.Signe // Generate map functions func genMapForLegacyTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getFlooredGas(data, getDataGas(data)) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -682,17 +684,51 @@ func genMapForLegacyTransaction(from TestAccount, to TestAccount, gasPrice *big. return values, intrinsic + gasPayload } +func getDataGasNoFloor(data []byte) uint64 { + z := uint64(bytes.Count(data, []byte{0})) + nz := uint64(len(data)) - z + return nz*params.TxDataNonZeroGasEIP2028 + z*params.TxDataZeroGas +} + +func getDataGas(data []byte) uint64 { + z := uint64(bytes.Count(data, []byte{0})) + nz := uint64(len(data)) - z + return nz*params.TxDataNonZeroGasEIP2028 + z*params.TxDataZeroGas + /* + tokens := nz*params.TokenPerNonZeroByte7623 + z + gas := nz*params.TxDataNonZeroGasEIP2028 + z*params.TxDataZeroGas + if gas < tokens*params.CostFloorPerToken7623 { + return tokens * params.CostFloorPerToken7623 + } + return gas*/ +} + +func getFlooredGas(data []byte, gas uint64) uint64 { + z := uint64(bytes.Count(data, []byte{0})) + nz := uint64(len(data)) - z + tokens := nz*params.TokenPerNonZeroByte7623 + z + floorGas := tokens * params.CostFloorPerToken7623 + if gas < floorGas { + return floorGas + } + return gas +} + func genMapForAccessListTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getDataGas(data) + accessList := types.AccessList{{Address: common.HexToAddress("0x0000000000000000000000000000000000000001"), StorageKeys: []common.Hash{{0}}}} toAddress := to.GetAddr() gasPayload += uint64(len(accessList)) * params.TxAccessListAddressGas gasPayload += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas + gasPayload = getFlooredGas(data, gasPayload) + values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), types.TxValueKeyTo: &toAddress, @@ -707,16 +743,19 @@ func genMapForAccessListTransaction(from TestAccount, to TestAccount, gasPrice * } func genMapForDynamicFeeTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getDataGas(data) accessList := types.AccessList{{Address: common.HexToAddress("0x0000000000000000000000000000000000000001"), StorageKeys: []common.Hash{{0}}}} toAddress := to.GetAddr() gasPayload += uint64(len(accessList)) * params.TxAccessListAddressGas gasPayload += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas + gasPayload = getFlooredGas(data, gasPayload) + values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), types.TxValueKeyTo: &toAddress, @@ -732,10 +771,11 @@ func genMapForDynamicFeeTransaction(from TestAccount, to TestAccount, gasPrice * } func genMapForSetCodeTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getDataGas(data) accessList := types.AccessList{{Address: common.HexToAddress("0x0000000000000000000000000000000000000001"), StorageKeys: []common.Hash{{0}}}} authorizationList := []types.SetCodeAuthorization{{ChainID: uint64(1), Address: common.HexToAddress("0x0000000000000000000000000000000000000001"), Nonce: 1, V: uint8(0), R: big.NewInt(0), S: big.NewInt(0)}} toAddress := to.GetAddr() @@ -744,6 +784,8 @@ func genMapForSetCodeTransaction(from TestAccount, to TestAccount, gasPrice *big gasPayload += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas gasPayload += uint64(len(authorizationList)) * params.CallNewAccountGas + gasPayload = getFlooredGas(data, gasPayload) + values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), types.TxValueKeyTo: toAddress, @@ -760,7 +802,7 @@ func genMapForSetCodeTransaction(from TestAccount, to TestAccount, gasPrice *big } func genMapForValueTransfer(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) values := map[types.TxValueKeyType]interface{}{ @@ -775,7 +817,7 @@ func genMapForValueTransfer(from TestAccount, to TestAccount, gasPrice *big.Int, } func genMapForValueTransferWithMemo(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) nonZeroData := []byte{1, 2, 3, 4} zeroData := []byte{0, 0, 0, 0} @@ -794,13 +836,14 @@ func genMapForValueTransferWithMemo(from TestAccount, to TestAccount, gasPrice * types.TxValueKeyData: data, } - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getFlooredGas(data, getDataGas(data)) return values, intrinsic + gasPayload } func genMapForCreate(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) amount := big.NewInt(0) values := map[types.TxValueKeyType]interface{}{ @@ -817,7 +860,7 @@ func genMapForCreate(from TestAccount, to TestAccount, gasPrice *big.Int, txType } func genMapForUpdate(from TestAccount, to TestAccount, gasPrice *big.Int, newKeys accountkey.AccountKey, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -843,14 +886,19 @@ func genMapForDeploy(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxValueKeyTo: (*common.Address)(nil), } - intrinsicGas := getIntrinsicGas(txType) + intrinsicGas := types.GetTxGasForTxType(txType) intrinsicGas += uint64(0x175fd) - // TODO-Kaia: Add test for EIP-7623 - gasPayloadWithGas, _, err := types.IntrinsicGasPayload(intrinsicGas, common.FromHex(code), true, params.Rules{IsIstanbul: true, IsShanghai: true}) + gasPayloadWithGas, dataTokens, err := types.IntrinsicGasPayload(intrinsicGas, common.FromHex(code), true, params.Rules{IsIstanbul: true, IsShanghai: true, IsPrague: true}) if err != nil { return nil, 0 } + floorGas, _ := blockchain.FloorDataGas(types.TxTypeSmartContractDeploy, dataTokens) + // Tx Gas is included in the gasPayloadWithGas, so we need to add it to the floorGas for correct comparison. + floorGas += types.GetTxGasForTxType(txType) + if gasPayloadWithGas < floorGas { + gasPayloadWithGas = floorGas + } return values, gasPayloadWithGas } @@ -879,20 +927,28 @@ func genMapForExecution(from TestAccount, to TestAccount, gasPrice *big.Int, txT types.TxValueKeyData: data, } - intrinsicGas := getIntrinsicGas(txType) + intrinsicGas := types.GetTxGasForTxType(txType) intrinsicGas += uint64(0x9ec4) - // TODO-Kaia: Add test for EIP-7623 - gasPayloadWithGas, _, err := types.IntrinsicGasPayload(intrinsicGas, data, false, params.Rules{IsShanghai: false}) + gasPayloadWithGas, dataTokens, err := types.IntrinsicGasPayload(intrinsicGas, data, false, params.Rules{IsShanghai: false, IsPrague: true}) + if err != nil { + return nil, 0 + } + floorGas, err := blockchain.FloorDataGas(txType, dataTokens) if err != nil { return nil, 0 } + // Tx Gas is included in the gasPayloadWithGas, so we need to add it to the floorGas for correct comparison. + floorGas += types.GetTxGasForTxType(txType) + if gasPayloadWithGas < floorGas { + gasPayloadWithGas = floorGas + } return values, gasPayloadWithGas } func genMapForCancel(from TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -904,9 +960,10 @@ func genMapForCancel(from TestAccount, gasPrice *big.Int, txType types.TxType) ( } func genMapForChainDataAnchoring(from TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := getIntrinsicGas(txType) + intrinsic := types.GetTxGasForTxType(txType) data := []byte{0x11, 0x22} - gasPayload := uint64(len(data)) * params.TxDataGas + // We have changed the gas calcuation since Prague per EIP-7623. + gasPayload := getFlooredGas(data, getDataGas(data)) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -1060,65 +1117,6 @@ func genMultiSigParamForRoleBased(t *testing.T) []TestCreateMultisigAccountParam return params } -func getIntrinsicGas(txType types.TxType) uint64 { - var intrinsic uint64 - - switch txType { - case types.TxTypeLegacyTransaction: - intrinsic = params.TxGas - case types.TxTypeEthereumAccessList: - intrinsic = params.TxGas - case types.TxTypeEthereumDynamicFee: - intrinsic = params.TxGas - case types.TxTypeEthereumSetCode: - intrinsic = params.TxGas - case types.TxTypeValueTransfer: - intrinsic = params.TxGasValueTransfer - case types.TxTypeFeeDelegatedValueTransfer: - intrinsic = params.TxGasValueTransfer + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedValueTransferWithRatio: - intrinsic = params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio - case types.TxTypeValueTransferMemo: - intrinsic = params.TxGasValueTransfer - case types.TxTypeFeeDelegatedValueTransferMemo: - intrinsic = params.TxGasValueTransfer + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedValueTransferMemoWithRatio: - intrinsic = params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio - case types.TxTypeAccountUpdate: - intrinsic = params.TxGasAccountUpdate - case types.TxTypeFeeDelegatedAccountUpdate: - intrinsic = params.TxGasAccountUpdate + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedAccountUpdateWithRatio: - intrinsic = params.TxGasAccountUpdate + params.TxGasFeeDelegatedWithRatio - case types.TxTypeSmartContractDeploy: - intrinsic = params.TxGasContractCreation - case types.TxTypeFeeDelegatedSmartContractDeploy: - intrinsic = params.TxGasContractCreation + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedSmartContractDeployWithRatio: - intrinsic = params.TxGasContractCreation + params.TxGasFeeDelegatedWithRatio - case types.TxTypeSmartContractExecution: - intrinsic = params.TxGasContractExecution - case types.TxTypeFeeDelegatedSmartContractExecution: - intrinsic = params.TxGasContractExecution + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedSmartContractExecutionWithRatio: - intrinsic = params.TxGasContractExecution + params.TxGasFeeDelegatedWithRatio - case types.TxTypeChainDataAnchoring: - intrinsic = params.TxChainDataAnchoringGas - case types.TxTypeFeeDelegatedChainDataAnchoring: - intrinsic = params.TxChainDataAnchoringGas + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedChainDataAnchoringWithRatio: - intrinsic = params.TxChainDataAnchoringGas + params.TxGasFeeDelegatedWithRatio - case types.TxTypeCancel: - intrinsic = params.TxGasCancel - case types.TxTypeFeeDelegatedCancel: - intrinsic = params.TxGasCancel + params.TxGasFeeDelegated - case types.TxTypeFeeDelegatedCancelWithRatio: - intrinsic = params.TxGasCancel + params.TxGasFeeDelegatedWithRatio - } - - return intrinsic -} - // Implement TestAccount interface for TestAccountType func (t *TestAccountType) GetAddr() common.Address { return t.Addr diff --git a/tests/tx_gas_overflow_test.go b/tests/tx_gas_overflow_test.go index 5b278c72b..38b276c83 100644 --- a/tests/tx_gas_overflow_test.go +++ b/tests/tx_gas_overflow_test.go @@ -74,7 +74,7 @@ func TestGasOverflow(t *testing.T) { } func testGasOverflowLegacyTransaction(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeLegacyTransaction) + intrinsic := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataNonZeroGasFrontier) @@ -84,14 +84,14 @@ func testGasOverflowLegacyTransaction(t *testing.T) { } func testGasOverflowValueTransfer(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeValueTransfer) + intrinsic := types.GetTxGasForTxType(types.TxTypeValueTransfer) senderValidationGas := getMaxValidationKeyGas(t) addUint64(t, intrinsic, senderValidationGas) } func testGasOverflowFeeDelegatedValueTransfer(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedValueTransfer) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransfer) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -100,7 +100,7 @@ func testGasOverflowFeeDelegatedValueTransfer(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioValueTransfer(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedValueTransferWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -109,7 +109,7 @@ func testGasOverflowFeeDelegatedWithRatioValueTransfer(t *testing.T) { } func testGasOverflowValueTransferWithMemo(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeValueTransferMemo) + intrinsic := types.GetTxGasForTxType(types.TxTypeValueTransferMemo) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -119,7 +119,7 @@ func testGasOverflowValueTransferWithMemo(t *testing.T) { } func testGasOverflowFeeDelegatedValueTransferWithMemo(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedValueTransferMemo) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemo) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -131,7 +131,7 @@ func testGasOverflowFeeDelegatedValueTransferWithMemo(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioValueTransferWithMemo(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedValueTransferMemoWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemoWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -143,7 +143,7 @@ func testGasOverflowFeeDelegatedWithRatioValueTransferWithMemo(t *testing.T) { } func testGasOverflowAccountUpdate(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeAccountUpdate) + intrinsic := types.GetTxGasForTxType(types.TxTypeAccountUpdate) senderValidationGas := getMaxValidationKeyGas(t) maxCreationGas := getMaxCreationKeyGas(t) @@ -153,7 +153,7 @@ func testGasOverflowAccountUpdate(t *testing.T) { } func testGasOverflowFeeDelegatedAccountUpdate(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedAccountUpdate) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdate) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -165,7 +165,7 @@ func testGasOverflowFeeDelegatedAccountUpdate(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioAccountUpdate(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedAccountUpdateWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdateWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -177,7 +177,7 @@ func testGasOverflowFeeDelegatedWithRatioAccountUpdate(t *testing.T) { } func testGasOverflowSmartContractDeploy(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeSmartContractDeploy) + intrinsic := types.GetTxGasForTxType(types.TxTypeSmartContractDeploy) senderValidationGas := getMaxValidationKeyGas(t) payloadGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -190,7 +190,7 @@ func testGasOverflowSmartContractDeploy(t *testing.T) { } func testGasOverflowFeeDelegatedSmartContractDeploy(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedSmartContractDeploy) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeploy) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -205,7 +205,7 @@ func testGasOverflowFeeDelegatedSmartContractDeploy(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioSmartContractDeploy(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedSmartContractDeployWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeployWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -220,7 +220,7 @@ func testGasOverflowFeeDelegatedWithRatioSmartContractDeploy(t *testing.T) { } func testGasOverflowSmartContractExecution(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeSmartContractExecution) + intrinsic := types.GetTxGasForTxType(types.TxTypeSmartContractExecution) senderValidationGas := getMaxValidationKeyGas(t) payloadGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -230,7 +230,7 @@ func testGasOverflowSmartContractExecution(t *testing.T) { } func testGasOverflowFeeDelegatedSmartContractExecution(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedSmartContractExecution) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecution) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -242,7 +242,7 @@ func testGasOverflowFeeDelegatedSmartContractExecution(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioSmartContractExecution(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedSmartContractExecutionWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecutionWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -254,14 +254,14 @@ func testGasOverflowFeeDelegatedWithRatioSmartContractExecution(t *testing.T) { } func testGasOverflowCancel(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeCancel) + intrinsic := types.GetTxGasForTxType(types.TxTypeCancel) senderValidationGas := getMaxValidationKeyGas(t) addUint64(t, intrinsic, senderValidationGas) } func testGasOverflowFeeDelegatedCancel(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedCancel) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancel) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -270,7 +270,7 @@ func testGasOverflowFeeDelegatedCancel(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioCancel(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedCancelWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancelWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -279,7 +279,7 @@ func testGasOverflowFeeDelegatedWithRatioCancel(t *testing.T) { } func testGasOverflowChainDataAnchoring(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeChainDataAnchoring) + intrinsic := types.GetTxGasForTxType(types.TxTypeChainDataAnchoring) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -289,7 +289,7 @@ func testGasOverflowChainDataAnchoring(t *testing.T) { } func testGasOverflowFeeDelegatedChainDataAnchoring(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedChainDataAnchoring) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoring) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -301,7 +301,7 @@ func testGasOverflowFeeDelegatedChainDataAnchoring(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioChainDataAnchoring(t *testing.T) { - intrinsic := getIntrinsicGas(types.TxTypeFeeDelegatedChainDataAnchoringWithRatio) + intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoringWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) From 848499272b247d63d384df99bc6bd23ac547d028 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:44:56 +0900 Subject: [PATCH 2/8] Bring recent commits in geth --- blockchain/state_transition.go | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index 1e4bbafd0..b35bae044 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -433,6 +433,16 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, vm.ErrTotalTimeLimitReached } + var gasRefund uint64 + if rules.IsKore { + // After EIP-3529: refunds are capped to gasUsed / 5 + gasRefund = st.refundAmount(params.RefundQuotientEIP3529) + } else { + // Before EIP-3529: refunds were capped to gasUsed / 2 + gasRefund = st.refundAmount(params.RefundQuotient) + } + st.gas += gasRefund + if rules.IsPrague { // After EIP-7623: Data-heavy transactions pay the floor gas. // Overflow error has already been checked and can be ignored here. @@ -444,14 +454,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { st.gas = st.initialGas - floorGas } } - - if rules.IsKore { - // After EIP-3529: refunds are capped to gasUsed / 5 - st.refundGas(params.RefundQuotientEIP3529) - } else { - // Before EIP-3529: refunds were capped to gasUsed / 2 - st.refundGas(params.RefundQuotient) - } + st.returnGas() // Defer transferring Tx fee when DeferredTxFee is true // DeferredTxFee has never been voted, so it's ok to use the genesis value instead of the latest value from governance. @@ -599,14 +602,16 @@ func (st *StateTransition) applyAuthorization(auth *types.SetCodeAuthorization, return nil } -func (st *StateTransition) refundGas(refundQuotient uint64) { +func (st *StateTransition) refundAmount(refundQuotient uint64) uint64 { // Apply refund counter, capped a refund quotient refund := st.gasUsed() / refundQuotient if refund > st.state.GetRefund() { refund = st.state.GetRefund() } - st.gas += refund + return refund +} +func (st *StateTransition) returnGas() { // Return KAIA for remaining gas, exchanged at the original rate. remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) From 291d8da5c8afc51a2d025ede9d47254f2c42ca80 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Thu, 23 Jan 2025 09:53:50 +0900 Subject: [PATCH 3/8] Tidy up --- blockchain/state_transition.go | 20 +++---- blockchain/tx_pool.go | 6 +- blockchain/types/tx_internal_data.go | 89 +++++++++++----------------- tests/tx_gas_calculation_test.go | 34 +++++------ tests/tx_gas_overflow_test.go | 44 +++++++------- 5 files changed, 80 insertions(+), 113 deletions(-) diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index b35bae044..7a0367a99 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -352,14 +352,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber) if rules.IsPrague { - floorGas, err := FloorDataGas(st.msg.Type(), validatedGas.Tokens) + floorGas, err := FloorDataGas(st.msg.Type(), validatedGas.Tokens, validatedGas.SigValidateGas) if err != nil { return nil, err } - // Some of Kaia's tx type has sig validation gas. - // The sig validation gas is not included in the floor gas comparison, - // however we need to check if the gas is enough to pay the sig validation gas too. - floorGas += validatedGas.SigValidateGas if st.gas < floorGas { return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gas, floorGas) } @@ -446,10 +442,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { 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(st.msg.Type(), validatedGas.Tokens) - // Remember that the sig validation gas is included in used gas. - // So we need to add it to the floor gas to make sure the floor gas comparison is correct. - floorGas += validatedGas.SigValidateGas + floorGas, _ := FloorDataGas(st.msg.Type(), validatedGas.Tokens, validatedGas.SigValidateGas) if st.gasUsed() < floorGas { st.gas = st.initialGas - floorGas } @@ -636,13 +629,16 @@ func (st *StateTransition) gasUsed() uint64 { // FloorDataGas calculates the minimum gas required for a transaction // based on its data tokens (EIP-7623). -func FloorDataGas(txType types.TxType, tokens uint64) (uint64, error) { +func FloorDataGas(txType types.TxType, tokens, sigValidateGas uint64) (uint64, error) { // Check for overflow // Instead of using parmas.TxGas, we should consider the tx type // because Kaia tx type has different tx gas (e.g., fee delegated tx). - txGas := types.GetTxGasForTxType(txType) + txGas, err := types.GetTxGasForTxType(txType) + if err != nil { + return 0, err + } if (math.MaxUint64-txGas)/params.CostFloorPerToken7623 < tokens { return 0, types.ErrGasUintOverflow } - return txGas + tokens*params.CostFloorPerToken7623, nil + return txGas + tokens*params.CostFloorPerToken7623 + sigValidateGas, nil } diff --git a/blockchain/tx_pool.go b/blockchain/tx_pool.go index bf0e74737..653c3b994 100644 --- a/blockchain/tx_pool.go +++ b/blockchain/tx_pool.go @@ -846,14 +846,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { } // Ensure the transaction can cover floor data gas. if pool.rules.IsPrague { - floorGas, err := FloorDataGas(tx.Type(), dataTokens) + floorGas, err := FloorDataGas(tx.Type(), dataTokens, sigValGas) if err != nil { return err } - // Some of Kaia's tx type has sig validation gas. - // The sig validation gas is not included in the floor gas comparison, - // however we need to check if the gas is enough to pay the sig validation gas too. - floorGas += sigValGas if tx.Gas() < floorGas { return fmt.Errorf("%w: gas %v, minimum needed %v", ErrDataFloorGas, tx.Gas(), floorGas) } diff --git a/blockchain/types/tx_internal_data.go b/blockchain/types/tx_internal_data.go index 9cafd2cab..3ef0dc487 100644 --- a/blockchain/types/tx_internal_data.go +++ b/blockchain/types/tx_internal_data.go @@ -22,6 +22,7 @@ import ( "bytes" "crypto/ecdsa" "errors" + "fmt" "math" "math/big" @@ -697,62 +698,40 @@ func IntrinsicGas(data []byte, accessList AccessList, authorizationList []SetCod return gasPayloadWithGas, tokens, nil } -func GetTxGasForTxType(txType TxType) uint64 { - switch txType { - case TxTypeLegacyTransaction: - return params.TxGas - case TxTypeValueTransfer: - return params.TxGasValueTransfer - case TxTypeFeeDelegatedValueTransfer: - return params.TxGasValueTransfer + params.TxGasFeeDelegated - case TxTypeFeeDelegatedValueTransferWithRatio: - return params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio - case TxTypeValueTransferMemo: - return params.TxGasValueTransfer - case TxTypeFeeDelegatedValueTransferMemo: - return params.TxGasValueTransfer + params.TxGasFeeDelegated - case TxTypeFeeDelegatedValueTransferMemoWithRatio: - return params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio - case TxTypeAccountCreation: - return params.TxGasAccountCreation - case TxTypeAccountUpdate: - return params.TxGasAccountUpdate - case TxTypeFeeDelegatedAccountUpdate: - return params.TxGasAccountUpdate + params.TxGasFeeDelegated - case TxTypeFeeDelegatedAccountUpdateWithRatio: - return params.TxGasAccountUpdate + params.TxGasFeeDelegatedWithRatio - case TxTypeSmartContractDeploy: - return params.TxGasContractCreation - case TxTypeFeeDelegatedSmartContractDeploy: - return params.TxGasContractCreation + params.TxGasFeeDelegated - case TxTypeFeeDelegatedSmartContractDeployWithRatio: - return params.TxGasContractCreation + params.TxGasFeeDelegatedWithRatio - case TxTypeSmartContractExecution: - return params.TxGasContractExecution - case TxTypeFeeDelegatedSmartContractExecution: - return params.TxGasContractExecution + params.TxGasFeeDelegated - case TxTypeFeeDelegatedSmartContractExecutionWithRatio: - return params.TxGasContractExecution + params.TxGasFeeDelegatedWithRatio - case TxTypeCancel: - return params.TxGasCancel - case TxTypeFeeDelegatedCancel: - return params.TxGasCancel + params.TxGasFeeDelegated - case TxTypeFeeDelegatedCancelWithRatio: - return params.TxGasCancel + params.TxGasFeeDelegatedWithRatio - case TxTypeChainDataAnchoring: - return params.TxChainDataAnchoringGas - case TxTypeFeeDelegatedChainDataAnchoring: - return params.TxChainDataAnchoringGas + params.TxGasFeeDelegated - case TxTypeFeeDelegatedChainDataAnchoringWithRatio: - return params.TxChainDataAnchoringGas + params.TxGasFeeDelegatedWithRatio - case TxTypeEthereumAccessList: - return params.TxGas - case TxTypeEthereumDynamicFee: - return params.TxGas - case TxTypeEthereumSetCode: - return params.TxGas +var txTypeToGasMap = map[TxType]uint64{ + TxTypeLegacyTransaction: params.TxGas, + TxTypeValueTransfer: params.TxGasValueTransfer, + TxTypeFeeDelegatedValueTransfer: params.TxGasValueTransfer + params.TxGasFeeDelegated, + TxTypeFeeDelegatedValueTransferWithRatio: params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio, + TxTypeValueTransferMemo: params.TxGasValueTransfer, + TxTypeFeeDelegatedValueTransferMemo: params.TxGasValueTransfer + params.TxGasFeeDelegated, + TxTypeFeeDelegatedValueTransferMemoWithRatio: params.TxGasValueTransfer + params.TxGasFeeDelegatedWithRatio, + TxTypeAccountCreation: params.TxGasAccountCreation, + TxTypeAccountUpdate: params.TxGasAccountUpdate, + TxTypeFeeDelegatedAccountUpdate: params.TxGasAccountUpdate + params.TxGasFeeDelegated, + TxTypeFeeDelegatedAccountUpdateWithRatio: params.TxGasAccountUpdate + params.TxGasFeeDelegatedWithRatio, + TxTypeSmartContractDeploy: params.TxGasContractCreation, + TxTypeFeeDelegatedSmartContractDeploy: params.TxGasContractCreation + params.TxGasFeeDelegated, + TxTypeFeeDelegatedSmartContractDeployWithRatio: params.TxGasContractCreation + params.TxGasFeeDelegatedWithRatio, + TxTypeSmartContractExecution: params.TxGasContractExecution, + TxTypeFeeDelegatedSmartContractExecution: params.TxGasContractExecution + params.TxGasFeeDelegated, + TxTypeFeeDelegatedSmartContractExecutionWithRatio: params.TxGasContractExecution + params.TxGasFeeDelegatedWithRatio, + TxTypeCancel: params.TxGasCancel, + TxTypeFeeDelegatedCancel: params.TxGasCancel + params.TxGasFeeDelegated, + TxTypeFeeDelegatedCancelWithRatio: params.TxGasCancel + params.TxGasFeeDelegatedWithRatio, + TxTypeChainDataAnchoring: params.TxChainDataAnchoringGas, + TxTypeFeeDelegatedChainDataAnchoring: params.TxChainDataAnchoringGas + params.TxGasFeeDelegated, + TxTypeFeeDelegatedChainDataAnchoringWithRatio: params.TxChainDataAnchoringGas + params.TxGasFeeDelegatedWithRatio, + TxTypeEthereumAccessList: params.TxGas, + TxTypeEthereumDynamicFee: params.TxGas, + TxTypeEthereumSetCode: params.TxGas, +} + +func GetTxGasForTxType(txType TxType) (uint64, error) { + if gas, exists := txTypeToGasMap[txType]; exists { + return gas, nil } - panic("unexpected tx type: " + txType.String()) + return 0, fmt.Errorf("cannot find txGas for txType %s", txType.String()) } // CalcFeeWithRatio returns feePayer's fee and sender's fee based on feeRatio. diff --git a/tests/tx_gas_calculation_test.go b/tests/tx_gas_calculation_test.go index 5680cb62b..44429ecf2 100644 --- a/tests/tx_gas_calculation_test.go +++ b/tests/tx_gas_calculation_test.go @@ -288,7 +288,7 @@ func testGasValidation(t *testing.T, bcdata *BCData, tx *types.Transaction, vali } func genLegacyTransaction(t *testing.T, signer types.Signer, from TestAccount, to TestAccount, payer TestAccount, gasPrice *big.Int) (*types.Transaction, uint64) { - intrinsic := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) amount := big.NewInt(100000) tx := types.NewTransaction(from.GetNonce(), to.GetAddr(), amount, gasLimit, gasPrice, []byte{}) @@ -667,7 +667,7 @@ func genFeeDelegatedWithRatioChainDataAnchoring(t *testing.T, signer types.Signe // Generate map functions func genMapForLegacyTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} // We have changed the gas calcuation since Prague per EIP-7623. @@ -715,7 +715,7 @@ func getFlooredGas(data []byte, gas uint64) uint64 { } func genMapForAccessListTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} // We have changed the gas calcuation since Prague per EIP-7623. @@ -743,7 +743,7 @@ func genMapForAccessListTransaction(from TestAccount, to TestAccount, gasPrice * } func genMapForDynamicFeeTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} // We have changed the gas calcuation since Prague per EIP-7623. @@ -771,7 +771,7 @@ func genMapForDynamicFeeTransaction(from TestAccount, to TestAccount, gasPrice * } func genMapForSetCodeTransaction(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) data := []byte{0x11, 0x22} // We have changed the gas calcuation since Prague per EIP-7623. @@ -802,7 +802,7 @@ func genMapForSetCodeTransaction(from TestAccount, to TestAccount, gasPrice *big } func genMapForValueTransfer(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(100000) values := map[types.TxValueKeyType]interface{}{ @@ -817,7 +817,7 @@ func genMapForValueTransfer(from TestAccount, to TestAccount, gasPrice *big.Int, } func genMapForValueTransferWithMemo(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) nonZeroData := []byte{1, 2, 3, 4} zeroData := []byte{0, 0, 0, 0} @@ -843,7 +843,7 @@ func genMapForValueTransferWithMemo(from TestAccount, to TestAccount, gasPrice * } func genMapForCreate(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) amount := big.NewInt(0) values := map[types.TxValueKeyType]interface{}{ @@ -860,7 +860,7 @@ func genMapForCreate(from TestAccount, to TestAccount, gasPrice *big.Int, txType } func genMapForUpdate(from TestAccount, to TestAccount, gasPrice *big.Int, newKeys accountkey.AccountKey, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -886,16 +886,14 @@ func genMapForDeploy(from TestAccount, to TestAccount, gasPrice *big.Int, txType types.TxValueKeyTo: (*common.Address)(nil), } - intrinsicGas := types.GetTxGasForTxType(txType) + intrinsicGas, _ := types.GetTxGasForTxType(txType) intrinsicGas += uint64(0x175fd) gasPayloadWithGas, dataTokens, err := types.IntrinsicGasPayload(intrinsicGas, common.FromHex(code), true, params.Rules{IsIstanbul: true, IsShanghai: true, IsPrague: true}) if err != nil { return nil, 0 } - floorGas, _ := blockchain.FloorDataGas(types.TxTypeSmartContractDeploy, dataTokens) - // Tx Gas is included in the gasPayloadWithGas, so we need to add it to the floorGas for correct comparison. - floorGas += types.GetTxGasForTxType(txType) + floorGas, _ := blockchain.FloorDataGas(txType, dataTokens, 0) if gasPayloadWithGas < floorGas { gasPayloadWithGas = floorGas } @@ -927,19 +925,17 @@ func genMapForExecution(from TestAccount, to TestAccount, gasPrice *big.Int, txT types.TxValueKeyData: data, } - intrinsicGas := types.GetTxGasForTxType(txType) + intrinsicGas, _ := types.GetTxGasForTxType(txType) intrinsicGas += uint64(0x9ec4) gasPayloadWithGas, dataTokens, err := types.IntrinsicGasPayload(intrinsicGas, data, false, params.Rules{IsShanghai: false, IsPrague: true}) if err != nil { return nil, 0 } - floorGas, err := blockchain.FloorDataGas(txType, dataTokens) + floorGas, err := blockchain.FloorDataGas(txType, dataTokens, 0) if err != nil { return nil, 0 } - // Tx Gas is included in the gasPayloadWithGas, so we need to add it to the floorGas for correct comparison. - floorGas += types.GetTxGasForTxType(txType) if gasPayloadWithGas < floorGas { gasPayloadWithGas = floorGas } @@ -948,7 +944,7 @@ func genMapForExecution(from TestAccount, to TestAccount, gasPrice *big.Int, txT } func genMapForCancel(from TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) values := map[types.TxValueKeyType]interface{}{ types.TxValueKeyNonce: from.GetNonce(), @@ -960,7 +956,7 @@ func genMapForCancel(from TestAccount, gasPrice *big.Int, txType types.TxType) ( } func genMapForChainDataAnchoring(from TestAccount, gasPrice *big.Int, txType types.TxType) (map[types.TxValueKeyType]interface{}, uint64) { - intrinsic := types.GetTxGasForTxType(txType) + intrinsic, _ := types.GetTxGasForTxType(txType) data := []byte{0x11, 0x22} // We have changed the gas calcuation since Prague per EIP-7623. gasPayload := getFlooredGas(data, getDataGas(data)) diff --git a/tests/tx_gas_overflow_test.go b/tests/tx_gas_overflow_test.go index 38b276c83..661286f64 100644 --- a/tests/tx_gas_overflow_test.go +++ b/tests/tx_gas_overflow_test.go @@ -74,7 +74,7 @@ func TestGasOverflow(t *testing.T) { } func testGasOverflowLegacyTransaction(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeLegacyTransaction) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataNonZeroGasFrontier) @@ -84,14 +84,14 @@ func testGasOverflowLegacyTransaction(t *testing.T) { } func testGasOverflowValueTransfer(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeValueTransfer) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeValueTransfer) senderValidationGas := getMaxValidationKeyGas(t) addUint64(t, intrinsic, senderValidationGas) } func testGasOverflowFeeDelegatedValueTransfer(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransfer) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransfer) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -100,7 +100,7 @@ func testGasOverflowFeeDelegatedValueTransfer(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioValueTransfer(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -109,7 +109,7 @@ func testGasOverflowFeeDelegatedWithRatioValueTransfer(t *testing.T) { } func testGasOverflowValueTransferWithMemo(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeValueTransferMemo) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeValueTransferMemo) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -119,7 +119,7 @@ func testGasOverflowValueTransferWithMemo(t *testing.T) { } func testGasOverflowFeeDelegatedValueTransferWithMemo(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemo) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemo) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -131,7 +131,7 @@ func testGasOverflowFeeDelegatedValueTransferWithMemo(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioValueTransferWithMemo(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemoWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedValueTransferMemoWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -143,7 +143,7 @@ func testGasOverflowFeeDelegatedWithRatioValueTransferWithMemo(t *testing.T) { } func testGasOverflowAccountUpdate(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeAccountUpdate) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeAccountUpdate) senderValidationGas := getMaxValidationKeyGas(t) maxCreationGas := getMaxCreationKeyGas(t) @@ -153,7 +153,7 @@ func testGasOverflowAccountUpdate(t *testing.T) { } func testGasOverflowFeeDelegatedAccountUpdate(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdate) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdate) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -165,7 +165,7 @@ func testGasOverflowFeeDelegatedAccountUpdate(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioAccountUpdate(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdateWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedAccountUpdateWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -177,7 +177,7 @@ func testGasOverflowFeeDelegatedWithRatioAccountUpdate(t *testing.T) { } func testGasOverflowSmartContractDeploy(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeSmartContractDeploy) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeSmartContractDeploy) senderValidationGas := getMaxValidationKeyGas(t) payloadGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -190,7 +190,7 @@ func testGasOverflowSmartContractDeploy(t *testing.T) { } func testGasOverflowFeeDelegatedSmartContractDeploy(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeploy) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeploy) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -205,7 +205,7 @@ func testGasOverflowFeeDelegatedSmartContractDeploy(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioSmartContractDeploy(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeployWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractDeployWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -220,7 +220,7 @@ func testGasOverflowFeeDelegatedWithRatioSmartContractDeploy(t *testing.T) { } func testGasOverflowSmartContractExecution(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeSmartContractExecution) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeSmartContractExecution) senderValidationGas := getMaxValidationKeyGas(t) payloadGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -230,7 +230,7 @@ func testGasOverflowSmartContractExecution(t *testing.T) { } func testGasOverflowFeeDelegatedSmartContractExecution(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecution) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecution) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -242,7 +242,7 @@ func testGasOverflowFeeDelegatedSmartContractExecution(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioSmartContractExecution(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecutionWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedSmartContractExecutionWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -254,14 +254,14 @@ func testGasOverflowFeeDelegatedWithRatioSmartContractExecution(t *testing.T) { } func testGasOverflowCancel(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeCancel) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeCancel) senderValidationGas := getMaxValidationKeyGas(t) addUint64(t, intrinsic, senderValidationGas) } func testGasOverflowFeeDelegatedCancel(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancel) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancel) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -270,7 +270,7 @@ func testGasOverflowFeeDelegatedCancel(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioCancel(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancelWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedCancelWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -279,7 +279,7 @@ func testGasOverflowFeeDelegatedWithRatioCancel(t *testing.T) { } func testGasOverflowChainDataAnchoring(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeChainDataAnchoring) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeChainDataAnchoring) senderValidationGas := getMaxValidationKeyGas(t) maxDataGas := mulUint64(t, blockchain.MaxTxDataSize, params.TxDataGas) @@ -289,7 +289,7 @@ func testGasOverflowChainDataAnchoring(t *testing.T) { } func testGasOverflowFeeDelegatedChainDataAnchoring(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoring) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoring) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) @@ -301,7 +301,7 @@ func testGasOverflowFeeDelegatedChainDataAnchoring(t *testing.T) { } func testGasOverflowFeeDelegatedWithRatioChainDataAnchoring(t *testing.T) { - intrinsic := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoringWithRatio) + intrinsic, _ := types.GetTxGasForTxType(types.TxTypeFeeDelegatedChainDataAnchoringWithRatio) senderValidationGas := getMaxValidationKeyGas(t) payerValidationGas := getMaxValidationKeyGas(t) From 084f0f3476bd260b53617cd9ba328df743f6df67 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:23:29 +0900 Subject: [PATCH 4/8] Add state transition test for EIP7623 --- blockchain/state_transition_test.go | 90 +++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/blockchain/state_transition_test.go b/blockchain/state_transition_test.go index f5b588be7..cb36d0646 100644 --- a/blockchain/state_transition_test.go +++ b/blockchain/state_transition_test.go @@ -19,6 +19,7 @@ package blockchain import ( + "crypto/ecdsa" "errors" "fmt" "math/big" @@ -31,6 +32,7 @@ import ( mock_vm "github.com/kaiachain/kaia/blockchain/vm/mocks" "github.com/kaiachain/kaia/common" "github.com/kaiachain/kaia/crypto" + "github.com/kaiachain/kaia/fork" "github.com/kaiachain/kaia/params" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -418,3 +420,91 @@ func TestStateTransition_applyAuthorization(t *testing.T) { }) } } + +func TestStateTransition_EIP7623(t *testing.T) { + // Prague fork block at 10 + config := params.TestChainConfig.Copy() + config.IstanbulCompatibleBlock = common.Big0 + config.LondonCompatibleBlock = common.Big0 + config.EthTxTypeCompatibleBlock = common.Big0 + config.MagmaCompatibleBlock = common.Big0 + config.KoreCompatibleBlock = common.Big0 + config.ShanghaiCompatibleBlock = common.Big0 + config.CancunCompatibleBlock = common.Big0 + config.KaiaCompatibleBlock = common.Big0 + config.PragueCompatibleBlock = big.NewInt(10) + config.Governance = params.GetDefaultGovernanceConfig() + config.Governance.KIP71.LowerBoundBaseFee = 0 + // Apply chain config to fork + fork.SetHardForkBlockNumberConfig(config) + + var ( + key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + addr = crypto.PubkeyToAddress(key.PublicKey) + amount = big.NewInt(1000) + data = []byte{1, 2, 3, 4, 0, 0, 0, 0} // 4 non-zero bytes, 4 zero bytes + signer = types.LatestSigner(config) + gaslimit1 = uint64(21800) // 21000 + 100 * 8 (100 per byte) + gaslimit2 = uint64(21200) // 21000 + 10*4*4 + 10*4 (10 per token, 4 tokens per non-zero byte, 1 token per zero byte) + ) + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + mockStateDB := mock_vm.NewMockStateDB(mockCtrl) + mockStateDB.EXPECT().GetBalance(gomock.Any()).Return(big.NewInt(params.KAIA)).AnyTimes() + mockStateDB.EXPECT().SubBalance(gomock.Any(), gomock.Any()).Return().AnyTimes() + mockStateDB.EXPECT().GetKey(gomock.Any()).Return(accountkey.NewAccountKeyLegacy()).AnyTimes() + mockStateDB.EXPECT().GetNonce(gomock.Any()).Return(uint64(0)).AnyTimes() + mockStateDB.EXPECT().Prepare(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() + mockStateDB.EXPECT().IncNonce(gomock.Any()).Return().AnyTimes() + mockStateDB.EXPECT().Snapshot().Return(1).AnyTimes() + mockStateDB.EXPECT().Exist(gomock.Any()).Return(false).AnyTimes() + mockStateDB.EXPECT().GetRefund().Return(uint64(0)).AnyTimes() + mockStateDB.EXPECT().AddBalance(gomock.Any(), gomock.Any()).Return().AnyTimes() + mockStateDB.EXPECT().CreateEOA(gomock.Any(), gomock.Any(), gomock.Any()).Return().AnyTimes() + mockStateDB.EXPECT().GetVmVersion(gomock.Any()).Return(params.VmVersion0, false).AnyTimes() + mockStateDB.EXPECT().IsProgramAccount(gomock.Any()).Return(false).AnyTimes() + + var ( + header *types.Header + blockContext vm.BlockContext + txContext vm.TxContext + evm *vm.EVM + res *ExecutionResult + err error + tx *types.Transaction + ) + + // Generate tx before Prague + tx = types.NewTransaction(0, addr, amount, gaslimit1, big.NewInt(1), data) + err = tx.SignWithKeys(signer, []*ecdsa.PrivateKey{key}) + assert.NoError(t, err) + tx, err = tx.AsMessageWithAccountKeyPicker(signer, mockStateDB, 0) + assert.NoError(t, err) + + header = &types.Header{Number: big.NewInt(0), Time: big.NewInt(0), BlockScore: big.NewInt(0)} + blockContext = NewEVMBlockContext(header, nil, &common.Address{}) + txContext = NewEVMTxContext(tx, header, config) + evm = vm.NewEVM(blockContext, txContext, mockStateDB, config, &vm.Config{}) + + res, err = NewStateTransition(evm, tx).TransitionDb() + assert.NoError(t, err) + assert.Equal(t, gaslimit1, res.UsedGas) + + // Generate tx after Prague + tx = types.NewTransaction(0, addr, amount, gaslimit2, big.NewInt(1), data) + err = tx.SignWithKeys(signer, []*ecdsa.PrivateKey{key}) + assert.NoError(t, err) + tx, err = tx.AsMessageWithAccountKeyPicker(signer, mockStateDB, 20) + assert.NoError(t, err) + + header = &types.Header{Number: big.NewInt(20), Time: big.NewInt(0), BlockScore: big.NewInt(0)} + blockContext = NewEVMBlockContext(header, nil, &common.Address{}) + txContext = NewEVMTxContext(tx, header, config) + evm = vm.NewEVM(blockContext, txContext, mockStateDB, config, &vm.Config{}) + + res, err = NewStateTransition(evm, tx).TransitionDb() + assert.NoError(t, err) + assert.Equal(t, gaslimit2, res.UsedGas) +} From 989fe4add24c1bb148bc9a64f43fc353463087a5 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:11:56 +0900 Subject: [PATCH 5/8] Update error name --- blockchain/error.go | 4 ++-- blockchain/state_transition.go | 2 +- blockchain/tx_pool.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/blockchain/error.go b/blockchain/error.go index c136da5da..e32c86941 100644 --- a/blockchain/error.go +++ b/blockchain/error.go @@ -86,9 +86,9 @@ 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 + // ErrFloorDataGas 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") + ErrFloorDataGas = errors.New("insufficient gas for floor data gas cost") // ErrGasLimit is returned if a transaction's requested gas limit exceeds the // maximum allowance of the current block. diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index 7a0367a99..c1cd7fea2 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -357,7 +357,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, err } if st.gas < floorGas { - return nil, fmt.Errorf("%w: have %d, want %d", ErrDataFloorGas, st.gas, floorGas) + return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, st.gas, floorGas) } } st.gas -= (validatedGas.IntrinsicGas + validatedGas.SigValidateGas) diff --git a/blockchain/tx_pool.go b/blockchain/tx_pool.go index 653c3b994..86adeb31d 100644 --- a/blockchain/tx_pool.go +++ b/blockchain/tx_pool.go @@ -851,7 +851,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { return err } if tx.Gas() < floorGas { - return fmt.Errorf("%w: gas %v, minimum needed %v", ErrDataFloorGas, tx.Gas(), floorGas) + return fmt.Errorf("%w: gas %v, minimum needed %v", ErrFloorDataGas, tx.Gas(), floorGas) } } From 7253117847034fafc5f4d197a7377734ea82c5dd Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:01:44 +0900 Subject: [PATCH 6/8] Include sig validatioin gas in intrinsic gas for semantic --- blockchain/state_transition.go | 5 +++-- blockchain/types/transaction.go | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index c1cd7fea2..01e9506c5 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -347,7 +347,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { // Check clauses 4-5, subtract intrinsic gas if everything is correct validatedGas := msg.ValidatedGas() - if st.gas < validatedGas.IntrinsicGas+validatedGas.SigValidateGas { + if st.gas < validatedGas.IntrinsicGas { return nil, ErrIntrinsicGas } rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber) @@ -360,7 +360,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, st.gas, floorGas) } } - st.gas -= (validatedGas.IntrinsicGas + validatedGas.SigValidateGas) + // SigValidationGas is already inclduded in IntrinsicGas + st.gas -= validatedGas.IntrinsicGas // Check clause 6 if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.ValidatedSender(), msg.Value()) { diff --git a/blockchain/types/transaction.go b/blockchain/types/transaction.go index 93f63f6a1..b2e70c503 100644 --- a/blockchain/types/transaction.go +++ b/blockchain/types/transaction.go @@ -73,8 +73,9 @@ func ErrFeePayer(err error) error { } // ValidatedGas holds the intrinsic gas, sig validation gas, and data tokens. -// - Intrinsic gas is the gas for the tx type + data. +// - Intrinsic gas is the gas for the tx type + signature validation + data. // After Prague, floor gas would be used if intrinsic gas < floor gas. +// Note that SigValidationGas is already included in IntrinsicGas. // - Sig validation gas is the gas for validating sender and feePayer. // It is related to Kaia-specific tx types, so it is not part of the floor gas comparison. // - Tokens is the number of tokens for the data. @@ -619,8 +620,11 @@ func (tx *Transaction) AsMessageWithAccountKeyPicker(s Signer, picker AccountKey } } + sigValidationGas := gasFrom + gasFeePayer + intrinsicGas = intrinsicGas + sigValidationGas + tx.mu.Lock() - tx.validatedGas = &ValidatedGas{IntrinsicGas: intrinsicGas, SigValidateGas: gasFrom + gasFeePayer, Tokens: dataTokens} + tx.validatedGas = &ValidatedGas{IntrinsicGas: intrinsicGas, SigValidateGas: sigValidationGas, Tokens: dataTokens} tx.mu.Unlock() return tx, err From 9ba1e08907cd758ae44b2e67e43738c1b86775b0 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Tue, 4 Feb 2025 08:41:13 +0900 Subject: [PATCH 7/8] Enable EIP-7623 test in EEST --- tests/state_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/state_test.go b/tests/state_test.go index 831f6cf17..95c545e00 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -96,7 +96,6 @@ func (suite *ExecutionSpecStateTestSuite) TestExecutionSpecState() { st.skipLoad(`^frontier\/opcodes\/all_opcodes\/all_opcodes.json`) st.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json`) st.skipLoad(`^prague\/eip7702_set_code_tx\/`) - st.skipLoad(`^prague\/eip7623_increase_calldata_cost\/`) // tests to skip // unsupported EIPs From 59dce307048519f794d024037704c1df8fd8d202 Mon Sep 17 00:00:00 2001 From: Sawyer <18228063+2dvorak@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:08:32 +0900 Subject: [PATCH 8/8] Update blockchain/state_transition.go Co-authored-by: Lewis --- blockchain/state_transition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index 0428d2ddd..4f25ee3a5 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -638,7 +638,7 @@ func FloorDataGas(txType types.TxType, tokens, sigValidateGas uint64) (uint64, e if err != nil { return 0, err } - if (math.MaxUint64-txGas)/params.CostFloorPerToken7623 < tokens { + if (math.MaxUint64-txGas-sigValidateGas)/params.CostFloorPerToken7623 < tokens { return 0, types.ErrGasUintOverflow } return txGas + tokens*params.CostFloorPerToken7623 + sigValidateGas, nil