ethereum / ethereumj

DEPRECATED! Java implementation of the Ethereum yellowpaper. For JSON-RPC and other client features check Ethereum Harmony
GNU Lesser General Public License v3.0
2.18k stars 1.1k forks source link

A bug on opcode CALL #1224

Open chenjiaweiprimeledger opened 5 years ago

chenjiaweiprimeledger commented 5 years ago

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.

mkalinin commented 5 years ago

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?

mitDarkMomo commented 5 years ago

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)));
    }