Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: calls to non-existent contracts in the AVM simulator return failure #10051

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

dbanks12
Copy link
Contributor

@dbanks12 dbanks12 commented Nov 20, 2024

A call to a non-existent contract does nothing and returns failure. The nested context does not consume any gas. The getBytecode is still traced because the circuit will need a hint to know that it should do a non-membership check of the contract.

If it is a nested call, the CALL opcode consumes its regular gas, but the nested context consumes nothing, so the entire gas allocation is refunded to the caller.

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Comment on lines +936 to +950
it(`Nested call to non-existent contract `, async () => {
const calldata = [value0, value1];
const context = createContext(calldata);
const callBytecode = getAvmTestContractBytecode('nested_call_to_add');

const nestedTrace = mock<PublicSideEffectTraceInterface>();
mockTraceFork(trace, nestedTrace);

const results = await new AvmSimulator(context).executeBytecode(callBytecode);
expect(results.reverted).toBe(true);
expect(results.output).toEqual([]);

expectTracedNestedCall(context.environment, nestedTrace, /*isStaticCall=*/ false, /*exists=*/ false);
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing non-existent contract by not mocking getBytecode

Comment on lines -86 to 104
// This assumes that we will not be able to send messages to accounts without code
// Pending classes and instances impl details
if (!bytecode) {
throw new NoBytecodeForContractError(this.context.environment.address);
// revert without consuming any gas
const message = `No bytecode found at: ${this.context.environment.address}. Reverting...`;
const revertReason = new AvmRevertReason(
message,
/*failingFunction=*/ {
contractAddress: this.context.environment.address,
functionSelector: this.context.environment.functionSelector,
},
/*noirCallStack=*/ [],
);
this.log.warn(message);
return new AvmContractCallResult(
/*reverted=*/ true,
/*output=*/ [],
/*gasLeft=*/ this.context.machineState.gasLeft,
revertReason,
);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it bad to hand-craft an AvmRevertReason like this?

Comment on lines +90 to +94
// should only charge gas for the call instruction itself
// (all gas allocated to the nested call should be refunded)
const callGasCost = instruction.gasCost(argsSize);
expect(context.machineState.l2GasLeft).toEqual(initialL2Gas - callGasCost.l2Gas);
expect(context.machineState.daGasLeft).toEqual(initialDaGas - callGasCost.daGas);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed instruction.gasCost from protected to public so that I can confirm here that the external call is charging no more than the cost of the call opcode itself. Is that an acceptable decision?

Comment on lines 86 to -89
if (!bytecode) {
throw new NoBytecodeForContractError(this.context.environment.address);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we "throw" then we'd need to wrap calls to the AVM in try-catch. It would be fine for external calls, but breaks things for enqueued calls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant