ethereum/ethereumj

A bug on opcode CALL

chenjiaweiprimeledger opened this issue · 2 comments

When I executed ethereumj with a solidity program, I found that the requred gas is greater than left gas, throwing an exception.

org.ethereum.vm.VM#step

                DataWord gasLeft = program.getGas().clone();
                gasLeft.sub(new DataWord(gasCost));
                adjustedCallGas = **blockchainConfig.getCallGas(op, callGasWord, gasLeft)**;
                gasCost += adjustedCallGas.longValueSafe();

for example:
program.getGas()=100
gasCost=40
callGasWord comes from stack, it is 100 when call is contract call, and 0 when call is transfer. transfer is OK, but for contract call callGasWord is 100, gasLeft is 60, blockchainConfig.getCallGas will throw the exception.

The input is

gasLeft = 100; // gas left for the rest of the program execution
callGas = 100; // amount of gas that underlying call should be supplied with

The steps are

gasLeft = 100 - 40; // gasLeft is reduced by 40gas, the CALL price
if (callGas > gasLeft) throw; // program throws, cause there is not enough gas to supply underlying call

Isn't it a correct behavior?

The input is

gasLeft = 100; // gas left for the rest of the program execution
callGas = 100; // amount of gas that underlying call should be supplied with

The steps are

gasLeft = 100 - 40; // gasLeft is reduced by 40gas, the CALL price
if (callGas > gasLeft) throw; // program throws, cause there is not enough gas to supply underlying call

Isn't it a correct behavior?

It's a correct behavior, but not a correct logic.

Comment on BlockchainConfig.getCallGas() says:

Calculates available gas to be passed for callee Since EIP150

But i'm afraid it's not implemented in AbstractConfig.getCallGas(), try this:

public DataWord getCallGas(OpCode op, DataWord requestedGas, DataWord availableGas) throws Program.OutOfGasException {
        // modify to apply eip150
        // if (requestedGas.compareTo(availableGas) > 0) {
        //     throw Program.Exception.notEnoughOpGas(op, requestedGas, availableGas);
        // }
        // return requestedGas;
        return availableGas.sub(availableGas.div(DataWord.of(64)));
    }