47da34c139
* Remove broken gas metering attempt * Add newline to fix lint * hardcode return value of eth_estimateGas to gas limit * evm: fix log message * state manager: safer calling * rpc: leave comment to help future debugging Co-authored-by: Karl Floersch <karl@karlfloersch.com> Co-authored-by: Kevin Ho <kevinjho1996@gmail.com>
138 lines
5.6 KiB
Go
138 lines
5.6 KiB
Go
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
)
|
|
|
|
type stateManagerFunction func(*EVM, *Contract, []byte) ([]byte, error)
|
|
|
|
var funcs = map[string]stateManagerFunction{
|
|
"getStorage(address,bytes32)": getStorage,
|
|
"setStorage(address,bytes32,bytes32)": setStorage,
|
|
"getOvmContractNonce(address)": getOvmContractNonce,
|
|
"incrementOvmContractNonce(address)": incrementOvmContractNonce,
|
|
"getCodeContractBytecode(address)": getCodeContractBytecode,
|
|
"getCodeContractHash(address)": getCodeContractHash,
|
|
"getCodeContractAddressFromOvmAddress(address)": getCodeContractAddress,
|
|
"associateCodeContract(address,address)": associateCodeContract,
|
|
"registerCreatedContract(address)": registerCreatedContract,
|
|
}
|
|
var methodIds map[[4]byte]stateManagerFunction
|
|
|
|
func init() {
|
|
methodIds = make(map[[4]byte]stateManagerFunction, len(funcs))
|
|
for methodSignature, f := range funcs {
|
|
methodIds[methodSignatureToMethodID(methodSignature)] = f
|
|
}
|
|
}
|
|
|
|
func methodSignatureToMethodID(methodSignature string) [4]byte {
|
|
var methodID [4]byte
|
|
copy(methodID[:], crypto.Keccak256([]byte(methodSignature)))
|
|
return methodID
|
|
}
|
|
|
|
func callStateManager(input []byte, evm *EVM, contract *Contract) (ret []byte, err error) {
|
|
var methodID [4]byte
|
|
if len(input) == 0 {
|
|
return nil, nil
|
|
}
|
|
copy(methodID[:], input[:4])
|
|
|
|
if method, ok := methodIds[methodID]; ok {
|
|
return method(evm, contract, input)
|
|
}
|
|
|
|
ret, err = methodIds[methodID](evm, contract, input)
|
|
return nil, fmt.Errorf("state manager call not found: %s", methodID)
|
|
}
|
|
|
|
func setStorage(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
key := common.BytesToHash(input[36:68])
|
|
val := common.BytesToHash(input[68:100])
|
|
log.Debug("[State Mgr] Setting storage.", "Contract address:", hex.EncodeToString(address.Bytes()), "key:", hex.EncodeToString(key.Bytes()), "val:", hex.EncodeToString(val.Bytes()))
|
|
evm.StateDB.SetState(address, key, val)
|
|
return nil, nil
|
|
}
|
|
|
|
func getStorage(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
key := common.BytesToHash(input[36:68])
|
|
val := evm.StateDB.GetState(address, key)
|
|
log.Debug("[State Mgr] Getting storage.", "Contract address:", hex.EncodeToString(address.Bytes()), "key:", hex.EncodeToString(key.Bytes()), "val:", hex.EncodeToString(val.Bytes()))
|
|
return val.Bytes(), nil
|
|
}
|
|
|
|
func getCodeContractBytecode(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
code := evm.StateDB.GetCode(address)
|
|
log.Debug("[State Mgr] Getting Bytecode.", " Contract address:", hex.EncodeToString(address.Bytes()), "Code:", hex.EncodeToString(code))
|
|
return simpleAbiEncode(code), nil
|
|
}
|
|
|
|
func getCodeContractHash(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
codeHash := evm.StateDB.GetCodeHash(address)
|
|
log.Debug("[State Mgr] Getting Code Hash.", " Contract address:", hex.EncodeToString(address.Bytes()), "Code hash:", hex.EncodeToString(codeHash.Bytes()))
|
|
return codeHash.Bytes(), nil
|
|
}
|
|
|
|
func associateCodeContract(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
log.Debug("[State Mgr] Associating code contract")
|
|
return []byte{}, nil
|
|
}
|
|
|
|
func registerCreatedContract(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
log.Debug("[State Mgr] Registering created contract")
|
|
return []byte{}, nil
|
|
}
|
|
|
|
func getCodeContractAddress(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := input[4:36]
|
|
// Ensure 0x0000...deadXXXX is not called as they are banned addresses (the address space used for the OVM contracts)
|
|
bannedAddresses := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 173}
|
|
if bytes.Equal(input[16:34], bannedAddresses) {
|
|
log.Error("[State Mgr] forbidden 0x...DEAD address access!", "Address", hex.EncodeToString(address))
|
|
return nil, errors.New("forbidden 0x...DEAD address access")
|
|
}
|
|
log.Debug("[State Mgr] Getting code contract.", "address:", hex.EncodeToString(address))
|
|
return address, nil
|
|
}
|
|
|
|
func getOvmContractNonce(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
b := make([]byte, 8)
|
|
binary.BigEndian.PutUint64(b, evm.StateDB.GetNonce(address))
|
|
val := append(make([]byte, 24), b[:]...)
|
|
log.Debug("[State Mgr] Getting nonce.", "Contract address:", hex.EncodeToString(address.Bytes()), "Nonce:", evm.StateDB.GetNonce(address))
|
|
return val, nil
|
|
}
|
|
|
|
func incrementOvmContractNonce(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
|
address := common.BytesToAddress(input[4:36])
|
|
oldNonce := evm.StateDB.GetNonce(address)
|
|
evm.StateDB.SetNonce(address, oldNonce+1)
|
|
log.Debug("[State Mgr] Incrementing nonce.", " Contract address:", hex.EncodeToString(address.Bytes()), "Nonce:", oldNonce+1)
|
|
return nil, nil
|
|
}
|
|
|
|
func simpleAbiEncode(bytes []byte) []byte {
|
|
encodedCode := make([]byte, WORD_SIZE)
|
|
binary.BigEndian.PutUint64(encodedCode[WORD_SIZE-8:], uint64(len(bytes)))
|
|
padding := make([]byte, len(bytes)%WORD_SIZE)
|
|
codeWithLength := append(append(encodedCode, bytes...), padding...)
|
|
offset := make([]byte, WORD_SIZE)
|
|
// Hardcode a 2 because we will only return dynamic bytes with a single element
|
|
binary.BigEndian.PutUint64(offset[WORD_SIZE-8:], uint64(2))
|
|
return append([]byte{0, 0}, append(offset, codeWithLength...)...)
|
|
}
|