After initializing evm.interpreter make sure to point fhevmEnvironment to it evm.fhevmEnvironment.interpreter = evm.interpreter then initialize it fhevm.InitFhevm(&evm.fhevmEnvironment)
Update RunPrecompiledContract
After changing precompiled contract interface in 2, we have to change usages of:
// Create creates a new contract using code as deployment code.func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address()))// Create the ciphertext storage if not already created.if evm.StateDB.GetNonce(fhevm.CiphertextStorageAddress) ==0 { evm.StateDB.CreateAccount(fhevm.CiphertextStorageAddress) evm.StateDB.SetNonce(fhevm.CiphertextStorageAddress, 1) }return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr, CREATE)}// Create2 creates a new contract using code as deployment code.//// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
codeAndHash :=&codeAndHash{code: code} contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())// Create the ciphertext storage if not already created.if evm.StateDB.GetNonce(fhevm.CiphertextStorageAddress) ==0 { evm.StateDB.CreateAccount(fhevm.CiphertextStorageAddress) evm.StateDB.SetNonce(fhevm.CiphertextStorageAddress, 1) }return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)}
Implement EVMEnvironment interface
Now implement the fhevm.EVMEnvironment interface for FhevmImplementation:
func (evm *EVM) FhevmEnvironment() fhevm.EVMEnvironment { return&evm.fhevmEnvironment }// If you are using OpenTelemetry, you can return a context that the precompiled fhelib will use// to trace its internal functions. Otherwise, just return nilfunc (evm *FhevmImplementation) OtelContext() context.Context {returnnil}func (evm *FhevmImplementation) GetState(addr common.Address, hash common.Hash) common.Hash {return evm.interpreter.evm.StateDB.GetState(addr, hash)}func (evm *FhevmImplementation) SetState(addr common.Address, hash common.Hash, input common.Hash) { evm.interpreter.evm.StateDB.SetState(addr, hash, input)}func (evm *FhevmImplementation) GetNonce(addr common.Address) uint64 {return evm.interpreter.evm.StateDB.GetNonce(addr)}func (evm *FhevmImplementation) AddBalance(addr common.Address, value *big.Int) { evm.interpreter.evm.StateDB.AddBalance(addr, value)}func (evm *FhevmImplementation) GetBalance(addr common.Address) *big.Int {return evm.interpreter.evm.StateDB.GetBalance(addr)}func (evm *FhevmImplementation) Suicide(addr common.Address) bool { evm.interpreter.evm.StateDB.SelfDestruct(addr)return evm.interpreter.evm.StateDB.HasSelfDestructed(addr)}func (evm *FhevmImplementation) GetDepth() int {return evm.interpreter.evm.depth}func (evm *FhevmImplementation) IsCommitting() bool {return!evm.interpreter.evm.isGasEstimation}func (evm *FhevmImplementation) IsEthCall() bool {return evm.interpreter.evm.isEthCall}func (evm *FhevmImplementation) IsReadOnly() bool {return evm.interpreter.readOnly}func (evm *FhevmImplementation) GetLogger() fhevm.Logger {return evm.logger}func (evm *FhevmImplementation) FhevmData() *fhevm.FhevmData {return&evm.data}func (evm *FhevmImplementation) FhevmParams() *fhevm.FhevmParams {return&evm.params}func (evm *FhevmImplementation) CreateContract(caller common.Address, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
return evm.interpreter.evm.create(AccountRef(caller), &codeAndHash{code: code}, gas, value, address, CREATE)}func (evm *FhevmImplementation) CreateContract2(caller common.Address, code []byte, codeHash common.Hash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
return evm.interpreter.evm.create(AccountRef(caller), &codeAndHash{code: code, hash: codeHash}, gas, value, address, CREATE2)
}
Step 5: update core/vm/instructions.go
Update opSstore
Rewrite opSstore by a call to their fhevm implementation:
In func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
Just before original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()), add this block to increase SSTORE gas cost for storing a ciphertext: