-
Notifications
You must be signed in to change notification settings - Fork 129
Description
Recall the 4 types of calls in EVM: call/delegatecall/callcode/staticcall:
-
call: normal message calladdr1 { addr2.call() }the context of the addr2 contract execution:
contract.caller: addr1 contract.address: addr2 interpreter.readOnly: false -
staticcall: read-only message calladdr1 { addr2.staticcall() }the context of the addr2 contract execution:
contract.caller: addr1 contract.address: addr2 interpreter.readOnly: true -
callcode: message call into itself with another account's codeaddr1 { addr2.callcode() }the context of the addr2 contract execution:
contract.caller: addr1 contract.address: addr1 interpreter.readOnly: false -
delegatecall: likecallcode, but keeping the currentmsg.senderandmsg.value.addr1 { addr2.delegatecall() }the context of the addr2 contract execution:
contract.caller: originCaller contract.address: addr1 interpreter.readOnly: false
Cosmos Precompiles
Let's say the addr1 is an user contract which calls a precompile at the address addr2.
For the cosmos precompiles that will access the cosmos storages:
-
They should never be executed on the storage of another contract, that means
contract.address == addr2should always betrue, that'll rule out bothdelegatecallandcallcode. -
They should respect the
readOnlysemantic ofstaticcall, for normal contracts they'll check theinterpreter.readOnlyflag:if interpreter.readOnly { return nil, ErrWriteProtection }But for precompiles, we check the
readOnlyparameter passed to theRunmethod.
Proposal
The contract.address can be read from existing parameters in default Run method of precompile (but we need to change runPrecompiledContract to build the contract instance in the same way as EVM itself):
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) {
if contract.Address() != p.Address() {
return nil, errors.New("deletatecall and callcode are not supported")
}
}
func (p Precompile) WritableMethod(evm *vm.EVM) (bz []byte, err error) {
if evm.Interpreter().ReadOnly() {
return nil, vm.ErrWriteProtection
}
}
As a result, we can remove the readOnly parameter from the Run method, one less thing to patch the go-ethereum.
Patch go-ethereum
- Change
runPrecompiledContractto build theContractinstance in the same way as EVM itself, for exampleNewContract(originCaller, caller)in the case of delegatecall, so the precompiles can distinguish different types of calls.
Problem: precompile don't carry full EVM context go-ethereum#10