quorum/tests/util.go

328 lines
9.7 KiB
Go
Raw Normal View History

2016-04-14 09:18:24 -07:00
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
2015-07-06 17:54:22 -07:00
//
// The go-ethereum library is free software: you can redistribute it and/or modify
2015-07-06 17:54:22 -07:00
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
2015-07-06 17:54:22 -07:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2015-07-06 17:54:22 -07:00
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
2015-07-06 17:54:22 -07:00
2015-06-10 13:29:42 -07:00
package tests
import (
"bytes"
"fmt"
"math/big"
"os"
2015-06-10 13:29:42 -07:00
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
2015-06-10 13:29:42 -07:00
)
var (
ForceJit bool
EnableJit bool
)
func init() {
glog.SetV(0)
if os.Getenv("JITVM") == "true" {
ForceJit = true
EnableJit = true
}
}
func checkLogs(tlog []Log, logs vm.Logs) error {
2015-06-10 13:29:42 -07:00
if len(tlog) != len(logs) {
return fmt.Errorf("log length mismatch. Expected %d, got %d", len(tlog), len(logs))
} else {
for i, log := range tlog {
if common.HexToAddress(log.AddressF) != logs[i].Address {
return fmt.Errorf("log address expected %v got %x", log.AddressF, logs[i].Address)
}
if !bytes.Equal(logs[i].Data, common.FromHex(log.DataF)) {
return fmt.Errorf("log data expected %v got %x", log.DataF, logs[i].Data)
}
if len(log.TopicsF) != len(logs[i].Topics) {
return fmt.Errorf("log topics length expected %d got %d", len(log.TopicsF), logs[i].Topics)
} else {
for j, topic := range log.TopicsF {
if common.HexToHash(topic) != logs[i].Topics[j] {
return fmt.Errorf("log topic[%d] expected %v got %x", j, topic, logs[i].Topics[j])
}
}
}
genBloom := common.LeftPadBytes(types.LogsBloom(vm.Logs{logs[i]}).Bytes(), 256)
2015-06-10 13:29:42 -07:00
if !bytes.Equal(genBloom, common.Hex2Bytes(log.BloomF)) {
return fmt.Errorf("bloom mismatch")
}
}
}
return nil
}
type Account struct {
Balance string
Code string
Nonce string
Storage map[string]string
}
type Log struct {
AddressF string `json:"address"`
DataF string `json:"data"`
TopicsF []string `json:"topics"`
BloomF string `json:"bloom"`
}
func (self Log) Address() []byte { return common.Hex2Bytes(self.AddressF) }
func (self Log) Data() []byte { return common.Hex2Bytes(self.DataF) }
func (self Log) RlpData() interface{} { return nil }
func (self Log) Topics() [][]byte {
t := make([][]byte, len(self.TopicsF))
for i, topic := range self.TopicsF {
t[i] = common.Hex2Bytes(topic)
}
return t
}
func makePreState(db ethdb.Database, accounts map[string]Account) *state.StateDB {
statedb, _ := state.New(common.Hash{}, db)
for addr, account := range accounts {
insertAccount(statedb, addr, account)
}
return statedb
}
func insertAccount(state *state.StateDB, saddr string, account Account) {
2015-06-10 13:29:42 -07:00
if common.IsHex(account.Code) {
account.Code = account.Code[2:]
}
addr := common.HexToAddress(saddr)
state.SetCode(addr, common.Hex2Bytes(account.Code))
state.SetNonce(addr, common.Big(account.Nonce).Uint64())
state.SetBalance(addr, common.Big(account.Balance))
for a, v := range account.Storage {
state.SetState(addr, common.HexToHash(a), common.HexToHash(v))
}
2015-06-10 13:29:42 -07:00
}
type VmEnv struct {
CurrentCoinbase string
CurrentDifficulty string
CurrentGasLimit string
CurrentNumber string
CurrentTimestamp interface{}
PreviousHash string
}
type VmTest struct {
Callcreates interface{}
//Env map[string]string
Env VmEnv
Exec map[string]string
Transaction map[string]string
Logs []Log
Gas string
Out string
Post map[string]Account
Pre map[string]Account
PostStateRoot string
}
type RuleSet struct {
HomesteadBlock *big.Int
DAOForkBlock *big.Int
DAOForkSupport bool
HomesteadGasRepriceBlock *big.Int
}
func (r RuleSet) IsHomestead(n *big.Int) bool {
return n.Cmp(r.HomesteadBlock) >= 0
}
func (r RuleSet) GasTable(num *big.Int) params.GasTable {
if r.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(r.HomesteadGasRepriceBlock) < 0 {
return params.GasTableHomestead
}
return params.GasTableHomesteadGasRepriceFork
}
2015-06-10 13:29:42 -07:00
type Env struct {
ruleSet RuleSet
2015-06-10 13:29:42 -07:00
depth int
state *state.StateDB
skipTransfer bool
initial bool
Gas *big.Int
origin common.Address
parent common.Hash
2015-06-10 13:29:42 -07:00
coinbase common.Address
number *big.Int
time *big.Int
2015-06-10 13:29:42 -07:00
difficulty *big.Int
gasLimit *big.Int
vmTest bool
evm *vm.EVM
2015-06-10 13:29:42 -07:00
}
func NewEnv(ruleSet RuleSet, state *state.StateDB) *Env {
env := &Env{
ruleSet: ruleSet,
state: state,
2015-06-10 13:29:42 -07:00
}
return env
2015-06-10 13:29:42 -07:00
}
func NewEnvFromMap(ruleSet RuleSet, state *state.StateDB, envValues map[string]string, exeValues map[string]string) *Env {
env := NewEnv(ruleSet, state)
2015-06-10 13:29:42 -07:00
env.origin = common.HexToAddress(exeValues["caller"])
env.parent = common.HexToHash(envValues["previousHash"])
2015-06-10 13:29:42 -07:00
env.coinbase = common.HexToAddress(envValues["currentCoinbase"])
env.number = common.Big(envValues["currentNumber"])
env.time = common.Big(envValues["currentTimestamp"])
2015-06-10 13:29:42 -07:00
env.difficulty = common.Big(envValues["currentDifficulty"])
env.gasLimit = common.Big(envValues["currentGasLimit"])
env.Gas = new(big.Int)
env.evm = vm.New(env, vm.Config{
EnableJit: EnableJit,
ForceJit: ForceJit,
})
2015-06-10 13:29:42 -07:00
return env
}
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
func (self *Env) Vm() vm.Vm { return self.evm }
func (self *Env) Origin() common.Address { return self.origin }
func (self *Env) BlockNumber() *big.Int { return self.number }
2015-06-10 13:29:42 -07:00
func (self *Env) Coinbase() common.Address { return self.coinbase }
func (self *Env) Time() *big.Int { return self.time }
2015-06-10 13:29:42 -07:00
func (self *Env) Difficulty() *big.Int { return self.difficulty }
func (self *Env) Db() vm.Database { return self.state }
2015-06-10 13:29:42 -07:00
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
func (self *Env) VmType() vm.Type { return vm.StdVmTy }
func (self *Env) GetHash(n uint64) common.Hash {
return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
2015-06-10 13:29:42 -07:00
}
func (self *Env) AddLog(log *vm.Log) {
2015-06-10 13:29:42 -07:00
self.state.AddLog(log)
}
func (self *Env) Depth() int { return self.depth }
func (self *Env) SetDepth(i int) { self.depth = i }
func (self *Env) CanTransfer(from common.Address, balance *big.Int) bool {
2015-06-10 13:29:42 -07:00
if self.skipTransfer {
if self.initial {
self.initial = false
return true
2015-06-10 13:29:42 -07:00
}
}
2015-06-10 13:29:42 -07:00
return self.state.GetBalance(from).Cmp(balance) >= 0
}
func (self *Env) SnapshotDatabase() int {
return self.state.Snapshot()
}
func (self *Env) RevertToSnapshot(snapshot int) {
self.state.RevertToSnapshot(snapshot)
}
2015-06-10 13:29:42 -07:00
func (self *Env) Transfer(from, to vm.Account, amount *big.Int) {
if self.skipTransfer {
return
2015-06-10 13:29:42 -07:00
}
core.Transfer(from, to, amount)
2015-06-10 13:29:42 -07:00
}
func (self *Env) Call(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
2015-06-10 13:29:42 -07:00
if self.vmTest && self.depth > 0 {
caller.ReturnGas(gas, price)
return nil, nil
}
ret, err := core.Call(self, caller, addr, data, gas, price, value)
self.Gas = gas
2015-06-10 13:29:42 -07:00
return ret, err
}
func (self *Env) CallCode(caller vm.ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) {
2015-06-10 13:29:42 -07:00
if self.vmTest && self.depth > 0 {
caller.ReturnGas(gas, price)
return nil, nil
}
return core.CallCode(self, caller, addr, data, gas, price, value)
2015-06-10 13:29:42 -07:00
}
func (self *Env) DelegateCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) {
if self.vmTest && self.depth > 0 {
caller.ReturnGas(gas, price)
return nil, nil
}
return core.DelegateCall(self, caller, addr, data, gas, price)
}
func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) {
2015-06-10 13:29:42 -07:00
if self.vmTest {
caller.ReturnGas(gas, price)
nonce := self.state.GetNonce(caller.Address())
obj := self.state.GetOrNewStateObject(crypto.CreateAddress(caller.Address(), nonce))
return nil, obj.Address(), nil
2015-06-10 13:29:42 -07:00
} else {
return core.Create(self, caller, data, gas, price, value)
2015-06-10 13:29:42 -07:00
}
}
core, core/vm: dual state & read only EVM This commit implements a dual state approach. The dual state approach separates public and private state by making the core vm environment context aware. Although not currently implemented it will need to prohibit value transfers and it must initialise all transactions from accounts on the public state. This means that sending transactions increments the account nonce on the public state and contract addresses are derived from the public state when initialised by a transaction. For obvious reasons, contract created by private contracts are still derived from public state. This is required in order to have consensus over the public state at all times as non-private participants would still process the transaction on the public state even though private payload can not be decrypted. This means that participants of a private group must do the same in order to have public consensus. However the creation of the contract and interaction still occurs on the private state. It implements support for the following calling model: S: sender, (X): private, X: public, ->: direction, [ ]: read only mode 1. S -> A -> B 2. S -> (A) -> (B) 3. S -> (A) -> [ B -> C ] It does not support 1. (S) -> A 2. (S) -> (A) 3. S -> (A) -> B Implemented "read only" mode for the EVM. Read only mode is checked during any opcode that could potentially modify the state. If such an opcode is encountered during "read only", it throws an exception. The EVM is flagged "read only" when a private contract calls in to public state.
2016-10-31 04:46:40 -07:00
func (self *Env) ReadOnly() bool { return false }
2015-06-10 13:29:42 -07:00
type Message struct {
from common.Address
to *common.Address
value, gas, price *big.Int
data []byte
nonce uint64
}
func NewMessage(from common.Address, to *common.Address, data []byte, value, gas, price *big.Int, nonce uint64) Message {
return Message{from, to, value, gas, price, data, nonce}
}
func (self Message) Hash() []byte { return nil }
func (self Message) From() (common.Address, error) { return self.from, nil }
func (self Message) FromFrontier() (common.Address, error) { return self.from, nil }
func (self Message) To() *common.Address { return self.to }
func (self Message) GasPrice() *big.Int { return self.price }
func (self Message) Gas() *big.Int { return self.gas }
func (self Message) Value() *big.Int { return self.value }
func (self Message) Nonce() uint64 { return self.nonce }
func (self Message) CheckNonce() bool { return true }
func (self Message) Data() []byte { return self.data }