what happened
Hey, I'm running some contracts to test ethereumjs/evm's security with other evms. I used evm.runCall to run solc generated bytecodes. Then I found that when dealing with specific contract, the gas costs of ethereumjs/evm differ from geth and py-evm(while these two vms' results are the same).
I'd like to know whether this is sort of bug or I should change my script to test jsevm better.
Thinks in advance.
Environment
- OS: Ubuntu 20.04
- solc 0.8.23
- node-v20.9.0-linux-x64
- @ethereumjs/evm@2.1.0
- @ethereumjs/util@9.0.1
- @ethereumjs/common@4.1.0
- @ethereumjs/blockchain@7.0.1
- @ethereumjs/statemanager@2.1.0
- memory-level@1.0.0
Here is my contract in solidity and the corresponding bytecode: src and bin.zip
My test script
runcode.js is the script I used to run bytecodes on ethereumjs
const { Account,Address,hexToBytes,bytesToHex } =require('@ethereumjs/util')
const { EVM } =require('@ethereumjs/evm')
const { Chain, Common, Hardfork,ConsensusType,ConsensusAlgorithm } =require('@ethereumjs/common')
const {Blockchain} = require('@ethereumjs/blockchain')
const { DefaultStateManager } =require('@ethereumjs/statemanager')
const { MemoryLevel } = require( 'memory-level')
const fs = require('fs');
const yargs = require('yargs')
yargs.option('code',{type:"string",demandOption:true})
.option('sig',{type:"string",demandOption:true})
var argv = yargs.argv
var code = '0x00'
var sig=argv.sig
// note that code has 0x prefix but sig doesn't
if (argv.code!=true){
code='0x'+argv.code
}
function uint8ArrayToHexString(uint8Array) {
let hexString = Array.from(uint8Array)
.map(byte => byte.toString(16).padStart(2, '0'))
.join('');
return hexString;
}
async function runEvmRunCall (){
const common = Common.custom({
chainId: 1234,
networkId: 1234,
defaultHardfork: Hardfork.Shanghai,
consensus: {
type: ConsensusType.ProofOfStake,
algorithm: ConsensusAlgorithm.Casper,
},
genesis: {
gasLimit: 10000000000,
difficulty: 1,
nonce: '0x0000000000000000',
extraData: '0x0',
},
comment: 'Custom empty chain for benchmarks',
bootstrapNodes: [],
dnsNetworks: [],
})
const db = new MemoryLevel()
const blockchain = await Blockchain.create(common,db)
const stateManager = new DefaultStateManager()
const evm = new EVM({ common,stateManager,blockchain })
evm.DEBUG=true
const contractCode = hexToBytes(code)
const contractAddress = Address.fromString('0x000000000000000000000000636F6E7472616374')
await evm.stateManager.putContractCode(contractAddress, contractCode)
evm.events.on('step', function (data) {
let hexStack = []
hexStack = data.stack.map(item => {
return '0x' + item.toString(16)
})
let hexMemory = '0x'
for (let i=0;i<data.memory.length;i++){
hexMemory += data.memory[i]
}
var opTrace = {
'pc': data.pc,
'gas': '0x' + data.gasLeft.toString(16),
'gasCost': '0x' + data.opcode.fee.toString(16),
'memory': hexMemory,
'memsize': data.memoryWordCount.toString(16),
'stack': hexStack,
'depth': data.depth,
'opName': data.opcode.name
}
opTrace_json = JSON.stringify(opTrace)
console.log(opTrace_json)
})
if(sig==undefined){
try{
const results = await evm.runCall({
code: hexToBytes(code),
gasLimit: BigInt('0x'+'ffff'),
to: contractAddress
}).catch(console.error);
var ret = {
'output':uint8ArrayToHexString(results.execResult.returnValue),
'gasUsed':'0x'+results.execResult.executionGasUsed.toString(16),
'error':results.execResult.exceptionError
}
ret_json = JSON.stringify(ret)
console.log(ret_json)
}
catch(err){
console.log(err)
}
}
// sig in defined
else {
sig=sig.toString(16)
if(sig.charAt(0)!= "0" && sig.charAt(1)!= "x"){
sig='0x'+sig
}
const results = await evm.runCall({
gasLimit: BigInt('0x'+'ffffff'),
data: hexToBytes(sig),
to: contractAddress,
caller: new Address(hexToBytes("0x1c7cd2d37ffd63856a5bd56a9af1643f2bcf545f"))
});
var ret = {
'output':uint8ArrayToHexString(results.execResult.returnValue),
'gasUsed':'0x'+results.execResult.executionGasUsed.toString(16),
'error':results.execResult.exceptionError
}
ret_json = JSON.stringify(ret)
console.log(ret_json)
}
}
runEvmRunCall()
Then I use this python script to call runcode.js, the command is python3 poc.py --sig 0x22ea223100000000000000000000000042a39d51fc07bb9c181a0b62df834575cb3b1aa40000000000000000000000000000000000000000000000000000000054c1f8e0 --code poc/D223ICO.bin-runtime
import subprocess
import argparse
def parse_args():
"""
Parse input arguments
"""
parser = argparse.ArgumentParser(description='Test a transaction')
parser.add_argument('--code', dest='code', default='./poc/xxx.bin-runtime', type=str)
# function signature bytecode
parser.add_argument('--sig', dest='signature', default='0x22ea223100000000000000000000000042a39d51fc07bb9c181a0b62df834575cb3b1aa40000000000000000000000000000000000000000000000000000000054c1f8e0', type=str)
args = parser.parse_args()
return args
PROJECT_DIR = "/home/alleysira/project"
args = parse_args()
codefile = open(args.code, "r")
bincode = codefile.read()
codefile.close()
sigName = args.signature
retcode = subprocess.call("node " + PROJECT_DIR + "/poc/runcode.js --code " + bincode + " --sig " + sigName + " > " + PROJECT_DIR + "/poc/jsout.json",shell=True)
The result will be added in the json file. In a similar way, I collected the results from geth and py-evm, then I found the gas cost of jsevm is 0x4a3a, which is different from 0x4076 of both geth and py-evm.
Here is the corresponding json file of 3 evms. gethout.json, jsout.json, pyout.json
Please enlighten me, thanks.
what happened
Hey, I'm running some contracts to test ethereumjs/evm's security with other evms. I used
evm.runCallto run solc generated bytecodes. Then I found that when dealing with specific contract, the gas costs of ethereumjs/evm differ from geth and py-evm(while these two vms' results are the same).I'd like to know whether this is sort of bug or I should change my script to test jsevm better.
Thinks in advance.
Environment
Here is my contract in solidity and the corresponding bytecode: src and bin.zip
My test script
runcode.jsis the script I used to run bytecodes on ethereumjsThen I use this python script to call runcode.js, the command is
python3 poc.py --sig 0x22ea223100000000000000000000000042a39d51fc07bb9c181a0b62df834575cb3b1aa40000000000000000000000000000000000000000000000000000000054c1f8e0 --code poc/D223ICO.bin-runtimeThe result will be added in the json file. In a similar way, I collected the results from geth and py-evm, then I found the gas cost of jsevm is 0x4a3a, which is different from 0x4076 of both geth and py-evm.
Here is the corresponding json file of 3 evms. gethout.json, jsout.json, pyout.json
Please enlighten me, thanks.