Refactored to new state and vm

This commit is contained in:
obscuren 2014-07-24 12:04:15 +02:00
parent 958b482ada
commit 32d125131f
20 changed files with 196 additions and 2025 deletions

View File

@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof Ethereum is currently in its testing phase. The current state is "Proof
of Concept 0.5.20". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). of Concept 0.6.0". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each Ethereum Go is split up in several sub packages Please refer to each
individual package for more information. individual package for more information.

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
@ -39,7 +40,7 @@ type Block struct {
Coinbase []byte Coinbase []byte
// Block Trie state // Block Trie state
//state *ethutil.Trie //state *ethutil.Trie
state *State state *ethstate.State
// Difficulty for the current block // Difficulty for the current block
Difficulty *big.Int Difficulty *big.Int
// Creation time // Creation time
@ -104,7 +105,7 @@ func CreateBlock(root interface{},
} }
block.SetUncles([]*Block{}) block.SetUncles([]*Block{})
block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, root)) block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root))
return block return block
} }
@ -116,12 +117,12 @@ func (block *Block) Hash() []byte {
func (block *Block) HashNoNonce() []byte { func (block *Block) HashNoNonce() []byte {
return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, return ethcrypto.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash,
block.UncleSha, block.Coinbase, block.state.trie.Root, block.UncleSha, block.Coinbase, block.state.Trie.Root,
block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, block.TxSha, block.Difficulty, block.Number, block.MinGasPrice,
block.GasLimit, block.GasUsed, block.Time, block.Extra})) block.GasLimit, block.GasUsed, block.Time, block.Extra}))
} }
func (block *Block) State() *State { func (block *Block) State() *ethstate.State {
return block.state return block.state
} }
@ -140,17 +141,17 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
base := new(big.Int) base := new(big.Int)
contract.Amount = base.Sub(contract.Amount, fee) contract.Amount = base.Sub(contract.Amount, fee)
block.state.trie.Update(string(addr), string(contract.RlpEncode())) block.state.Trie.Update(string(addr), string(contract.RlpEncode()))
data := block.state.trie.Get(string(block.Coinbase)) data := block.state.Trie.Get(string(block.Coinbase))
// Get the ether (Coinbase) and add the fee (gief fee to miner) // Get the ether (Coinbase) and add the fee (gief fee to miner)
account := NewStateObjectFromBytes(block.Coinbase, []byte(data)) account := ethstate.NewStateObjectFromBytes(block.Coinbase, []byte(data))
base = new(big.Int) base = new(big.Int)
account.Amount = base.Add(account.Amount, fee) account.Amount = base.Add(account.Amount, fee)
//block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode())) //block.state.Trie.Update(string(block.Coinbase), string(ether.RlpEncode()))
block.state.UpdateStateObject(account) block.state.UpdateStateObject(account)
return true return true
@ -312,7 +313,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block.PrevHash = header.Get(0).Bytes() block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).Bytes() block.UncleSha = header.Get(1).Bytes()
block.Coinbase = header.Get(2).Bytes() block.Coinbase = header.Get(2).Bytes()
block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val))
block.TxSha = header.Get(4).Bytes() block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt() block.Difficulty = header.Get(5).BigInt()
block.Number = header.Get(6).BigInt() block.Number = header.Get(6).BigInt()
@ -354,7 +355,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
block.PrevHash = header.Get(0).Bytes() block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).Bytes() block.UncleSha = header.Get(1).Bytes()
block.Coinbase = header.Get(2).Bytes() block.Coinbase = header.Get(2).Bytes()
block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, header.Get(3).Val))
block.TxSha = header.Get(4).Bytes() block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt() block.Difficulty = header.Get(5).BigInt()
block.Number = header.Get(6).BigInt() block.Number = header.Get(6).BigInt()
@ -369,7 +370,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
} }
func (block *Block) GetRoot() interface{} { func (block *Block) GetRoot() interface{} {
return block.state.trie.Root return block.state.Trie.Root
} }
func (self *Block) Receipts() []*Receipt { func (self *Block) Receipts() []*Receipt {
@ -385,7 +386,7 @@ func (block *Block) header() []interface{} {
// Coinbase address // Coinbase address
block.Coinbase, block.Coinbase,
// root state // root state
block.state.trie.Root, block.state.Trie.Root,
// Sha of tx // Sha of tx
block.TxSha, block.TxSha,
// Current block Difficulty // Current block Difficulty
@ -429,7 +430,7 @@ func (block *Block) String() string {
block.PrevHash, block.PrevHash,
block.UncleSha, block.UncleSha,
block.Coinbase, block.Coinbase,
block.state.trie.Root, block.state.Trie.Root,
block.TxSha, block.TxSha,
block.Difficulty, block.Difficulty,
block.Number, block.Number,

View File

@ -44,7 +44,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
hash := ZeroHash256 hash := ZeroHash256
if bc.CurrentBlock != nil { if bc.CurrentBlock != nil {
root = bc.CurrentBlock.state.trie.Root root = bc.CurrentBlock.state.Trie.Root
hash = bc.LastBlockHash hash = bc.LastBlockHash
lastBlockTime = bc.CurrentBlock.Time lastBlockTime = bc.CurrentBlock.Time
} }
@ -297,7 +297,7 @@ func (bc *BlockChain) setLastBlock() {
} else { } else {
AddTestNetFunds(bc.genesisBlock) AddTestNetFunds(bc.genesisBlock)
bc.genesisBlock.state.trie.Sync() bc.genesisBlock.state.Trie.Sync()
// Prepare the genesis block // Prepare the genesis block
bc.Add(bc.genesisBlock) bc.Add(bc.genesisBlock)

View File

@ -1,121 +0,0 @@
package ethchain
// TODO Re write VM to use values instead of big integers?
import (
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type ClosureRef interface {
ReturnGas(*big.Int, *big.Int, *State)
Address() []byte
GetStorage(*big.Int) *ethutil.Value
SetStorage(*big.Int, *ethutil.Value)
N() *big.Int
}
// Basic inline closure object which implement the 'closure' interface
type Closure struct {
caller ClosureRef
object *StateObject
Script []byte
State *State
Gas, UsedGas, Price *big.Int
Args []byte
}
// Create a new closure for the given data items
func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure {
c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil}
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
c.Gas = gas //new(big.Int).Set(gas)
// In most cases price and value are pointers to transaction objects
// and we don't want the transaction's values to change.
c.Price = new(big.Int).Set(price)
c.UsedGas = new(big.Int)
return c
}
// Retuns the x element in data slice
func (c *Closure) GetStorage(x *big.Int) *ethutil.Value {
m := c.object.GetStorage(x)
if m == nil {
return ethutil.EmptyValue()
}
return m
}
func (c *Closure) Get(x *big.Int) *ethutil.Value {
return c.Gets(x, big.NewInt(1))
}
func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) {
return ethutil.NewValue(0)
}
partial := c.Script[x.Int64() : x.Int64()+y.Int64()]
return ethutil.NewValue(partial)
}
func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) {
c.object.SetStorage(x, val)
}
func (c *Closure) Address() []byte {
return c.object.Address()
}
func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) {
c.Args = args
ret, err := vm.RunClosure(c)
return ret, c.UsedGas, err
}
func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the caller
c.caller.ReturnGas(c.Gas, c.Price, c.State)
return ret
}
func (c *Closure) UseGas(gas *big.Int) bool {
if c.Gas.Cmp(gas) < 0 {
return false
}
// Sub the amount of gas from the remaining
c.Gas.Sub(c.Gas, gas)
c.UsedGas.Add(c.UsedGas, gas)
return true
}
// Implement the caller interface
func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
// Return the gas to the closure
c.Gas.Add(c.Gas, gas)
c.UsedGas.Sub(c.UsedGas, gas)
}
func (c *Closure) Object() *StateObject {
return c.object
}
func (c *Closure) Caller() ClosureRef {
return c.caller
}
func (c *Closure) N() *big.Int {
return c.object.N()
}

View File

@ -1,150 +0,0 @@
package ethchain
import (
"fmt"
"math"
"math/big"
)
type OpType int
const (
tNorm = iota
tData
tExtro
tCrypto
)
type TxCallback func(opType OpType) bool
// Simple push/pop stack mechanism
type Stack struct {
data []*big.Int
}
func NewStack() *Stack {
return &Stack{}
}
func (st *Stack) Data() []*big.Int {
return st.data
}
func (st *Stack) Len() int {
return len(st.data)
}
func (st *Stack) Pop() *big.Int {
str := st.data[len(st.data)-1]
copy(st.data[:len(st.data)-1], st.data[:len(st.data)-1])
st.data = st.data[:len(st.data)-1]
return str
}
func (st *Stack) Popn() (*big.Int, *big.Int) {
ints := st.data[len(st.data)-2:]
copy(st.data[:len(st.data)-2], st.data[:len(st.data)-2])
st.data = st.data[:len(st.data)-2]
return ints[0], ints[1]
}
func (st *Stack) Peek() *big.Int {
str := st.data[len(st.data)-1]
return str
}
func (st *Stack) Peekn() (*big.Int, *big.Int) {
ints := st.data[:2]
return ints[0], ints[1]
}
func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, new(big.Int).Set(d))
}
func (st *Stack) Get(amount *big.Int) []*big.Int {
// offset + size <= len(data)
length := big.NewInt(int64(len(st.data)))
if amount.Cmp(length) <= 0 {
start := new(big.Int).Sub(length, amount)
return st.data[start.Int64():length.Int64()]
}
return nil
}
func (st *Stack) Print() {
fmt.Println("### stack ###")
if len(st.data) > 0 {
for i, val := range st.data {
fmt.Printf("%-3d %v\n", i, val)
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("#############")
}
type Memory struct {
store []byte
}
func (m *Memory) Set(offset, size int64, value []byte) {
totSize := offset + size
lenSize := int64(len(m.store) - 1)
if totSize > lenSize {
// Calculate the diff between the sizes
diff := totSize - lenSize
if diff > 0 {
// Create a new empty slice and append it
newSlice := make([]byte, diff-1)
// Resize slice
m.store = append(m.store, newSlice...)
}
}
copy(m.store[offset:offset+size], value)
}
func (m *Memory) Resize(size uint64) {
if uint64(m.Len()) < size {
m.store = append(m.store, make([]byte, size-uint64(m.Len()))...)
}
}
func (m *Memory) Get(offset, size int64) []byte {
if len(m.store) > int(offset) {
end := int(math.Min(float64(len(m.store)), float64(offset+size)))
return m.store[offset:end]
}
return nil
}
func (m *Memory) Len() int {
return len(m.store)
}
func (m *Memory) Data() []byte {
return m.store
}
func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.store))
if len(m.store) > 0 {
addr := 0
for i := 0; i+32 <= len(m.store); i += 32 {
fmt.Printf("%03d: % x\n", addr, m.store[i:i+32])
addr++
}
} else {
fmt.Println("-- empty --")
}
fmt.Println("####################")
}

View File

@ -1,250 +0,0 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
// States within the ethereum protocol are used to store anything
// within the merkle trie. States take care of caching and storing
// nested states. It's the general query interface to retrieve:
// * Contracts
// * Accounts
type State struct {
// The trie for this structure
trie *ethtrie.Trie
stateObjects map[string]*StateObject
manifest *Manifest
}
// Create a new state from a given trie
func NewState(trie *ethtrie.Trie) *State {
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
}
// Retrieve the balance from the given address or 0 if object not found
func (self *State) GetBalance(addr []byte) *big.Int {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.Amount
}
return ethutil.Big0
}
func (self *State) GetNonce(addr []byte) uint64 {
stateObject := self.GetStateObject(addr)
if stateObject != nil {
return stateObject.Nonce
}
return 0
}
//
// Setting, updating & deleting state object methods
//
// Update the given state object and apply it to state trie
func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
self.trie.Update(string(addr), string(stateObject.RlpEncode()))
self.manifest.AddObjectChange(stateObject)
}
// Delete the given state object and delete it from the state trie
func (self *State) DeleteStateObject(stateObject *StateObject) {
self.trie.Delete(string(stateObject.Address()))
delete(self.stateObjects, string(stateObject.Address()))
}
// Retrieve a state object given my the address. Nil if not found
func (self *State) GetStateObject(addr []byte) *StateObject {
addr = ethutil.Address(addr)
stateObject := self.stateObjects[string(addr)]
if stateObject != nil {
return stateObject
}
data := self.trie.Get(string(addr))
if len(data) == 0 {
return nil
}
stateObject = NewStateObjectFromBytes(addr, []byte(data))
self.stateObjects[string(addr)] = stateObject
return stateObject
}
// Retrieve a state object or create a new state object if nil
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
stateObject := self.GetStateObject(addr)
if stateObject == nil {
stateObject = self.NewStateObject(addr)
}
return stateObject
}
// Create a state object whether it exist in the trie or not
func (self *State) NewStateObject(addr []byte) *StateObject {
statelogger.Infof("(+) %x\n", addr)
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
return stateObject
}
// Deprecated
func (self *State) GetAccount(addr []byte) *StateObject {
return self.GetOrNewStateObject(addr)
}
//
// Setting, copying of the state methods
//
func (s *State) Cmp(other *State) bool {
return s.trie.Cmp(other.trie)
}
func (self *State) Copy() *State {
if self.trie != nil {
state := NewState(self.trie.Copy())
for k, stateObject := range self.stateObjects {
state.stateObjects[k] = stateObject.Copy()
}
return state
}
return nil
}
func (self *State) Set(state *State) {
if state == nil {
panic("Tried setting 'state' to nil through 'Set'")
}
self.trie = state.trie
self.stateObjects = state.stateObjects
}
func (s *State) Root() interface{} {
return s.trie.Root
}
// Resets the trie and all siblings
func (s *State) Reset() {
s.trie.Undo()
// Reset all nested states
for _, stateObject := range s.stateObjects {
if stateObject.state == nil {
continue
}
//stateObject.state.Reset()
stateObject.Reset()
}
s.Empty()
}
// Syncs the trie and all siblings
func (s *State) Sync() {
// Sync all nested states
for _, stateObject := range s.stateObjects {
//s.UpdateStateObject(stateObject)
if stateObject.state == nil {
continue
}
stateObject.state.Sync()
}
s.trie.Sync()
s.Empty()
}
func (self *State) Empty() {
self.stateObjects = make(map[string]*StateObject)
}
func (self *State) Update() {
for _, stateObject := range self.stateObjects {
if stateObject.remove {
self.DeleteStateObject(stateObject)
} else {
stateObject.Sync()
self.UpdateStateObject(stateObject)
}
}
// FIXME trie delete is broken
valid, t2 := ethtrie.ParanoiaCheck(self.trie)
if !valid {
statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root)
self.trie = t2
}
}
// Debug stuff
func (self *State) CreateOutputForDiff() {
for _, stateObject := range self.stateObjects {
stateObject.CreateOutputForDiff()
}
}
// Object manifest
//
// The object manifest is used to keep changes to the state so we can keep track of the changes
// that occurred during a state transitioning phase.
type Manifest struct {
// XXX These will be handy in the future. Not important for now.
objectAddresses map[string]bool
storageAddresses map[string]map[string]bool
objectChanges map[string]*StateObject
storageChanges map[string]map[string]*big.Int
}
func NewManifest() *Manifest {
m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)}
m.Reset()
return m
}
func (m *Manifest) Reset() {
m.objectChanges = make(map[string]*StateObject)
m.storageChanges = make(map[string]map[string]*big.Int)
}
func (m *Manifest) AddObjectChange(stateObject *StateObject) {
m.objectChanges[string(stateObject.Address())] = stateObject
}
func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) {
if m.storageChanges[string(stateObject.Address())] == nil {
m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int)
}
m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage
}

View File

@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
_ "github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethwire"
"math/big" "math/big"
@ -50,8 +50,6 @@ type StateManager struct {
mutex sync.Mutex mutex sync.Mutex
// Canonical block chain // Canonical block chain
bc *BlockChain bc *BlockChain
// Stack for processing contracts
stack *Stack
// non-persistent key/value memory storage // non-persistent key/value memory storage
mem map[string]*big.Int mem map[string]*big.Int
// Proof of work used for validating // Proof of work used for validating
@ -62,10 +60,10 @@ type StateManager struct {
// Transiently state. The trans state isn't ever saved, validated and // Transiently state. The trans state isn't ever saved, validated and
// it could be used for setting account nonces without effecting // it could be used for setting account nonces without effecting
// the main states. // the main states.
transState *State transState *ethstate.State
// Mining state. The mining state is used purely and solely by the mining // Mining state. The mining state is used purely and solely by the mining
// operation. // operation.
miningState *State miningState *ethstate.State
// The last attempted block is mainly used for debugging purposes // The last attempted block is mainly used for debugging purposes
// This does not have to be a valid block and will be set during // This does not have to be a valid block and will be set during
@ -75,7 +73,6 @@ type StateManager struct {
func NewStateManager(ethereum EthManager) *StateManager { func NewStateManager(ethereum EthManager) *StateManager {
sm := &StateManager{ sm := &StateManager{
stack: NewStack(),
mem: make(map[string]*big.Int), mem: make(map[string]*big.Int),
Pow: &EasyPow{}, Pow: &EasyPow{},
Ethereum: ethereum, Ethereum: ethereum,
@ -87,19 +84,19 @@ func NewStateManager(ethereum EthManager) *StateManager {
return sm return sm
} }
func (sm *StateManager) CurrentState() *State { func (sm *StateManager) CurrentState() *ethstate.State {
return sm.Ethereum.BlockChain().CurrentBlock.State() return sm.Ethereum.BlockChain().CurrentBlock.State()
} }
func (sm *StateManager) TransState() *State { func (sm *StateManager) TransState() *ethstate.State {
return sm.transState return sm.transState
} }
func (sm *StateManager) MiningState() *State { func (sm *StateManager) MiningState() *ethstate.State {
return sm.miningState return sm.miningState
} }
func (sm *StateManager) NewMiningState() *State { func (sm *StateManager) NewMiningState() *ethstate.State {
sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy() sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy()
return sm.miningState return sm.miningState
@ -109,7 +106,7 @@ func (sm *StateManager) BlockChain() *BlockChain {
return sm.bc return sm.bc
} }
func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) {
var ( var (
receipts Receipts receipts Receipts
handled, unhandled Transactions handled, unhandled Transactions
@ -225,7 +222,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
} }
if !block.State().Cmp(state) { if !block.State().Cmp(state) {
err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().Trie.Root, state.Trie.Root)
return return
} }
@ -242,7 +239,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
if dontReact == false { if dontReact == false {
sm.Ethereum.Reactor().Post("newBlock", block) sm.Ethereum.Reactor().Post("newBlock", block)
state.manifest.Reset() state.Manifest().Reset()
} }
sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
@ -255,7 +252,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
return nil return nil
} }
func (sm *StateManager) ApplyDiff(state *State, parent, block *Block) (receipts Receipts, err error) { func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) {
coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase := state.GetOrNewStateObject(block.Coinbase)
coinbase.SetGasPool(block.CalcGasLimit(parent)) coinbase.SetGasPool(block.CalcGasLimit(parent))
@ -340,7 +337,7 @@ func CalculateUncleReward(block *Block) *big.Int {
return UncleReward return UncleReward
} }
func (sm *StateManager) AccumelateRewards(state *State, block *Block) error { func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error {
// Get the account associated with the coinbase // Get the account associated with the coinbase
account := state.GetAccount(block.Coinbase) account := state.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address // Reward amount of ether to the coinbase address
@ -364,14 +361,14 @@ func (sm *StateManager) Stop() {
sm.bc.Stop() sm.bc.Stop()
} }
func (sm *StateManager) notifyChanges(state *State) { func (sm *StateManager) notifyChanges(state *ethstate.State) {
for addr, stateObject := range state.manifest.objectChanges { for addr, stateObject := range state.Manifest().ObjectChanges {
sm.Ethereum.Reactor().Post("object:"+addr, stateObject) sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
} }
for stateObjectAddr, mappedObjects := range state.manifest.storageChanges { for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
for addr, value := range mappedObjects { for addr, value := range mappedObjects {
sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
} }
} }
} }

View File

@ -1,368 +0,0 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"strings"
)
type Code []byte
func (self Code) String() string {
return strings.Join(Disassemble(self), " ")
}
type Storage map[string]*ethutil.Value
func (self Storage) Copy() Storage {
cpy := make(Storage)
for key, value := range self {
// XXX Do we need a 'value' copy or is this sufficient?
cpy[key] = value
}
return cpy
}
type StateObject struct {
// Address of the object
address []byte
// Shared attributes
Amount *big.Int
ScriptHash []byte
Nonce uint64
// Contract related attributes
state *State
script Code
initScript Code
storage Storage
// Total gas pool is the total amount of gas currently
// left if this object is the coinbase. Gas is directly
// purchased of the coinbase.
gasPool *big.Int
// Mark for deletion
// When an object is marked for deletion it will be delete from the trie
// during the "update" phase of the state transition
remove bool
}
func (self *StateObject) Reset() {
self.storage = make(Storage)
self.state.Reset()
}
// Converts an transaction in to a state object
func MakeContract(tx *Transaction, state *State) *StateObject {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.CreationAddress()
contract := state.NewStateObject(addr)
contract.initScript = tx.Data
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
return contract
}
return nil
}
func NewStateObject(addr []byte) *StateObject {
// This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter.
address := ethutil.Address(addr)
object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)}
object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
object.storage = make(Storage)
object.gasPool = new(big.Int)
return object
}
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
contract := NewStateObject(address)
contract.Amount = Amount
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
return contract
}
func NewStateObjectFromBytes(address, data []byte) *StateObject {
object := &StateObject{address: address}
object.RlpDecode(data)
return object
}
func (self *StateObject) MarkForDeletion() {
self.remove = true
statelogger.DebugDetailf("%x: #%d %v (deletion)\n", self.Address(), self.Nonce, self.Amount)
}
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
}
func (c *StateObject) SetAddr(addr []byte, value interface{}) {
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
}
func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value {
return self.getStorage(key.Bytes())
}
func (self *StateObject) SetStorage(key *big.Int, value *ethutil.Value) {
self.setStorage(key.Bytes(), value)
}
func (self *StateObject) getStorage(k []byte) *ethutil.Value {
key := ethutil.LeftPadBytes(k, 32)
value := self.storage[string(key)]
if value == nil {
value = self.GetAddr(key)
if !value.IsNil() {
self.storage[string(key)] = value
}
}
return value
//return self.GetAddr(key)
}
func (self *StateObject) setStorage(k []byte, value *ethutil.Value) {
key := ethutil.LeftPadBytes(k, 32)
self.storage[string(key)] = value.Copy()
/*
if value.BigInt().Cmp(ethutil.Big0) == 0 {
self.state.trie.Delete(string(key))
return
}
self.SetAddr(key, value)
*/
}
// Iterate over each storage address and yield callback
func (self *StateObject) EachStorage(cb ethtrie.EachCallback) {
// First loop over the uncommit/cached values in storage
for key, value := range self.storage {
// XXX Most iterators Fns as it stands require encoded values
encoded := ethutil.NewValue(value.Encode())
cb(key, encoded)
}
it := self.state.trie.NewIterator()
it.Each(func(key string, value *ethutil.Value) {
// If it's cached don't call the callback.
if self.storage[key] == nil {
cb(key, value)
}
})
}
func (self *StateObject) Sync() {
/*
fmt.Println("############# BEFORE ################")
self.state.EachStorage(func(key string, value *ethutil.Value) {
fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes())
})
fmt.Printf("%x @:%x\n", self.Address(), self.state.Root())
fmt.Println("#####################################")
*/
for key, value := range self.storage {
if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 {
//data := self.getStorage([]byte(key))
//fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data)
self.state.trie.Delete(string(key))
continue
}
self.SetAddr([]byte(key), value)
}
valid, t2 := ethtrie.ParanoiaCheck(self.state.trie)
if !valid {
statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root)
self.state.trie = t2
}
/*
fmt.Println("############# AFTER ################")
self.state.EachStorage(func(key string, value *ethutil.Value) {
fmt.Printf("%x %x %x\n", self.Address(), []byte(key), value.Bytes())
})
*/
//fmt.Printf("%x @:%x\n", self.Address(), self.state.Root())
}
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
if int64(len(c.script)-1) < pc.Int64() {
return ethutil.NewValue(0)
}
return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]})
}
func (c *StateObject) AddAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Add(c.Amount, amount))
statelogger.Debugf("%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount)
}
func (c *StateObject) SubAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Sub(c.Amount, amount))
statelogger.Debugf("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount)
}
func (c *StateObject) SetAmount(amount *big.Int) {
c.Amount = amount
}
//
// Gas setters and getters
//
// Return the gas back to the origin. Used by the Virtual machine or Closures
func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {}
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
total := new(big.Int).Mul(gas, price)
if total.Cmp(c.Amount) > 0 {
return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total)
}
c.SubAmount(total)
return nil
}
func (self *StateObject) SetGasPool(gasLimit *big.Int) {
self.gasPool = new(big.Int).Set(gasLimit)
statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool)
}
func (self *StateObject) BuyGas(gas, price *big.Int) error {
if self.gasPool.Cmp(gas) < 0 {
return GasLimitError(self.gasPool, gas)
}
rGas := new(big.Int).Set(gas)
rGas.Mul(rGas, price)
self.AddAmount(rGas)
return nil
}
func (self *StateObject) RefundGas(gas, price *big.Int) {
self.gasPool.Add(self.gasPool, gas)
rGas := new(big.Int).Set(gas)
rGas.Mul(rGas, price)
self.Amount.Sub(self.Amount, rGas)
}
func (self *StateObject) Copy() *StateObject {
stateObject := NewStateObject(self.Address())
stateObject.Amount.Set(self.Amount)
stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash)
stateObject.Nonce = self.Nonce
if self.state != nil {
stateObject.state = self.state.Copy()
}
stateObject.script = ethutil.CopyBytes(self.script)
stateObject.initScript = ethutil.CopyBytes(self.initScript)
stateObject.storage = self.storage.Copy()
stateObject.gasPool.Set(self.gasPool)
return stateObject
}
func (self *StateObject) Set(stateObject *StateObject) {
*self = *stateObject
}
//
// Attribute accessors
//
func (c *StateObject) State() *State {
return c.state
}
func (c *StateObject) N() *big.Int {
return big.NewInt(int64(c.Nonce))
}
// Returns the address of the contract/account
func (c *StateObject) Address() []byte {
return c.address
}
// Returns the main script body
func (c *StateObject) Script() Code {
return c.script
}
// Returns the initialization script
func (c *StateObject) Init() Code {
return c.initScript
}
// Debug stuff
func (self *StateObject) CreateOutputForDiff() {
fmt.Printf("%x %x %x %x\n", self.Address(), self.state.Root(), self.Amount.Bytes(), self.Nonce)
self.EachStorage(func(addr string, value *ethutil.Value) {
fmt.Printf("%x %x\n", addr, value.Bytes())
})
}
//
// Encoding
//
// State object encoding methods
func (c *StateObject) RlpEncode() []byte {
var root interface{}
if c.state != nil {
root = c.state.trie.Root
} else {
root = ""
}
return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.script)})
}
func (c *StateObject) RlpDecode(data []byte) {
decoder := ethutil.NewValueFromBytes(data)
c.Nonce = decoder.Get(0).Uint()
c.Amount = decoder.Get(1).BigInt()
c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
c.storage = make(map[string]*ethutil.Value)
c.gasPool = new(big.Int)
c.ScriptHash = decoder.Get(3).Bytes()
c.script, _ = ethutil.Config.Db.Get(c.ScriptHash)
}
// Storage change object. Used by the manifest for notifying changes to
// the sub channels.
type StorageState struct {
StateAddress []byte
Address []byte
Value *big.Int
}

View File

@ -1,52 +0,0 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func TestSync(t *testing.T) {
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
contract.script = []byte{42}
state.UpdateStateObject(contract)
state.Sync()
object := state.GetStateObject([]byte("aa"))
if len(object.Script()) == 0 {
t.Fail()
}
}
func TestObjectGet(t *testing.T) {
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
db, _ := ethdb.NewMemDatabase()
ethutil.Config.Db = db
state := NewState(ethutil.NewTrie(db, ""))
contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
state.UpdateStateObject(contract)
contract = state.GetStateObject([]byte("aa"))
contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello"))
o := contract.GetMem(big.NewInt(0))
fmt.Println(o)
state.UpdateStateObject(contract)
contract.SetStorage(big.NewInt(0), ethutil.NewValue("hello00"))
contract = state.GetStateObject([]byte("aa"))
o = contract.GetMem(big.NewInt(0))
fmt.Println("after", o)
}

View File

@ -1,30 +0,0 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"testing"
)
func TestSnapshot(t *testing.T) {
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
state.UpdateStateObject(stateObject)
stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42))
snapshot := state.Copy()
stateObject = state.GetStateObject([]byte("aa"))
stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43))
state.Set(snapshot)
stateObject = state.GetStateObject([]byte("aa"))
if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) {
t.Error("Expected storage 0 to be 42")
}
}

View File

@ -2,6 +2,10 @@ package ethchain
import ( import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethvm"
"math/big" "math/big"
) )
@ -27,17 +31,17 @@ type StateTransition struct {
gas, gasPrice *big.Int gas, gasPrice *big.Int
value *big.Int value *big.Int
data []byte data []byte
state *State state *ethstate.State
block *Block block *Block
cb, rec, sen *StateObject cb, rec, sen *ethstate.StateObject
} }
func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { func NewStateTransition(coinbase *ethstate.StateObject, tx *Transaction, state *ethstate.State, block *Block) *StateTransition {
return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil}
} }
func (self *StateTransition) Coinbase() *StateObject { func (self *StateTransition) Coinbase() *ethstate.StateObject {
if self.cb != nil { if self.cb != nil {
return self.cb return self.cb
} }
@ -45,7 +49,7 @@ func (self *StateTransition) Coinbase() *StateObject {
self.cb = self.state.GetOrNewStateObject(self.coinbase) self.cb = self.state.GetOrNewStateObject(self.coinbase)
return self.cb return self.cb
} }
func (self *StateTransition) Sender() *StateObject { func (self *StateTransition) Sender() *ethstate.StateObject {
if self.sen != nil { if self.sen != nil {
return self.sen return self.sen
} }
@ -54,7 +58,7 @@ func (self *StateTransition) Sender() *StateObject {
return self.sen return self.sen
} }
func (self *StateTransition) Receiver() *StateObject { func (self *StateTransition) Receiver() *ethstate.StateObject {
if self.tx != nil && self.tx.CreatesContract() { if self.tx != nil && self.tx.CreatesContract() {
return nil return nil
} }
@ -67,7 +71,7 @@ func (self *StateTransition) Receiver() *StateObject {
return self.rec return self.rec
} }
func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { func (self *StateTransition) MakeStateObject(state *ethstate.State, tx *Transaction) *ethstate.StateObject {
contract := MakeContract(tx, state) contract := MakeContract(tx, state)
return contract return contract
@ -154,7 +158,7 @@ func (self *StateTransition) TransitionState() (err error) {
var ( var (
tx = self.tx tx = self.tx
sender = self.Sender() sender = self.Sender()
receiver *StateObject receiver *ethstate.StateObject
) )
defer self.RefundGas() defer self.RefundGas()
@ -163,13 +167,13 @@ func (self *StateTransition) TransitionState() (err error) {
sender.Nonce += 1 sender.Nonce += 1
// Transaction gas // Transaction gas
if err = self.UseGas(GasTx); err != nil { if err = self.UseGas(ethvm.GasTx); err != nil {
return return
} }
// Pay data gas // Pay data gas
dataPrice := big.NewInt(int64(len(self.data))) dataPrice := big.NewInt(int64(len(self.data)))
dataPrice.Mul(dataPrice, GasData) dataPrice.Mul(dataPrice, ethvm.GasData)
if err = self.UseGas(dataPrice); err != nil { if err = self.UseGas(dataPrice); err != nil {
return return
} }
@ -178,7 +182,7 @@ func (self *StateTransition) TransitionState() (err error) {
return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount)
} }
var snapshot *State var snapshot *ethstate.State
// If the receiver is nil it's a contract (\0*32). // If the receiver is nil it's a contract (\0*32).
if tx.CreatesContract() { if tx.CreatesContract() {
// Subtract the (irreversible) amount from the senders account // Subtract the (irreversible) amount from the senders account
@ -220,10 +224,10 @@ func (self *StateTransition) TransitionState() (err error) {
return fmt.Errorf("Error during init execution %v", err) return fmt.Errorf("Error during init execution %v", err)
} }
receiver.script = code receiver.Code = code
} else { } else {
if len(receiver.Script()) > 0 { if len(receiver.Code) > 0 {
_, err = self.Eval(receiver.Script(), receiver, "code") _, err = self.Eval(receiver.Code, receiver, "code")
if err != nil { if err != nil {
self.state.Set(snapshot) self.state.Set(snapshot)
@ -235,7 +239,7 @@ func (self *StateTransition) TransitionState() (err error) {
return return
} }
func (self *StateTransition) transferValue(sender, receiver *StateObject) error { func (self *StateTransition) transferValue(sender, receiver *ethstate.StateObject) error {
if sender.Amount.Cmp(self.value) < 0 { if sender.Amount.Cmp(self.value) < 0 {
return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount) return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount)
} }
@ -248,34 +252,61 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error
return nil return nil
} }
func (self *StateTransition) Eval(script []byte, context *StateObject, typ string) (ret []byte, err error) { func (self *StateTransition) Eval(script []byte, context *ethstate.StateObject, typ string) (ret []byte, err error) {
var ( var (
block = self.block transactor = self.Sender()
initiator = self.Sender() state = self.state
state = self.state env = NewEnv(state, self.tx, self.block)
callerClosure = ethvm.NewClosure(transactor, context, script, self.gas, self.gasPrice)
) )
closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice) vm := ethvm.New(env)
vm := NewVm(state, nil, RuntimeVars{
Origin: initiator.Address(),
Block: block,
BlockNumber: block.Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: self.value,
})
vm.Verbose = true vm.Verbose = true
vm.Fn = typ vm.Fn = typ
ret, err = Call(vm, closure, self.data) ret, _, err = callerClosure.Call(vm, self.tx.Data)
/*
closure := NewClosure(initiator, context, script, state, self.gas, self.gasPrice)
vm := NewVm(state, nil, RuntimeVars{
Origin: initiator.Address(),
Block: block,
BlockNumber: block.Number,
PrevHash: block.PrevHash,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: self.value,
})
vm.Verbose = true
vm.Fn = typ
ret, err = Call(vm, closure, self.data)
*/
return return
} }
func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { /*
func Call(vm *eth.Vm, closure *Closure, data []byte) (ret []byte, err error) {
ret, _, err = closure.Call(vm, data) ret, _, err = closure.Call(vm, data)
return return
} }
*/
// Converts an transaction in to a state object
func MakeContract(tx *Transaction, state *ethstate.State) *ethstate.StateObject {
// Create contract if there's no recipient
if tx.IsContract() {
addr := tx.CreationAddress()
contract := state.NewStateObject(addr)
contract.InitCode = tx.Data
contract.State = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
return contract
}
return nil
}

View File

@ -5,6 +5,7 @@ import (
"container/list" "container/list"
"fmt" "fmt"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethwire"
"math/big" "math/big"
"sync" "sync"
@ -252,7 +253,7 @@ func (pool *TxPool) CurrentTransactions() []*Transaction {
return txList return txList
} }
func (pool *TxPool) RemoveInvalid(state *State) { func (pool *TxPool) RemoveInvalid(state *ethstate.State) {
for e := pool.pool.Front(); e != nil; e = e.Next() { for e := pool.pool.Front(); e != nil; e = e.Next() {
tx := e.Value.(*Transaction) tx := e.Value.(*Transaction)
sender := state.GetAccount(tx.Sender()) sender := state.GetAccount(tx.Sender())

View File

@ -1,843 +0,0 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethutil"
"math"
"math/big"
)
var vmlogger = ethlog.NewLogger("VM")
var (
GasStep = big.NewInt(1)
GasSha = big.NewInt(20)
GasSLoad = big.NewInt(20)
GasSStore = big.NewInt(100)
GasBalance = big.NewInt(20)
GasCreate = big.NewInt(100)
GasCall = big.NewInt(20)
GasMemory = big.NewInt(1)
GasData = big.NewInt(5)
GasTx = big.NewInt(500)
LogTyPretty byte = 0x1
LogTyDiff byte = 0x2
)
type Debugger interface {
BreakHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
StepHook(step int, op OpCode, mem *Memory, stack *Stack, stateObject *StateObject) bool
BreakPoints() []int64
SetCode(byteCode []byte)
}
type Vm struct {
// Stack for processing contracts
stack *Stack
// non-persistent key/value memory storage
mem map[string]*big.Int
vars RuntimeVars
state *State
stateManager *StateManager
Verbose bool
logTy byte
logStr string
err error
// Debugging
Dbg Debugger
BreakPoints []int64
Stepping bool
Fn string
}
type RuntimeVars struct {
Origin []byte
Block *Block
BlockNumber *big.Int
PrevHash []byte
Coinbase []byte
Time int64
Diff *big.Int
TxData []string
Value *big.Int
}
func (self *Vm) Printf(format string, v ...interface{}) *Vm {
if self.Verbose && self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
return self
}
func (self *Vm) Endl() *Vm {
if self.Verbose && self.logTy == LogTyPretty {
vmlogger.Debugln(self.logStr)
self.logStr = ""
}
return self
}
func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
lt := LogTyPretty
if ethutil.Config.Diff {
lt = LogTyDiff
}
return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt}
}
var Pow256 = ethutil.BigPow(2, 256)
var isRequireError = false
func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// Recover from any require exception
defer func() {
if r := recover(); r != nil {
ret = closure.Return(nil)
err = fmt.Errorf("%v", r)
vmlogger.Errorln("vm err", err)
}
}()
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
// Don't bother with the execution if there's no code.
if len(closure.Script) == 0 {
return closure.Return(nil), nil
}
vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args)
var (
op OpCode
mem = &Memory{}
stack = NewStack()
pc = big.NewInt(0)
step = 0
prevStep = 0
require = func(m int) {
if stack.Len() < m {
isRequireError = true
panic(fmt.Sprintf("%04v (%v) stack err size = %d, required = %d", pc, op, stack.Len(), m))
}
}
)
for {
prevStep = step
// The base for all big integer arithmetic
base := new(big.Int)
step++
// Get the memory location of pc
val := closure.Get(pc)
// Get the opcode (it must be an opcode!)
op = OpCode(val.Uint())
// XXX Leave this Println intact. Don't change this to the log system.
// Used for creating diffs between implementations
if vm.logTy == LogTyDiff {
switch op {
case STOP, RETURN, SUICIDE:
closure.object.Sync()
closure.object.EachStorage(func(key string, value *ethutil.Value) {
value.Decode()
fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes())
})
}
b := pc.Bytes()
if len(b) == 0 {
b = []byte{0}
}
fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
}
gas := new(big.Int)
addStepGasUsage := func(amount *big.Int) {
if amount.Cmp(ethutil.Big0) >= 0 {
gas.Add(gas, amount)
}
}
addStepGasUsage(GasStep)
var newMemSize uint64 = 0
switch op {
case STOP:
gas.Set(ethutil.Big0)
case SUICIDE:
gas.Set(ethutil.Big0)
case SLOAD:
gas.Set(GasSLoad)
case SSTORE:
var mult *big.Int
y, x := stack.Peekn()
val := closure.GetStorage(x)
if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 {
mult = ethutil.Big2
} else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 {
mult = ethutil.Big0
} else {
mult = ethutil.Big1
}
gas = new(big.Int).Mul(mult, GasSStore)
case BALANCE:
gas.Set(GasBalance)
case MSTORE:
require(2)
newMemSize = stack.Peek().Uint64() + 32
case MLOAD:
require(1)
newMemSize = stack.Peek().Uint64() + 32
case MSTORE8:
require(2)
newMemSize = stack.Peek().Uint64() + 1
case RETURN:
require(2)
newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
case SHA3:
require(2)
gas.Set(GasSha)
newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64()
case CALLDATACOPY:
require(3)
newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
case CODECOPY:
require(3)
newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64()
case CALL:
require(7)
gas.Set(GasCall)
addStepGasUsage(stack.data[stack.Len()-1])
x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64()
y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64()
newMemSize = uint64(math.Max(float64(x), float64(y)))
case CREATE:
require(3)
gas.Set(GasCreate)
newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64()
}
newMemSize = (newMemSize + 31) / 32 * 32
if newMemSize > uint64(mem.Len()) {
m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32
addStepGasUsage(big.NewInt(int64(m)))
}
if !closure.UseGas(gas) {
err := fmt.Errorf("Insufficient gas for %v. req %v has %v", op, gas, closure.Gas)
closure.UseGas(closure.Gas)
return closure.Return(nil), err
}
vm.Printf("(pc) %-3d -o- %-14s", pc, op.String())
vm.Printf(" (g) %-3v (%v)", gas, closure.Gas)
mem.Resize(newMemSize)
switch op {
case LOG:
stack.Print()
mem.Print()
// 0x20 range
case ADD:
require(2)
x, y := stack.Popn()
vm.Printf(" %v + %v", y, x)
base.Add(y, x)
vm.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
case SUB:
require(2)
x, y := stack.Popn()
vm.Printf(" %v - %v", y, x)
base.Sub(y, x)
vm.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
case MUL:
require(2)
x, y := stack.Popn()
vm.Printf(" %v * %v", y, x)
base.Mul(y, x)
vm.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
case DIV:
require(2)
x, y := stack.Popn()
vm.Printf(" %v / %v", y, x)
base.Div(y, x)
vm.Printf(" = %v", base)
// Pop result back on the stack
stack.Push(base)
case SDIV:
require(2)
x, y := stack.Popn()
// n > 2**255
if x.Cmp(Pow256) > 0 {
x.Sub(Pow256, x)
}
if y.Cmp(Pow256) > 0 {
y.Sub(Pow256, y)
}
z := new(big.Int)
z.Div(x, y)
if z.Cmp(Pow256) > 0 {
z.Sub(Pow256, z)
}
// Push result on to the stack
stack.Push(z)
case MOD:
require(2)
x, y := stack.Popn()
vm.Printf(" %v %% %v", y, x)
base.Mod(y, x)
vm.Printf(" = %v", base)
stack.Push(base)
case SMOD:
require(2)
x, y := stack.Popn()
// n > 2**255
if x.Cmp(Pow256) > 0 {
x.Sub(Pow256, x)
}
if y.Cmp(Pow256) > 0 {
y.Sub(Pow256, y)
}
z := new(big.Int)
z.Mod(x, y)
if z.Cmp(Pow256) > 0 {
z.Sub(Pow256, z)
}
// Push result on to the stack
stack.Push(z)
case EXP:
require(2)
x, y := stack.Popn()
vm.Printf(" %v ** %v", y, x)
base.Exp(y, x, Pow256)
vm.Printf(" = %v", base)
stack.Push(base)
case NEG:
require(1)
base.Sub(Pow256, stack.Pop())
stack.Push(base)
case LT:
require(2)
x, y := stack.Popn()
vm.Printf(" %v < %v", y, x)
// x < y
if y.Cmp(x) < 0 {
stack.Push(ethutil.BigTrue)
} else {
stack.Push(ethutil.BigFalse)
}
case GT:
require(2)
x, y := stack.Popn()
vm.Printf(" %v > %v", y, x)
// x > y
if y.Cmp(x) > 0 {
stack.Push(ethutil.BigTrue)
} else {
stack.Push(ethutil.BigFalse)
}
case SLT:
require(2)
x, y := stack.Popn()
vm.Printf(" %v < %v", y, x)
// x < y
if y.Cmp(x) < 0 {
stack.Push(ethutil.BigTrue)
} else {
stack.Push(ethutil.BigFalse)
}
case SGT:
require(2)
x, y := stack.Popn()
vm.Printf(" %v > %v", y, x)
// x > y
if y.Cmp(x) > 0 {
stack.Push(ethutil.BigTrue)
} else {
stack.Push(ethutil.BigFalse)
}
case EQ:
require(2)
x, y := stack.Popn()
vm.Printf(" %v == %v", y, x)
// x == y
if x.Cmp(y) == 0 {
stack.Push(ethutil.BigTrue)
} else {
stack.Push(ethutil.BigFalse)
}
case NOT:
require(1)
x := stack.Pop()
if x.Cmp(ethutil.BigFalse) > 0 {
stack.Push(ethutil.BigFalse)
} else {
stack.Push(ethutil.BigTrue)
}
// 0x10 range
case AND:
require(2)
x, y := stack.Popn()
vm.Printf(" %v & %v", y, x)
stack.Push(base.And(y, x))
case OR:
require(2)
x, y := stack.Popn()
vm.Printf(" %v | %v", y, x)
stack.Push(base.Or(y, x))
case XOR:
require(2)
x, y := stack.Popn()
vm.Printf(" %v ^ %v", y, x)
stack.Push(base.Xor(y, x))
case BYTE:
require(2)
val, th := stack.Popn()
if th.Cmp(big.NewInt(32)) < 0 && th.Cmp(big.NewInt(int64(len(val.Bytes())))) < 0 {
byt := big.NewInt(int64(val.Bytes()[th.Int64()]))
stack.Push(byt)
vm.Printf(" => 0x%x", byt.Bytes())
} else {
stack.Push(ethutil.BigFalse)
}
// 0x20 range
case SHA3:
require(2)
size, offset := stack.Popn()
data := ethcrypto.Sha3Bin(mem.Get(offset.Int64(), size.Int64()))
stack.Push(ethutil.BigD(data))
vm.Printf(" => %x", data)
// 0x30 range
case ADDRESS:
stack.Push(ethutil.BigD(closure.Address()))
vm.Printf(" => %x", closure.Address())
case BALANCE:
require(1)
addr := stack.Pop().Bytes()
balance := vm.state.GetBalance(addr)
stack.Push(balance)
vm.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
stack.Push(ethutil.BigD(vm.vars.Origin))
vm.Printf(" => %x", vm.vars.Origin)
case CALLER:
caller := closure.caller.Address()
stack.Push(ethutil.BigD(caller))
vm.Printf(" => %x", caller)
case CALLVALUE:
stack.Push(vm.vars.Value)
vm.Printf(" => %v", vm.vars.Value)
case CALLDATALOAD:
require(1)
var (
offset = stack.Pop()
data = make([]byte, 32)
lenData = big.NewInt(int64(len(closure.Args)))
)
if lenData.Cmp(offset) >= 0 {
length := new(big.Int).Add(offset, ethutil.Big32)
length = ethutil.BigMin(length, lenData)
copy(data, closure.Args[offset.Int64():length.Int64()])
}
vm.Printf(" => 0x%x", data)
stack.Push(ethutil.BigD(data))
case CALLDATASIZE:
l := int64(len(closure.Args))
stack.Push(big.NewInt(l))
vm.Printf(" => %d", l)
case CALLDATACOPY:
var (
size = int64(len(closure.Args))
mOff = stack.Pop().Int64()
cOff = stack.Pop().Int64()
l = stack.Pop().Int64()
)
if cOff > size {
cOff = 0
l = 0
} else if cOff+l > size {
l = 0
}
code := closure.Args[cOff : cOff+l]
mem.Set(mOff, l, code)
case CODESIZE:
l := big.NewInt(int64(len(closure.Script)))
stack.Push(l)
vm.Printf(" => %d", l)
case CODECOPY:
var (
size = int64(len(closure.Script))
mOff = stack.Pop().Int64()
cOff = stack.Pop().Int64()
l = stack.Pop().Int64()
)
if cOff > size {
cOff = 0
l = 0
} else if cOff+l > size {
l = 0
}
code := closure.Script[cOff : cOff+l]
fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff)
mem.Set(mOff, l, code)
case GASPRICE:
stack.Push(closure.Price)
// 0x40 range
case PREVHASH:
stack.Push(ethutil.BigD(vm.vars.PrevHash))
case COINBASE:
stack.Push(ethutil.BigD(vm.vars.Coinbase))
case TIMESTAMP:
stack.Push(big.NewInt(vm.vars.Time))
case NUMBER:
stack.Push(vm.vars.BlockNumber)
case DIFFICULTY:
stack.Push(vm.vars.Diff)
case GASLIMIT:
// TODO
stack.Push(big.NewInt(0))
// 0x50 range
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
a := big.NewInt(int64(op) - int64(PUSH1) + 1)
pc.Add(pc, ethutil.Big1)
data := closure.Gets(pc, a)
val := ethutil.BigD(data.Bytes())
// Push value to stack
stack.Push(val)
pc.Add(pc, a.Sub(a, big.NewInt(1)))
step += int(op) - int(PUSH1) + 1
vm.Printf(" => 0x%x", data.Bytes())
case POP:
require(1)
stack.Pop()
case DUP:
require(1)
stack.Push(stack.Peek())
vm.Printf(" => 0x%x", stack.Peek().Bytes())
case SWAP:
require(2)
x, y := stack.Popn()
stack.Push(y)
stack.Push(x)
case MLOAD:
require(1)
offset := stack.Pop()
val := ethutil.BigD(mem.Get(offset.Int64(), 32))
stack.Push(val)
vm.Printf(" => 0x%x", val.Bytes())
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
require(2)
// Pop value of the stack
val, mStart := stack.Popn()
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
vm.Printf(" => 0x%x", val)
case MSTORE8:
require(2)
val, mStart := stack.Popn()
//base.And(val, new(big.Int).SetInt64(0xff))
//mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
mem.store[mStart.Int64()] = byte(val.Int64() & 0xff)
vm.Printf(" => 0x%x", val)
case SLOAD:
require(1)
loc := stack.Pop()
val := closure.GetStorage(loc)
stack.Push(val.BigInt())
vm.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
case SSTORE:
require(2)
val, loc := stack.Popn()
closure.SetStorage(loc, ethutil.NewValue(val))
// Add the change to manifest
vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val)
vm.Printf(" {0x%x : 0x%x}", loc, val)
case JUMP:
require(1)
pc = stack.Pop()
// Reduce pc by one because of the increment that's at the end of this for loop
vm.Printf(" ~> %v", pc).Endl()
continue
case JUMPI:
require(2)
cond, pos := stack.Popn()
if cond.Cmp(ethutil.BigTrue) >= 0 {
pc = pos
vm.Printf(" ~> %v (t)", pc).Endl()
continue
} else {
vm.Printf(" (f)")
}
case PC:
stack.Push(pc)
case MSIZE:
stack.Push(big.NewInt(int64(mem.Len())))
vm.Printf(" => %v", mem.Len()).Endl()
case GAS:
stack.Push(closure.Gas)
// 0x60 range
case CREATE:
require(3)
var (
err error
value = stack.Pop()
size, offset = stack.Popn()
// Snapshot the current stack so we are able to
// revert back to it later.
snapshot = vm.state.Copy()
)
// Generate a new address
addr := ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64())
for i := uint64(0); vm.state.GetStateObject(addr) != nil; i++ {
ethcrypto.CreateAddress(closure.Address(), closure.N().Uint64()+i)
}
closure.object.Nonce++
vm.Printf(" (*) %x", addr).Endl()
// Create a new contract
contract := vm.state.NewStateObject(addr)
if contract.Amount.Cmp(value) >= 0 {
closure.object.SubAmount(value)
contract.AddAmount(value)
// Set the init script
initCode := mem.Get(offset.Int64(), size.Int64())
//fmt.Printf("%x\n", initCode)
// Transfer all remaining gas to the new
// contract so it may run the init script
gas := new(big.Int).Set(closure.Gas)
closure.UseGas(closure.Gas)
// Create the closure
c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price)
// Call the closure and set the return value as
// main script.
contract.script, err = Call(vm, c, nil)
} else {
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
}
if err != nil {
stack.Push(ethutil.BigFalse)
// Revert the state as it was before.
vm.state.Set(snapshot)
vm.Printf("CREATE err %v", err)
} else {
stack.Push(ethutil.BigD(addr))
vm.Printf("CREATE success")
}
vm.Endl()
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
case CALL:
require(7)
vm.Endl()
gas := stack.Pop()
// Pop gas and value of the stack.
value, addr := stack.Popn()
// Pop input size and offset
inSize, inOffset := stack.Popn()
// Pop return size and offset
retSize, retOffset := stack.Popn()
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
if closure.object.Amount.Cmp(value) < 0 {
vmlogger.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
closure.ReturnGas(gas, nil, nil)
stack.Push(ethutil.BigFalse)
} else {
snapshot := vm.state.Copy()
stateObject := vm.state.GetOrNewStateObject(addr.Bytes())
closure.object.SubAmount(value)
stateObject.AddAmount(value)
// Create a new callable closure
c := NewClosure(closure, stateObject, stateObject.script, vm.state, gas, closure.Price)
// Executer the closure and get the return value (if any)
ret, err := Call(vm, c, args)
if err != nil {
stack.Push(ethutil.BigFalse)
vmlogger.Debugf("Closure execution failed. %v\n", err)
vm.state.Set(snapshot)
} else {
stack.Push(ethutil.BigTrue)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
}
// Debug hook
if vm.Dbg != nil {
vm.Dbg.SetCode(closure.Script)
}
}
case RETURN:
require(2)
size, offset := stack.Popn()
ret := mem.Get(offset.Int64(), size.Int64())
vm.Printf(" => (%d) 0x%x", len(ret), ret).Endl()
return closure.Return(ret), nil
case SUICIDE:
require(1)
receiver := vm.state.GetOrNewStateObject(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount)
closure.object.MarkForDeletion()
fallthrough
case STOP: // Stop the closure
vm.Endl()
return closure.Return(nil), nil
default:
vmlogger.Debugf("(pc) %-3v Invalid opcode %x\n", pc, op)
fmt.Println(Code(closure.Script))
return closure.Return(nil), fmt.Errorf("Invalid opcode %x", op)
}
pc.Add(pc, ethutil.Big1)
vm.Endl()
if vm.Dbg != nil {
for _, instrNo := range vm.Dbg.BreakPoints() {
if pc.Cmp(big.NewInt(instrNo)) == 0 {
vm.Stepping = true
if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) {
return nil, nil
}
} else if vm.Stepping {
if !vm.Dbg.StepHook(prevStep, op, mem, stack, closure.Object()) {
return nil, nil
}
}
}
}
}
}

28
ethchain/vm_env.go Normal file
View File

@ -0,0 +1,28 @@
package ethchain
import (
"github.com/ethereum/eth-go/ethstate"
"math/big"
)
type VMEnv struct {
state *ethstate.State
block *Block
tx *Transaction
}
func NewEnv(state *ethstate.State, tx *Transaction, block *Block) *VMEnv {
return &VMEnv{
state: state,
block: block,
}
}
func (self *VMEnv) Origin() []byte { return self.tx.Sender() }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) Value() *big.Int { return self.tx.Value }
func (self *VMEnv) State() *ethstate.State { return self.state }

View File

@ -1,68 +0,0 @@
package ethchain
import (
_ "bytes"
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
func TestRun4(t *testing.T) {
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
callerScript, err := ethutil.Compile(`
this.store[this.origin()] = 10**20
hello := "world"
return lambda {
big to = this.data[0]
big from = this.origin()
big value = this.data[1]
if this.store[from] >= value {
this.store[from] = this.store[from] - value
this.store[to] = this.store[to] + value
}
}
`)
if err != nil {
fmt.Println(err)
}
fmt.Println(Disassemble(callerScript))
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript)
callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
// Contract addr as test address
gas := big.NewInt(1000)
gasPrice := big.NewInt(10)
account := NewAccount(ContractAddr, big.NewInt(10000000))
fmt.Println("account.Amount =", account.Amount)
c := MakeContract(callerTx, state)
e := account.ConvertGas(gas, gasPrice)
if e != nil {
fmt.Println(err)
}
fmt.Println("account.Amount =", account.Amount)
callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice)
vm := NewVm(state, nil, RuntimeVars{
Origin: account.Address(),
BlockNumber: big.NewInt(1),
PrevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
Coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
Time: 1,
Diff: big.NewInt(256),
})
var ret []byte
ret, _, e = callerClosure.Call(vm, nil, nil)
if e != nil {
fmt.Println("error", e)
}
fmt.Println(ret)
}

View File

@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog" "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
"strings" "strings"
@ -24,11 +25,11 @@ type helper struct {
func EthereumConfig(stateManager *ethchain.StateManager) helper { func EthereumConfig(stateManager *ethchain.StateManager) helper {
return helper{stateManager} return helper{stateManager}
} }
func (self helper) obj() *ethchain.StateObject { func (self helper) obj() *ethstate.StateObject {
return self.sm.CurrentState().GetStateObject(cnfCtr) return self.sm.CurrentState().GetStateObject(cnfCtr)
} }
func (self helper) NameReg() *ethchain.StateObject { func (self helper) NameReg() *ethstate.StateObject {
if self.obj() != nil { if self.obj() != nil {
addr := self.obj().GetStorage(big.NewInt(0)) addr := self.obj().GetStorage(big.NewInt(0))
if len(addr.Bytes()) > 0 { if len(addr.Bytes()) > 0 {

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethtrie" "github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"strings" "strings"
@ -154,10 +155,10 @@ func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *
} }
type PStateObject struct { type PStateObject struct {
object *ethchain.StateObject object *ethstate.StateObject
} }
func NewPStateObject(object *ethchain.StateObject) *PStateObject { func NewPStateObject(object *ethstate.StateObject) *PStateObject {
return &PStateObject{object: object} return &PStateObject{object: object}
} }
@ -200,7 +201,7 @@ func (c *PStateObject) Nonce() int {
func (c *PStateObject) Root() string { func (c *PStateObject) Root() string {
if c.object != nil { if c.object != nil {
return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State().Root()).Bytes()) return ethutil.Bytes2Hex(ethutil.NewValue(c.object.State.Root()).Bytes())
} }
return "<err>" return "<err>"
@ -208,7 +209,7 @@ func (c *PStateObject) Root() string {
func (c *PStateObject) IsContract() bool { func (c *PStateObject) IsContract() bool {
if c.object != nil { if c.object != nil {
return len(c.object.Script()) > 0 return len(c.object.Code) > 0
} }
return false return false
@ -245,7 +246,7 @@ func (c *PStateObject) StateKeyVal(asJson bool) interface{} {
func (c *PStateObject) Script() string { func (c *PStateObject) Script() string {
if c.object != nil { if c.object != nil {
return strings.Join(ethchain.Disassemble(c.object.Script()), " ") return strings.Join(ethchain.Disassemble(c.object.Code), " ")
} }
return "" return ""
@ -253,7 +254,7 @@ func (c *PStateObject) Script() string {
func (c *PStateObject) HexScript() string { func (c *PStateObject) HexScript() string {
if c.object != nil { if c.object != nil {
return ethutil.Bytes2Hex(c.object.Script()) return ethutil.Bytes2Hex(c.object.Code)
} }
return "" return ""
@ -265,6 +266,6 @@ type PStorageState struct {
Value string Value string
} }
func NewPStorageState(storageObject *ethchain.StorageState) *PStorageState { func NewPStorageState(storageObject *ethstate.StorageState) *PStorageState {
return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()} return &PStorageState{ethutil.Bytes2Hex(storageObject.StateAddress), ethutil.Bytes2Hex(storageObject.Address), storageObject.Value.String()}
} }

View File

@ -17,7 +17,7 @@ var statelogger = ethlog.NewLogger("STATE")
// * Accounts // * Accounts
type State struct { type State struct {
// The trie for this structure // The trie for this structure
trie *ethtrie.Trie Trie *ethtrie.Trie
stateObjects map[string]*StateObject stateObjects map[string]*StateObject
@ -26,7 +26,7 @@ type State struct {
// Create a new state from a given trie // Create a new state from a given trie
func NewState(trie *ethtrie.Trie) *State { func NewState(trie *ethtrie.Trie) *State {
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()} return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
} }
// Retrieve the balance from the given address or 0 if object not found // Retrieve the balance from the given address or 0 if object not found
@ -58,14 +58,14 @@ func (self *State) UpdateStateObject(stateObject *StateObject) {
ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code) ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Code), stateObject.Code)
self.trie.Update(string(addr), string(stateObject.RlpEncode())) self.Trie.Update(string(addr), string(stateObject.RlpEncode()))
self.manifest.AddObjectChange(stateObject) self.manifest.AddObjectChange(stateObject)
} }
// Delete the given state object and delete it from the state trie // Delete the given state object and delete it from the state trie
func (self *State) DeleteStateObject(stateObject *StateObject) { func (self *State) DeleteStateObject(stateObject *StateObject) {
self.trie.Delete(string(stateObject.Address())) self.Trie.Delete(string(stateObject.Address()))
delete(self.stateObjects, string(stateObject.Address())) delete(self.stateObjects, string(stateObject.Address()))
} }
@ -79,7 +79,7 @@ func (self *State) GetStateObject(addr []byte) *StateObject {
return stateObject return stateObject
} }
data := self.trie.Get(string(addr)) data := self.Trie.Get(string(addr))
if len(data) == 0 { if len(data) == 0 {
return nil return nil
} }
@ -122,12 +122,12 @@ func (self *State) GetAccount(addr []byte) *StateObject {
// //
func (s *State) Cmp(other *State) bool { func (s *State) Cmp(other *State) bool {
return s.trie.Cmp(other.trie) return s.Trie.Cmp(other.Trie)
} }
func (self *State) Copy() *State { func (self *State) Copy() *State {
if self.trie != nil { if self.Trie != nil {
state := NewState(self.trie.Copy()) state := NewState(self.Trie.Copy())
for k, stateObject := range self.stateObjects { for k, stateObject := range self.stateObjects {
state.stateObjects[k] = stateObject.Copy() state.stateObjects[k] = stateObject.Copy()
} }
@ -143,21 +143,21 @@ func (self *State) Set(state *State) {
panic("Tried setting 'state' to nil through 'Set'") panic("Tried setting 'state' to nil through 'Set'")
} }
self.trie = state.trie self.Trie = state.Trie
self.stateObjects = state.stateObjects self.stateObjects = state.stateObjects
} }
func (s *State) Root() interface{} { func (s *State) Root() interface{} {
return s.trie.Root return s.Trie.Root
} }
// Resets the trie and all siblings // Resets the trie and all siblings
func (s *State) Reset() { func (s *State) Reset() {
s.trie.Undo() s.Trie.Undo()
// Reset all nested states // Reset all nested states
for _, stateObject := range s.stateObjects { for _, stateObject := range s.stateObjects {
if stateObject.state == nil { if stateObject.State == nil {
continue continue
} }
@ -174,14 +174,14 @@ func (s *State) Sync() {
for _, stateObject := range s.stateObjects { for _, stateObject := range s.stateObjects {
//s.UpdateStateObject(stateObject) //s.UpdateStateObject(stateObject)
if stateObject.state == nil { if stateObject.State == nil {
continue continue
} }
stateObject.state.Sync() stateObject.State.Sync()
} }
s.trie.Sync() s.Trie.Sync()
s.Empty() s.Empty()
} }
@ -202,11 +202,11 @@ func (self *State) Update() {
} }
// FIXME trie delete is broken // FIXME trie delete is broken
valid, t2 := ethtrie.ParanoiaCheck(self.trie) valid, t2 := ethtrie.ParanoiaCheck(self.Trie)
if !valid { if !valid {
statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.trie.Root, t2.Root) statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.Trie.Root, t2.Root)
self.trie = t2 self.Trie = t2
} }
} }
@ -230,8 +230,8 @@ type Manifest struct {
objectAddresses map[string]bool objectAddresses map[string]bool
storageAddresses map[string]map[string]bool storageAddresses map[string]map[string]bool
objectChanges map[string]*StateObject ObjectChanges map[string]*StateObject
storageChanges map[string]map[string]*big.Int StorageChanges map[string]map[string]*big.Int
} }
func NewManifest() *Manifest { func NewManifest() *Manifest {
@ -242,18 +242,18 @@ func NewManifest() *Manifest {
} }
func (m *Manifest) Reset() { func (m *Manifest) Reset() {
m.objectChanges = make(map[string]*StateObject) m.ObjectChanges = make(map[string]*StateObject)
m.storageChanges = make(map[string]map[string]*big.Int) m.StorageChanges = make(map[string]map[string]*big.Int)
} }
func (m *Manifest) AddObjectChange(stateObject *StateObject) { func (m *Manifest) AddObjectChange(stateObject *StateObject) {
m.objectChanges[string(stateObject.Address())] = stateObject m.ObjectChanges[string(stateObject.Address())] = stateObject
} }
func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) { func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) {
if m.storageChanges[string(stateObject.Address())] == nil { if m.StorageChanges[string(stateObject.Address())] == nil {
m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int) m.StorageChanges[string(stateObject.Address())] = make(map[string]*big.Int)
} }
m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage
} }

View File

@ -34,9 +34,9 @@ type StateObject struct {
CodeHash []byte CodeHash []byte
Nonce uint64 Nonce uint64
// Contract related attributes // Contract related attributes
state *State State *State
Code Code Code Code
initCode Code InitCode Code
storage Storage storage Storage
@ -53,7 +53,7 @@ type StateObject struct {
func (self *StateObject) Reset() { func (self *StateObject) Reset() {
self.storage = make(Storage) self.storage = make(Storage)
self.state.Reset() self.State.Reset()
} }
/* /*
@ -79,7 +79,7 @@ func NewStateObject(addr []byte) *StateObject {
address := ethutil.Address(addr) address := ethutil.Address(addr)
object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)} object := &StateObject{address: address, Amount: new(big.Int), gasPool: new(big.Int)}
object.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) object.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
object.storage = make(Storage) object.storage = make(Storage)
object.gasPool = new(big.Int) object.gasPool = new(big.Int)
@ -89,7 +89,7 @@ func NewStateObject(addr []byte) *StateObject {
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
contract := NewStateObject(address) contract := NewStateObject(address)
contract.Amount = Amount contract.Amount = Amount
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root))) contract.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
return contract return contract
} }
@ -107,11 +107,11 @@ func (self *StateObject) MarkForDeletion() {
} }
func (c *StateObject) GetAddr(addr []byte) *ethutil.Value { func (c *StateObject) GetAddr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr)))) return ethutil.NewValueFromBytes([]byte(c.State.Trie.Get(string(addr))))
} }
func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetAddr(addr []byte, value interface{}) {
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode())) c.State.Trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
} }
func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value { func (self *StateObject) GetStorage(key *big.Int) *ethutil.Value {
@ -152,7 +152,7 @@ func (self *StateObject) EachStorage(cb ethtrie.EachCallback) {
cb(key, encoded) cb(key, encoded)
} }
it := self.state.trie.NewIterator() it := self.State.Trie.NewIterator()
it.Each(func(key string, value *ethutil.Value) { it.Each(func(key string, value *ethutil.Value) {
// If it's cached don't call the callback. // If it's cached don't call the callback.
if self.storage[key] == nil { if self.storage[key] == nil {
@ -166,18 +166,18 @@ func (self *StateObject) Sync() {
if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 { if value.Len() == 0 { // value.BigInt().Cmp(ethutil.Big0) == 0 {
//data := self.getStorage([]byte(key)) //data := self.getStorage([]byte(key))
//fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data) //fmt.Printf("deleting %x %x 0x%x\n", self.Address(), []byte(key), data)
self.state.trie.Delete(string(key)) self.State.Trie.Delete(string(key))
continue continue
} }
self.SetAddr([]byte(key), value) self.SetAddr([]byte(key), value)
} }
valid, t2 := ethtrie.ParanoiaCheck(self.state.trie) valid, t2 := ethtrie.ParanoiaCheck(self.State.Trie)
if !valid { if !valid {
statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.state.trie.Root, t2.Root) statelogger.Infof("Warn: PARANOIA: Different state storage root during copy %x vs %x\n", self.State.Trie.Root, t2.Root)
self.state.trie = t2 self.State.Trie = t2
} }
} }
@ -255,11 +255,11 @@ func (self *StateObject) Copy() *StateObject {
stateObject.Amount.Set(self.Amount) stateObject.Amount.Set(self.Amount)
stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash) stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash)
stateObject.Nonce = self.Nonce stateObject.Nonce = self.Nonce
if self.state != nil { if self.State != nil {
stateObject.state = self.state.Copy() stateObject.State = self.State.Copy()
} }
stateObject.Code = ethutil.CopyBytes(self.Code) stateObject.Code = ethutil.CopyBytes(self.Code)
stateObject.initCode = ethutil.CopyBytes(self.initCode) stateObject.InitCode = ethutil.CopyBytes(self.InitCode)
stateObject.storage = self.storage.Copy() stateObject.storage = self.storage.Copy()
stateObject.gasPool.Set(self.gasPool) stateObject.gasPool.Set(self.gasPool)
@ -274,10 +274,6 @@ func (self *StateObject) Set(stateObject *StateObject) {
// Attribute accessors // Attribute accessors
// //
func (c *StateObject) State() *State {
return c.state
}
func (c *StateObject) N() *big.Int { func (c *StateObject) N() *big.Int {
return big.NewInt(int64(c.Nonce)) return big.NewInt(int64(c.Nonce))
} }
@ -289,12 +285,12 @@ func (c *StateObject) Address() []byte {
// Returns the initialization Code // Returns the initialization Code
func (c *StateObject) Init() Code { func (c *StateObject) Init() Code {
return c.initCode return c.InitCode
} }
// Debug stuff // Debug stuff
func (self *StateObject) CreateOutputForDiff() { func (self *StateObject) CreateOutputForDiff() {
fmt.Printf("%x %x %x %x\n", self.Address(), self.state.Root(), self.Amount.Bytes(), self.Nonce) fmt.Printf("%x %x %x %x\n", self.Address(), self.State.Root(), self.Amount.Bytes(), self.Nonce)
self.EachStorage(func(addr string, value *ethutil.Value) { self.EachStorage(func(addr string, value *ethutil.Value) {
fmt.Printf("%x %x\n", addr, value.Bytes()) fmt.Printf("%x %x\n", addr, value.Bytes())
}) })
@ -307,8 +303,8 @@ func (self *StateObject) CreateOutputForDiff() {
// State object encoding methods // State object encoding methods
func (c *StateObject) RlpEncode() []byte { func (c *StateObject) RlpEncode() []byte {
var root interface{} var root interface{}
if c.state != nil { if c.State != nil {
root = c.state.trie.Root root = c.State.Trie.Root
} else { } else {
root = "" root = ""
} }
@ -321,7 +317,7 @@ func (c *StateObject) RlpDecode(data []byte) {
c.Nonce = decoder.Get(0).Uint() c.Nonce = decoder.Get(0).Uint()
c.Amount = decoder.Get(1).BigInt() c.Amount = decoder.Get(1).BigInt()
c.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
c.storage = make(map[string]*ethutil.Value) c.storage = make(map[string]*ethutil.Value)
c.gasPool = new(big.Int) c.gasPool = new(big.Int)

29
peer.go
View File

@ -470,23 +470,20 @@ func (p *Peer) HandleInbound() {
p.pushPeers() p.pushPeers()
case ethwire.MsgPeersTy: case ethwire.MsgPeersTy:
// Received a list of peers (probably because MsgGetPeersTy was send) // Received a list of peers (probably because MsgGetPeersTy was send)
// Only act on message if we actually requested for a peers list data := msg.Data
if p.requestedPeerList { // Create new list of possible peers for the ethereum to process
data := msg.Data peers := make([]string, data.Len())
// Create new list of possible peers for the ethereum to process // Parse each possible peer
peers := make([]string, data.Len()) for i := 0; i < data.Len(); i++ {
// Parse each possible peer value := data.Get(i)
for i := 0; i < data.Len(); i++ { peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint())
value := data.Get(i)
peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint())
}
// Connect to the list of peers
p.ethereum.ProcessPeerList(peers)
// Mark unrequested again
p.requestedPeerList = false
} }
// Connect to the list of peers
p.ethereum.ProcessPeerList(peers)
// Mark unrequested again
p.requestedPeerList = false
case ethwire.MsgGetChainTy: case ethwire.MsgGetChainTy:
var parent *ethchain.Block var parent *ethchain.Block
// Length minus one since the very last element in the array is a count // Length minus one since the very last element in the array is a count