diff --git a/.circleci/config.yml b/.circleci/config.yml index 235ee2f01..817ed96a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -51,7 +51,7 @@ executors: - image: kaiachain/build_base:go1.23.7-solc0.8.13-ubuntu-22.04 test-tests-executor: # this executor is for test-tests job working_directory: ~/go/src/github.com/kaiachain/kaia - resource_class: medium+ + resource_class: xlarge docker: - image: kaiachain/build_base:go1.23-solc0.8.13-ubuntu-22.04 test-others-executor: # this executor is for test-others job diff --git a/blockchain/chain_makers.go b/blockchain/chain_makers.go index 3e2d53928..baf7b815b 100644 --- a/blockchain/chain_makers.go +++ b/blockchain/chain_makers.go @@ -72,6 +72,18 @@ func (b *BlockGen) SetGovData(data []byte) { b.header.Governance = data } +func (b *BlockGen) SetMixHash(mixHash common.Hash) { + b.header.MixHash = mixHash.Bytes() +} + +func (b *BlockGen) SetBaseFee(baseFee *big.Int) { + b.header.BaseFee = baseFee +} + +func (b *BlockGen) SetTime(time *big.Int) { + b.header.Time = time +} + // AddTx adds a transaction to the generated block. // In gxhash, arbitrary address is used as a block author's address. // @@ -110,7 +122,11 @@ func (b *BlockGen) AddTxWithChainEvenHasError(bc *BlockChain, tx *types.Transact if bc != nil { vmConfig = bc.vmConfig } - receipt, _, _ := bc.ApplyTransaction(b.config, ¶ms.AuthorAddressForTesting, b.statedb, b.header, tx, &b.header.GasUsed, &vmConfig) + auther, err := b.engine.Author(b.header) + if err != nil { + return err + } + receipt, _, _ := bc.ApplyTransaction(b.config, &auther, b.statedb, b.header, tx, &b.header.GasUsed, &vmConfig) b.txs = append(b.txs, tx) if receipt != nil { b.receipts = append(b.receipts, receipt) diff --git a/blockchain/error.go b/blockchain/error.go index 0c5d61eb8..5c0efeb51 100644 --- a/blockchain/error.go +++ b/blockchain/error.go @@ -140,6 +140,10 @@ var ( // ErrFeeCapVeryHigh is a sanity error to avoid extremely big numbers specified in the fee cap field. ErrFeeCapVeryHigh = errors.New("max fee per gas higher than 2^256-1") + // ErrFeeCapTooLow is returned if the transaction fee cap is less than the + // base fee of the block. + ErrFeeCapTooLow = errors.New("max fee per gas less than block base fee") + // ErrTipAboveFeeCap is a sanity error to ensure no one is able to specify a // transaction with a tip higher than the total fee cap. ErrTipAboveFeeCap = errors.New("max fee per gas higher than max priority fee per gas") diff --git a/blockchain/state_transition.go b/blockchain/state_transition.go index ec50d54cf..491589c0a 100644 --- a/blockchain/state_transition.go +++ b/blockchain/state_transition.go @@ -299,6 +299,33 @@ func (st *StateTransition) preCheck() error { } } + // Make sure that transaction gasFeeCap is greater than the baseFee (post london) + // NOTE: Kaia adopt the validation post Prague since we're already released London + if st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber).IsPrague { + // Skip the checks if gas fields are zero and baseFee was explicitly disabled (eth_call) + skipCheck := st.msg.GasFeeCap().BitLen() == 0 && st.msg.GasTipCap().BitLen() == 0 + if !skipCheck { + if l := st.msg.GasFeeCap().BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh, + st.msg.ValidatedSender().Hex(), l) + } + if l := st.msg.GasTipCap().BitLen(); l > 256 { + return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh, + st.msg.ValidatedSender().Hex(), l) + } + if st.msg.GasFeeCap().Cmp(st.msg.GasTipCap()) < 0 { + return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap, + st.msg.ValidatedSender().Hex(), st.msg.GasTipCap(), st.msg.GasFeeCap()) + } + // This will panic if baseFee is nil, but basefee presence is verified + // as part of header validation. + if st.msg.GasFeeCap().Cmp(st.evm.Context.BaseFee) < 0 { + return fmt.Errorf("%w: address %v, maxFeePerGas: %s, baseFee: %s", ErrFeeCapTooLow, + st.msg.ValidatedSender().Hex(), st.msg.GasFeeCap(), st.evm.Context.BaseFee) + } + } + } + // Check that EIP-7702 authorization list signatures are well formed. if st.msg.AuthList() != nil { if st.msg.To() == nil { diff --git a/blockchain/vm/eips.go b/blockchain/vm/eips.go index 93e6bd5bf..4b08d0f2f 100644 --- a/blockchain/vm/eips.go +++ b/blockchain/vm/eips.go @@ -381,8 +381,10 @@ func enableCancunComputationCostModification(jt *JumpTable) { jt[LOG4].computationCost = params.Log4ComputationCostCancun } -func ChangeGasCostForTest(jt *JumpTable, opCode OpCode, constantGas uint64) { - jt[opCode].constantGas = constantGas +func ChangeGasCostForTest(jt *JumpTable) { + // EIP-1052 must be activated for backward compatibility on Kaia. But EIP-2929 is activated instead of it on Ethereum + jt[EXTCODEHASH].constantGas = params.WarmStorageReadCostEIP2929 + jt[EXTCODEHASH].dynamicGas = gasEip2929AccountCheck } // enable7702 the EIP-7702 changes to support delegation designators. diff --git a/build/checksums.txt b/build/checksums.txt index 80464d209..b0615de0a 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -1,5 +1,5 @@ # This file contains sha256 checksums of optional build dependencies. -# version:spec-tests pectra-devnet-6@v1.0.0 -# https://raw.githubusercontent.com/kaiachain/kaia/refs/heads/pectra-devnet-6/build/pectra-devnet-6@v1.0.0 -b69211752a3029083c020dc635fe12156ca1a6725a08559da540a0337586a77e fixtures_pectra-devnet-6.tar.gz +# version:spec-tests v4.5.0 +# https://github.com/ethereum/execution-spec-tests/releases/download/v4.5.0/ +58afb92a0075a2cb7c4dec1281f7cb88b21b02afbedad096b580f3f8cc14c54c fixtures_develop.tar.gz diff --git a/build/ci.go b/build/ci.go index 51cad1c3a..71b736ddd 100644 --- a/build/ci.go +++ b/build/ci.go @@ -305,8 +305,8 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string { log.Fatal(err) } ext := ".tar.gz" - base := "fixtures_pectra-devnet-6" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename - url := fmt.Sprintf("https://raw.githubusercontent.com/kaiachain/kaia/refs/heads/pectra-devnet-6/build/%s/%s%s", executionSpecTestsVersion, base, ext) + base := "fixtures_develop" + url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/%s/%s%s", executionSpecTestsVersion, base, ext) archivePath := filepath.Join(cachedir, base+ext) if err := csdb.DownloadFile(url, archivePath); err != nil { log.Fatal(err) diff --git a/tests/block_test.go b/tests/block_test.go index 02caca56a..09054431b 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -70,12 +70,20 @@ func (suite *ExecutionSpecBlockTestSuite) TestExecutionSpecBlock() { bt.skipLoad(`^prague\/eip7002_el_triggerable_withdrawals`) bt.skipLoad(`^prague\/eip6110_deposits`) // different amount of gas is consumed because 0x0b contract is added to access list by ActivePrecompiles although Cancun doesn't have it as a precompiled contract - bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test-31_bytes\]`) - bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test-32_bytes\]`) - bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test-empty_calldata\]`) + bt.skipLoad(`^frontier\/precompiles\/precompiles\/precompiles.json\/tests\/frontier\/precompiles\/test_precompiles.py::test_precompiles\[fork_Cancun-address_0xb-precompile_exists_False-blockchain_test_from_state_test\]`) + bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test_from_state_test-31_bytes\]`) + bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test_from_state_test-32_bytes\]`) + bt.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-blockchain_test_from_state_test-empty_calldata\]`) + bt.skipLoad(`^prague\/eip2537_bls_12_381_precompiles\/bls12_precompiles_before_fork\/precompile_before_fork.json\/tests\/prague\/eip2537_bls_12_381_precompiles\/test_bls12_precompiles_before_fork.py::test_precompile_before_fork\[fork_Cancun-state_test--G1ADD\]`) // type 3 tx (EIP-4844) is not supported + bt.skipLoad(`^frontier\/scenarios\/scenarios\/scenarios.json\/tests\/frontier\/scenarios\/test_scenarios.py::test_scenarios\[fork_Cancun-blockchain_test-program_BLOBBASEFEE-debug\]`) + bt.skipLoad(`^frontier\/scenarios\/scenarios\/scenarios.json\/tests\/frontier\/scenarios\/test_scenarios.py::test_scenarios\[fork_Prague-blockchain_test-program_BLOBBASEFEE-debug\]`) bt.skipLoad(`^prague\/eip7623_increase_calldata_cost\/.*type_3.*`) - bt.skipLoad(`^prague\/eip7702_set_code_tx\/set_code_txs\/eoa_tx_after_set_code.json\/tests\/prague\/eip7702_set_code_tx\/test_set_code_txs.py::test_eoa_tx_after_set_code\[fork_Prague-tx_type_3-evm_code_type_LEGACY-blockchain_test\]`) + bt.skipLoad(`^prague\/eip7702_set_code_tx\/set_code_txs\/eoa_tx_after_set_code.json\/tests\/prague\/eip7702_set_code_tx\/test_set_code_txs.py::test_eoa_tx_after_set_code\[fork_Prague-tx_type_3-evm_code_type_LEGACY-blockchain_test-different_block\]`) + bt.skipLoad(`^prague\/eip7702_set_code_tx\/set_code_txs\/eoa_tx_after_set_code.json\/tests\/prague\/eip7702_set_code_tx\/test_set_code_txs.py::test_eoa_tx_after_set_code\[fork_Prague-tx_type_3-evm_code_type_LEGACY-blockchain_test-same_block\]`) + // Kaia cannot calculate the same block hash as Ethereum + bt.skipLoad(`^frontier\/scenarios\/scenarios\/scenarios.json\/tests\/frontier\/scenarios\/test_scenarios.py::test_scenarios\[fork_Cancun-blockchain_test-program_BLOCKHASH-debug\]`) + bt.skipLoad(`^frontier\/scenarios\/scenarios\/scenarios.json\/tests\/frontier\/scenarios\/test_scenarios.py::test_scenarios\[fork_Prague-blockchain_test-program_BLOCKHASH-debug\]`) bt.walk(t, executionSpecBlockTestDir, func(t *testing.T, name string, test *BlockTest) { skipForks := []string{ @@ -91,6 +99,7 @@ func (suite *ExecutionSpecBlockTestSuite) TestExecutionSpecBlock() { "London", "Merge", "Paris", + "ParisToShanghaiAtTime15k", "Shanghai", "ShanghaiToCancunAtTime15k", "CancunToPragueAtTime15k", diff --git a/tests/block_test_util.go b/tests/block_test_util.go index f5d875646..95d2c38f6 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -118,18 +118,19 @@ type eestEngine struct { *gxhash.Gxhash baseFee *big.Int gasLimit uint64 + coinbase common.Address } var _ consensus.Engine = &eestEngine{} // This is called inside blockchain.ApplyTransaction to manipulate the evm configuration and recreate the eth. func (e *eestEngine) BeforeApplyMessage(evm *vm.EVM, msg *types.Transaction) { - // Change GasLimit to the one in the eth header + // Change BaseFee/GasLimit to the one in the eth header + evm.Context.BaseFee = e.baseFee evm.Context.GasLimit = e.gasLimit if evm.ChainConfig().Rules(evm.Context.BlockNumber).IsCancun { - // EIP-1052 must be activated for backward compatibility on Kaia. But EIP-2929 is activated instead of it on Ethereum - vm.ChangeGasCostForTest(&evm.Config.JumpTable, vm.EXTCODEHASH, params.WarmStorageReadCostEIP2929) + vm.ChangeGasCostForTest(&evm.Config.JumpTable) } // When istanbul is enabled, instrinsic gas is different from eth, so enable IsPrague to make them equal @@ -176,9 +177,14 @@ func (e *eestEngine) Finalize(chain consensus.ChainReader, header *types.Header, return types.NewBlock(header, txs, receipts), nil } +func (e *eestEngine) Author(header *types.Header) (common.Address, error) { + return e.coinbase, nil +} + func (e *eestEngine) applyHeader(h btHeader) { e.baseFee = h.BaseFee e.gasLimit = h.GasLimit + e.coinbase = h.Coinbase } func (t *BlockTest) Run() error { @@ -295,9 +301,11 @@ func (t *BlockTest) insertBlocks(bc *blockchain.BlockChain, gBlock types.Block, e.applyHeader(header) } - // var maxFeePerGas *big.Int blocks, _ := blockchain.GenerateChain(bc.Config(), preBlock, bc.Engine(), db, 1, func(i int, b *blockchain.BlockGen) { b.SetRewardbase(common.Address(header.Coinbase)) + b.SetMixHash(header.MixHash) + b.SetBaseFee(header.BaseFee) + b.SetTime(big.NewInt(int64(header.Time))) for _, tx := range txs { b.AddTxWithChainEvenHasError(bc, tx) } diff --git a/tests/state_test.go b/tests/state_test.go index 1a1bed68b..2b7840bf1 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -98,12 +98,15 @@ func (suite *ExecutionSpecStateTestSuite) TestExecutionSpecState() { st.skipLoad(`^cancun\/eip4788_beacon_root\/`) st.skipLoad(`^cancun\/eip4844_blobs\/`) // different amount of gas is consumed because 0x0b contract is added to access list by ActivePrecompiles although Cancun doesn't have it as a precompiled contract + st.skipLoad(`^frontier\/precompiles\/precompiles\/precompiles.json\/tests\/frontier\/precompiles\/test_precompiles.py::test_precompiles\[fork_Cancun-address_0xb-precompile_exists_False-state_test\]`) st.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-state_test-31_bytes\]`) st.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-state_test-32_bytes\]`) st.skipLoad(`^frontier\/precompiles\/precompile_absence\/precompile_absence.json\/tests\/frontier\/precompiles\/test_precompile_absence.py::test_precompile_absence\[fork_Cancun-state_test-empty_calldata\]`) - st.skipLoad(`^prague\/eip2537_bls_12_381_precompiles\/bls12_precompiles_before_fork\/precompile_before_fork.json\/tests\/prague\/eip2537_bls_12_381_precompiles\/test_bls12_precompiles_before_fork.py::test_precompile_before_fork\[fork_CancunToPragueAtTime15k-state_test--G1ADD\]`) + st.skipLoad(`^prague\/eip2537_bls_12_381_precompiles\/bls12_precompiles_before_fork\/precompile_before_fork.json\/tests\/prague\/eip2537_bls_12_381_precompiles\/test_bls12_precompiles_before_fork.py::test_precompile_before_fork\[fork_Cancun-state_test--G1ADD\]`) // type 3 tx (EIP-4844) is not supported st.skipLoad(`^prague\/eip7623_increase_calldata_cost\/.*type_3.*`) + // EIP-3607 is not implemented because Kaia can't reject the TxFromSenderEOA since Kaia have a contract code at the zero address and people usually use from == 0x0 to call the view function + st.skipLoad(`^prague\/eip7702_set_code_tx\/set_code_txs\/set_code_from_account_with_non_delegating_code.json\/tests\/prague\/eip7702_set_code_tx\/test_set_code_txs.py::test_set_code_from_account_with_non_delegating_code`) st.walk(t, executionSpecStateTestDir, func(t *testing.T, name string, test *StateTest) { execStateTest(t, st, test, name, []string{ diff --git a/tests/state_test_util.go b/tests/state_test_util.go index e093c469e..7459eb59f 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -292,6 +292,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, isTest blockContext := blockchain.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) blockContext.GetHash = vmTestBlockHash if isTestExecutionSpecState { + blockContext.BaseFee = t.json.Env.BaseFee blockContext.GasLimit = t.json.Env.GasLimit } evm := vm.NewEVM(blockContext, txContext, st, config, &vmconfig) @@ -507,8 +508,7 @@ func calculateEthGasPrice(r params.Rules, envGasPrice, envBaseFee, envMaxFeePerG func useEthOpCodeGas(r params.Rules, evm *vm.EVM) { if r.IsCancun { - // EIP-1052 must be activated for backward compatibility on Kaia. But EIP-2929 is activated instead of it on Ethereum - vm.ChangeGasCostForTest(&evm.Config.JumpTable, vm.EXTCODEHASH, params.WarmStorageReadCostEIP2929) + vm.ChangeGasCostForTest(&evm.Config.JumpTable) } }