Skip to content

Commit

Permalink
Merge pull request ethereum#1 from zama-ai/petar/v1.10.19
Browse files Browse the repository at this point in the history
Add in-memory state and restrict SLOAD/SSTORE
  • Loading branch information
dartdart26 committed Nov 24, 2022
2 parents 19b0337 + cefa1e0 commit 7804a56
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 3 deletions.
10 changes: 10 additions & 0 deletions core/vm/contracts.go
Expand Up @@ -48,6 +48,8 @@ var PrecompiledContractsHomestead = map[common.Address]StatefulPrecompiledContra
common.BytesToAddress([]byte{3}): newWrappedPrecompiledContract(&ripemd160hash{}),
common.BytesToAddress([]byte{4}): newWrappedPrecompiledContract(&dataCopy{}),
common.BytesToAddress([]byte{19}): &fheAdd{},
common.BytesToAddress([]byte{20}): &setMemoryState{},
common.BytesToAddress([]byte{21}): &getMemoryState{},
}

// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
Expand All @@ -62,6 +64,8 @@ var PrecompiledContractsByzantium = map[common.Address]StatefulPrecompiledContra
common.BytesToAddress([]byte{7}): newWrappedPrecompiledContract(&bn256ScalarMulByzantium{}),
common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingByzantium{}),
common.BytesToAddress([]byte{19}): &fheAdd{},
common.BytesToAddress([]byte{20}): &setMemoryState{},
common.BytesToAddress([]byte{21}): &getMemoryState{},
}

// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
Expand All @@ -77,6 +81,8 @@ var PrecompiledContractsIstanbul = map[common.Address]StatefulPrecompiledContrac
common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingIstanbul{}),
common.BytesToAddress([]byte{9}): newWrappedPrecompiledContract(&blake2F{}),
common.BytesToAddress([]byte{19}): &fheAdd{},
common.BytesToAddress([]byte{20}): &setMemoryState{},
common.BytesToAddress([]byte{21}): &getMemoryState{},
}

// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
Expand All @@ -92,6 +98,8 @@ var PrecompiledContractsBerlin = map[common.Address]StatefulPrecompiledContract{
common.BytesToAddress([]byte{8}): newWrappedPrecompiledContract(&bn256PairingIstanbul{}),
common.BytesToAddress([]byte{9}): newWrappedPrecompiledContract(&blake2F{}),
common.BytesToAddress([]byte{19}): &fheAdd{},
common.BytesToAddress([]byte{20}): &setMemoryState{},
common.BytesToAddress([]byte{21}): &getMemoryState{},
}

// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
Expand All @@ -107,6 +115,8 @@ var PrecompiledContractsBLS = map[common.Address]StatefulPrecompiledContract{
common.BytesToAddress([]byte{17}): newWrappedPrecompiledContract(&bls12381MapG1{}),
common.BytesToAddress([]byte{18}): newWrappedPrecompiledContract(&bls12381MapG2{}),
common.BytesToAddress([]byte{19}): &fheAdd{},
common.BytesToAddress([]byte{20}): &setMemoryState{},
common.BytesToAddress([]byte{21}): &getMemoryState{},
}

var (
Expand Down
20 changes: 20 additions & 0 deletions core/vm/contracts_stateful.go
Expand Up @@ -62,3 +62,23 @@ func (e *fheAdd) Run(accessibleState PrecompileAccessibleState, caller common.Ad

return input, suppliedGas, nil
}

type setMemoryState struct{}

func (c *setMemoryState) RequiredGas(input []byte) uint64 {
return 1
}

func (c *setMemoryState) Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
return []byte{}, suppliedGas, nil
}

type getMemoryState struct{}

func (c *getMemoryState) RequiredGas(input []byte) uint64 {
return 1
}

func (c *getMemoryState) Run(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
return []byte{}, suppliedGas, nil
}
19 changes: 18 additions & 1 deletion core/vm/evm.go
Expand Up @@ -121,6 +121,8 @@ type EVM struct {
// available gas is calculated in gasCall* according to the 63/64 rule and later
// applied in opCall*.
callGasTemp uint64
// some arbitrary in-memory state that lives as long as the enclosing EVM
inMemoryState []byte
}

// NewEVM returns a new EVM. The returned EVM is not thread safe and should
Expand All @@ -143,6 +145,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
func (evm *EVM) Reset(txCtx TxContext, statedb StateDB) {
evm.TxContext = txCtx
evm.StateDB = statedb
evm.inMemoryState = []byte{}
}

// Cancel cancels any running EVM operation. This may be called concurrently and
Expand Down Expand Up @@ -222,6 +225,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}

if isPrecompile {
// If it is the set memory state call, set the input to the EVM's in-memory state.
// Return whatever the precompiled contract returns.
if addr == common.BytesToAddress([]byte{20}) {
evm.inMemoryState = input
}
ret, gas, err = RunStatefulPrecompiledContract(p, evm, caller.Address(), addr, input, gas, evm.interpreter.readOnly)
} else {
// Initialise a new contract and set the code that is to be used by the EVM.
Expand Down Expand Up @@ -375,7 +383,16 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
}

if p, isPrecompile := evm.precompile(addr); isPrecompile {
ret, gas, err = RunStatefulPrecompiledContract(p, evm, caller.Address(), addr, input, gas, evm.interpreter.readOnly)
// If it is the get memory state call, return the EVM's in-memory state.
if addr == common.BytesToAddress([]byte{21}) {
if gas < p.RequiredGas(input) {
ret, gas, err = nil, 0, ErrOutOfGas
} else {
ret, gas, err = evm.inMemoryState, gas-p.RequiredGas(input), nil
}
} else {
ret, gas, err = RunStatefulPrecompiledContract(p, evm, caller.Address(), addr, input, gas, evm.interpreter.readOnly)
}
} else {
// At this point, we use a copy of address. If we don't, the go compiler will
// leak the 'contract' to the outer scope, and make allocation for 'contract'
Expand Down
17 changes: 15 additions & 2 deletions core/vm/instructions.go
Expand Up @@ -513,9 +513,22 @@ func opMstore8(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
return nil, nil
}

var locationModulus *uint256.Int

func init() {
locationModulus = uint256.NewInt(0)
locationModulus.SetAllOne()
locationModulus[3] = 0
}

func unprotectedLocation(loc uint256.Int) uint256.Int {
return *loc.Mod(&loc, locationModulus)
}

func opSload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
loc := scope.Stack.peek()
hash := common.Hash(loc.Bytes32())
actual_loc := unprotectedLocation(*loc)
hash := common.Hash(actual_loc.Bytes32())
val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash)
loc.SetBytes(val.Bytes())
return nil, nil
Expand All @@ -525,7 +538,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
if interpreter.readOnly {
return nil, ErrWriteProtection
}
loc := scope.Stack.pop()
loc := unprotectedLocation(scope.Stack.pop())
val := scope.Stack.pop()
interpreter.evm.StateDB.SetState(scope.Contract.Address(),
loc.Bytes32(), val.Bytes32())
Expand Down

0 comments on commit 7804a56

Please sign in to comment.