mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
Add StateManager set & getStorage
This commit is contained in:
parent
9de0a7a2d6
commit
7f0923b35e
5 changed files with 443 additions and 122 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -38,6 +38,9 @@ profile.cov
|
|||
# VS Code
|
||||
.vscode
|
||||
|
||||
# vim
|
||||
*.swp
|
||||
|
||||
# dashboard
|
||||
/dashboard/assets/flow-typed
|
||||
/dashboard/assets/node_modules
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ type (
|
|||
|
||||
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
|
||||
func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) {
|
||||
if contract.Address() == StateManagerAddress {
|
||||
return callStateManager(input, evm, contract)
|
||||
}
|
||||
if contract.Address() == StateManagerAddress {
|
||||
return callStateManager(input, evm, contract)
|
||||
}
|
||||
|
||||
if contract.CodeAddr != nil {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
|
|
@ -207,7 +207,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
to = AccountRef(addr)
|
||||
snapshot = evm.StateDB.Snapshot()
|
||||
)
|
||||
if !evm.StateDB.Exist(addr) && addr != StateManagerAddress {
|
||||
if !evm.StateDB.Exist(addr) && addr != StateManagerAddress {
|
||||
precompiles := PrecompiledContractsHomestead
|
||||
if evm.chainRules.IsByzantium {
|
||||
precompiles = PrecompiledContractsByzantium
|
||||
|
|
|
|||
|
|
@ -1,42 +1,39 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
StateManagerAddress = common.HexToAddress(os.Getenv("STATE_MANAGER_ADDRESS"))
|
||||
StateManagerAddress = common.HexToAddress(os.Getenv("STATE_MANAGER_ADDRESS"))
|
||||
)
|
||||
|
||||
type ovmOperation func(*EVM, *Contract, []byte) ([]byte, error)
|
||||
type stateManagerFunction func(*EVM, *Contract, []byte) ([]byte, error)
|
||||
type methodId [4]byte
|
||||
|
||||
var funcs = map[string]ovmOperation{
|
||||
"getStorage(address,bytes32)": getStorage,
|
||||
"setStorage(address,bytes32,bytes32)": setStorage,
|
||||
var funcs = map[string]stateManagerFunction{
|
||||
"getStorage(address,bytes32)": getStorage,
|
||||
"setStorage(address,bytes32,bytes32)": setStorage,
|
||||
}
|
||||
var methodIds map[[4]byte]ovmOperation
|
||||
var methodIds map[[4]byte]stateManagerFunction
|
||||
var executionMangerBytecode []byte
|
||||
|
||||
|
||||
func init() {
|
||||
methodIds = make(map[[4]byte]ovmOperation, len(funcs))
|
||||
methodIds = make(map[[4]byte]stateManagerFunction, len(funcs))
|
||||
for methodSignature, f := range funcs {
|
||||
methodIds[MethodSignatureToMethodId(methodSignature)] = f
|
||||
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
|
||||
copy(methodId[:], input[:4])
|
||||
|
|
@ -45,14 +42,16 @@ func callStateManager(input []byte, evm *EVM, contract *Contract) (ret []byte, e
|
|||
}
|
||||
|
||||
func setStorage(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
||||
key := common.BytesToHash(input[4:36])
|
||||
val := common.BytesToHash(input[36:68])
|
||||
evm.StateDB.SetState(contract.Address(), key, val)
|
||||
return nil, nil
|
||||
address := common.BytesToAddress(input[4:36])
|
||||
key := common.BytesToHash(input[36:68])
|
||||
val := common.BytesToHash(input[68:100])
|
||||
evm.StateDB.SetState(address, key, val)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func getStorage(evm *EVM, contract *Contract, input []byte) (ret []byte, err error) {
|
||||
key := common.BytesToHash(input[4:36])
|
||||
val := evm.StateDB.GetState(contract.Address(), key)
|
||||
address := common.BytesToAddress(input[4:36])
|
||||
key := common.BytesToHash(input[36:68])
|
||||
val := evm.StateDB.GetState(address, key)
|
||||
return val.Bytes(), nil
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
|
|
|||
398
tests/StateManagerABI.json
Normal file
398
tests/StateManagerABI.json
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
[
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "associateCodeContract",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractAddress",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractBytecode",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "codeContractBytecode",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractHash",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_codeContractHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getOvmContractNonce",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_slot",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "getStorage",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "incrementOvmContractNonce",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setOvmContractNonce",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_slot",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_value",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "setStorage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"evm": {
|
||||
"bytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
},
|
||||
"deployedBytecode": {
|
||||
"linkReferences": {},
|
||||
"object": "",
|
||||
"opcodes": "",
|
||||
"sourceMap": ""
|
||||
}
|
||||
},
|
||||
"interface": [
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "associateCodeContract",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractAddress",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractBytecode",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes",
|
||||
"name": "codeContractBytecode",
|
||||
"type": "bytes"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_codeContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getCodeContractHash",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_codeContractHash",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "getOvmContractNonce",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_slot",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "getStorage",
|
||||
"outputs": [
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
}
|
||||
],
|
||||
"name": "incrementOvmContractNonce",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "uint256",
|
||||
"name": "_value",
|
||||
"type": "uint256"
|
||||
}
|
||||
],
|
||||
"name": "setOvmContractNonce",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"internalType": "address",
|
||||
"name": "_ovmContractAddress",
|
||||
"type": "address"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_slot",
|
||||
"type": "bytes32"
|
||||
},
|
||||
{
|
||||
"internalType": "bytes32",
|
||||
"name": "_value",
|
||||
"type": "bytes32"
|
||||
}
|
||||
],
|
||||
"name": "setStorage",
|
||||
"outputs": [],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
||||
|
|
@ -2,9 +2,12 @@ package tests
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
|
|
@ -13,8 +16,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var KEY = common.FromHex("0102030000000000000000000000000000000000000000000000000000000000")
|
||||
var VALUE = common.FromHex("0405060000000000000000000000000000000000000000000000000000000000")
|
||||
var chainConfig params.ChainConfig
|
||||
|
||||
func init() {
|
||||
|
|
@ -32,72 +33,33 @@ func init() {
|
|||
}
|
||||
|
||||
func TestSloadAndStore(t *testing.T) {
|
||||
vm.StateManagerAddress = common.HexToAddress("42")
|
||||
rawStateManagerAbi, _ := ioutil.ReadFile("./StateManagerABI.json")
|
||||
stateManagerAbi, _ := abi.JSON(strings.NewReader(string(rawStateManagerAbi)))
|
||||
state := newState()
|
||||
setStorageMethodId := vm.MethodSignatureToMethodId("setStorage(address,bytes32,bytes32)")
|
||||
storeCode := setStorageMethodId[:]
|
||||
storeCode = append(storeCode, KEY...)
|
||||
storeCode = append(storeCode, VALUE...)
|
||||
getStorageMethodId := vm.MethodSignatureToMethodId("getStorage(address,bytes32)")
|
||||
loadCode := getStorageMethodId[:]
|
||||
loadCode = append(loadCode, KEY...)
|
||||
|
||||
call(t, state, vm.StateManagerAddress, storeCode)
|
||||
codeReturnValue, _ := call(t, state, vm.StateManagerAddress, loadCode)
|
||||
address := common.HexToAddress("9999999999999999999999999999999999999999")
|
||||
key := [32]byte{}
|
||||
value := [32]byte{}
|
||||
copy(key[:], []byte("hello"))
|
||||
copy(value[:], []byte("world"))
|
||||
|
||||
if !bytes.Equal(VALUE, codeReturnValue) {
|
||||
t.Errorf("Expected %020x; got %020x", VALUE, codeReturnValue)
|
||||
storeCalldata, _ := stateManagerAbi.Pack("setStorage", address, key, value)
|
||||
getCalldata, _ := stateManagerAbi.Pack("getStorage", address, key)
|
||||
|
||||
call(t, state, vm.StateManagerAddress, storeCalldata)
|
||||
getStorageReturnValue, _ := call(t, state, vm.StateManagerAddress, getCalldata)
|
||||
|
||||
if !bytes.Equal(value[:], getStorageReturnValue) {
|
||||
t.Errorf("Expected %020x; got %020x", value[:], getStorageReturnValue)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
callCode generates EVM bytecode which makes a single CALL with call data as
|
||||
it's input.
|
||||
*/
|
||||
func callCode(addr common.Address) []byte {
|
||||
output := []byte{}
|
||||
output = append(output, []byte{
|
||||
byte(vm.CALLDATASIZE),
|
||||
byte(vm.PUSH1), 0,
|
||||
byte(vm.PUSH1), 0,
|
||||
byte(vm.CALLDATACOPY),
|
||||
}...)
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, byte(vm.CALLDATASIZE))
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, pushN(0))
|
||||
output = append(output, int64ToBytes(0)...)
|
||||
output = append(output, []byte{
|
||||
byte(vm.PUSH20)}...)
|
||||
output = append(output, addr.Bytes()...)
|
||||
output = append(output, []byte{
|
||||
byte(vm.GAS),
|
||||
byte(vm.CALL),
|
||||
byte(vm.POP),
|
||||
byte(vm.RETURNDATASIZE),
|
||||
byte(vm.PUSH1), 0,
|
||||
byte(vm.PUSH1), 0,
|
||||
byte(vm.RETURNDATACOPY),
|
||||
byte(vm.RETURNDATASIZE),
|
||||
byte(vm.PUSH1), 0,
|
||||
byte(vm.RETURN),
|
||||
}...)
|
||||
return output
|
||||
}
|
||||
|
||||
func newState() *state.StateDB {
|
||||
db := state.NewDatabase(rawdb.NewMemoryDatabase())
|
||||
state, _ := state.New(common.Hash{}, db, nil)
|
||||
return state
|
||||
}
|
||||
|
||||
func call(t *testing.T, state *state.StateDB, address common.Address, callData []byte) ([]byte, error) {
|
||||
returnValue, _, err := runtime.Call(address, callData, &runtime.Config{
|
||||
State: state,
|
||||
|
|
@ -106,44 +68,3 @@ func call(t *testing.T, state *state.StateDB, address common.Address, callData [
|
|||
|
||||
return returnValue, err
|
||||
}
|
||||
|
||||
func int64ToBytes(n int64) []byte {
|
||||
if bytes.Equal(big.NewInt(n).Bytes(), []byte{}) {
|
||||
return []byte{0}
|
||||
} else {
|
||||
return big.NewInt(n).Bytes()
|
||||
}
|
||||
}
|
||||
func pushN(n int64) byte {
|
||||
return byte(int(vm.PUSH1) + byteLength(n) - 1)
|
||||
}
|
||||
func byteLength(n int64) int {
|
||||
if bytes.Equal(big.NewInt(n).Bytes(), []byte{}) {
|
||||
return 1
|
||||
} else {
|
||||
return len(big.NewInt(n).Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func mockPurityChecker(pure bool) []byte {
|
||||
var pureByte byte
|
||||
|
||||
if pure {
|
||||
pureByte = 1
|
||||
} else {
|
||||
pureByte = 0
|
||||
}
|
||||
|
||||
return []byte{
|
||||
byte(vm.PUSH1),
|
||||
pureByte,
|
||||
byte(vm.PUSH1),
|
||||
0,
|
||||
byte(vm.MSTORE8),
|
||||
byte(vm.PUSH1),
|
||||
1,
|
||||
byte(vm.PUSH1),
|
||||
0,
|
||||
byte(vm.RETURN),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue