@@ -2,14 +2,14 @@ import { Chain, Common, Hardfork } from '@ethereumjs/common'
22import {
33 Account ,
44 Address ,
5- BIGINT_100 ,
65 MAX_UINT64 ,
76 bytesToBigInt ,
87 bytesToHex ,
98 concatBytes ,
109 hexToBytes ,
1110 padToEven ,
1211 unpadBytes ,
12+ zeros ,
1313} from '@ethereumjs/util'
1414import { keccak256 } from 'ethereum-cryptography/keccak.js'
1515import { assert , describe , it } from 'vitest'
@@ -724,38 +724,68 @@ describe('RunCall tests', () => {
724724 const evm = new EVM ( {
725725 common,
726726 } )
727- for ( const opcode of [ 'f1' , 'f2' ] ) {
728- // Code to either CALL or CALLCODE into the own address, with value 1
729- // JUMPDEST added at the start to track how much CALL(CODE)s are made
730- const contractCode = hexToBytes ( `0x5B6000808080600130611a90${ opcode } ` )
731- const contractAddress = Address . fromString ( '0x000000000000000000000000636F6E7472616374' )
732- await evm . stateManager . putContractCode ( contractAddress , contractCode )
733727
734- const account = await evm . stateManager . getAccount ( contractAddress )
735- account ! . balance = BIGINT_100
736-
737- await evm . stateManager . putAccount ( contractAddress , account )
728+ for ( const [ opcode , gas , expectedOutput ] of [
729+ [ 'f1' , 36600 , '0x' ] , // 36600 is CALL fee
730+ [ 'f2' , 11600 , '0x' ] , // 11600 is CALLCODE fee
731+ [ 'f1' , 36600 + 7 * 3 , '0x01' ] , // 36600 is CALL fee + 7 * 3 gas for 7 PUSH opcodes
732+ [ 'f2' , 11600 + 7 * 3 , '0x01' ] , // 11600 is CALLCODE fee + 7 * 3 gas for 7 PUSH opcodes
733+ ] ) {
734+ // Code to either CALL or CALLCODE into AACC empty contract, with value 1
735+ // If enough gas is provided, then since nonzero value is sent, the gas limit
736+ // in the call(coded) contract will get the "bonus gas" stipend of 2300
737+ // Previously, we added this gas stipend to the current gas available (which is wrong)
738+
739+ /***
740+ * Bytecode for AAAA contract (used to check CALL/CALLCODE execution when gas is less than required)
741+ * PUSH1 0x00
742+ * PUSH1 0x00
743+ * PUSH1 0x00
744+ * PUSH1 0x00
745+ * PUSH1 0x01
746+ * PUSH2 0xAACC
747+ * PUSH2 0x1a90 // Note: this is the gas available in the new call(code) frame, this value does not matter
748+ * CALLCODE/CALL
749+ */
750+ const callCodeAddress = Address . fromString ( '0x000000000000000000000000000000000000aaaa' )
751+ const callCode = hexToBytes ( `0x6000600060006000600161AACC611a90${ opcode } ` )
752+
753+ const gasLimit = gas . toString ( 16 ) . padStart ( 4 , '0' )
754+
755+ /***
756+ * Bytecode for AAAB contract (used to call contract AAAA and stores result of call execution)
757+ * PUSH1 0x00
758+ * DUP1
759+ * DUP1
760+ * DUP1
761+ * DUP1
762+ * PUSH2 0xAAAA
763+ * PUSH2 0x{gas} <- This is the gas limit set for the CALL/CODE execution
764+ * CALL
765+ * PUSH1 0x00
766+ * SSTORE
767+ */
768+ const callerAddress = Address . fromString ( '0x000000000000000000000000000000000000aaab' )
769+ const callerCode = hexToBytes ( `0x60008080808061AAAA61${ gasLimit } f1600055` )
770+
771+ await evm . stateManager . putAccount ( callCodeAddress , new Account ( ) )
772+ await evm . stateManager . putContractCode ( callCodeAddress , callCode )
773+
774+ await evm . stateManager . putAccount ( callerAddress , new Account ( undefined , BigInt ( 1 ) ) )
775+ await evm . stateManager . putContractCode ( callerAddress , callerCode )
738776
739777 const runCallArgs = {
740- gasLimit : BigInt ( 50000 - 21000 ) ,
741- to : contractAddress ,
778+ to : callerAddress ,
779+ gasLimit : 0xfffffffn ,
742780 }
743-
744- let jumpdestCalls = 0
745-
746- evm . events . on ( 'step' , ( e ) => {
747- if ( e . opcode . name === 'JUMPDEST' ) {
748- jumpdestCalls ++
749- }
750- } )
751-
752781 await evm . runCall ( runCallArgs )
753- // JUMPDEST should be called twice:
754- // 1: call into the contract (externally, via tx)
755- // 2: call(code) into the contract (internally)
756- // If jumpdest would run >=3 times, it means the (2) has enough gas to pay for CALL(CODE)
757- // This is not correct
758- assert . ok ( jumpdestCalls === 2 , 'called JUMPDEST twice' )
782+
783+ const callResult = bytesToHex (
784+ await evm . stateManager . getContractStorage ( callerAddress , zeros ( 32 ) )
785+ )
786+ // Expect slot to have value of either: 0 since CALLCODE and CODE did not have enough gas to execute
787+ // Or 1, if CALL(CODE) has enough gas to enter the new call frame
788+ assert . equal ( callResult , expectedOutput , `should have result ${ expectedOutput } ` )
759789 }
760790 } )
761791} )
0 commit comments