aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-07-25 16:43:35 +0800
committerobscuren <geffobscura@gmail.com>2014-07-25 16:43:35 +0800
commitd761af84c83ae8d9d723e6766abb7950ff59cdf3 (patch)
tree6fe0805649ddf38b2b90e77c5fb2000a4bdab536
parent06ec80f39495bdd92878468cf862f52e9748f1ca (diff)
parent54f9ea14e197ad805f24592153f1b9e69f3bc5c3 (diff)
downloadgo-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar.gz
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar.bz2
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar.lz
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar.xz
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.tar.zst
go-tangerine-d761af84c83ae8d9d723e6766abb7950ff59cdf3.zip
Merge branch 'release/0.6.0'
-rw-r--r--README.md2
-rw-r--r--ethchain/asm.go4
-rw-r--r--ethchain/block.go27
-rw-r--r--ethchain/block_chain.go4
-rw-r--r--ethchain/state_manager.go37
-rw-r--r--ethchain/state_object_test.go52
-rw-r--r--ethchain/state_transition.go73
-rw-r--r--ethchain/transaction_pool.go3
-rw-r--r--ethchain/vm_env.go29
-rw-r--r--ethchain/vm_test.go68
-rw-r--r--ethpub/pub.go11
-rw-r--r--ethpub/types.go19
-rw-r--r--ethstate/.ethtest0
-rw-r--r--ethstate/errors.go23
-rw-r--r--ethstate/state.go (renamed from ethchain/state.go)79
-rw-r--r--ethstate/state_object.go (renamed from ethchain/state_object.go)125
-rw-r--r--ethstate/state_test.go (renamed from ethchain/state_test.go)21
-rw-r--r--ethutil/big.go19
-rw-r--r--ethutil/common.go12
-rw-r--r--ethutil/value.go2
-rw-r--r--ethvm/.ethtest0
-rw-r--r--ethvm/asm.go44
-rw-r--r--ethvm/closure.go (renamed from ethchain/closure.go)29
-rw-r--r--ethvm/common.go27
-rw-r--r--ethvm/stack.go (renamed from ethchain/stack.go)2
-rw-r--r--ethvm/types.go346
-rw-r--r--ethvm/vm.go (renamed from ethchain/vm.go)413
-rw-r--r--ethvm/vm_test.go45
-rw-r--r--peer.go93
29 files changed, 1019 insertions, 590 deletions
diff --git a/README.md b/README.md
index 69c6eb0ad..5b0f6e07f 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
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
individual package for more information.
diff --git a/ethchain/asm.go b/ethchain/asm.go
index 2697953fd..9f99b0c48 100644
--- a/ethchain/asm.go
+++ b/ethchain/asm.go
@@ -25,7 +25,7 @@ func Disassemble(script []byte) (asm []string) {
pc.Add(pc, ethutil.Big1)
a := int64(op) - int64(PUSH1) + 1
if int(pc.Int64()+a) > len(script) {
- return nil
+ return
}
data := script[pc.Int64() : pc.Int64()+a]
@@ -40,5 +40,5 @@ func Disassemble(script []byte) (asm []string) {
pc.Add(pc, ethutil.Big1)
}
- return
+ return asm
}
diff --git a/ethchain/block.go b/ethchain/block.go
index 447d55f99..437525e35 100644
--- a/ethchain/block.go
+++ b/ethchain/block.go
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"math/big"
@@ -39,7 +40,7 @@ type Block struct {
Coinbase []byte
// Block Trie state
//state *ethutil.Trie
- state *State
+ state *ethstate.State
// Difficulty for the current block
Difficulty *big.Int
// Creation time
@@ -104,7 +105,7 @@ func CreateBlock(root interface{},
}
block.SetUncles([]*Block{})
- block.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, root))
+ block.state = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, root))
return block
}
@@ -116,12 +117,12 @@ func (block *Block) Hash() []byte {
func (block *Block) HashNoNonce() []byte {
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.GasLimit, block.GasUsed, block.Time, block.Extra}))
}
-func (block *Block) State() *State {
+func (block *Block) State() *ethstate.State {
return block.state
}
@@ -140,17 +141,17 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
base := new(big.Int)
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)
- account := NewStateObjectFromBytes(block.Coinbase, []byte(data))
+ account := ethstate.NewStateObjectFromBytes(block.Coinbase, []byte(data))
base = new(big.Int)
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)
return true
@@ -312,7 +313,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).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.Difficulty = header.Get(5).BigInt()
block.Number = header.Get(6).BigInt()
@@ -354,7 +355,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
block.PrevHash = header.Get(0).Bytes()
block.UncleSha = header.Get(1).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.Difficulty = header.Get(5).BigInt()
block.Number = header.Get(6).BigInt()
@@ -369,7 +370,7 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
}
func (block *Block) GetRoot() interface{} {
- return block.state.trie.Root
+ return block.state.Trie.Root
}
func (self *Block) Receipts() []*Receipt {
@@ -385,7 +386,7 @@ func (block *Block) header() []interface{} {
// Coinbase address
block.Coinbase,
// root state
- block.state.trie.Root,
+ block.state.Trie.Root,
// Sha of tx
block.TxSha,
// Current block Difficulty
@@ -429,7 +430,7 @@ func (block *Block) String() string {
block.PrevHash,
block.UncleSha,
block.Coinbase,
- block.state.trie.Root,
+ block.state.Trie.Root,
block.TxSha,
block.Difficulty,
block.Number,
diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go
index f72a77706..1a2662787 100644
--- a/ethchain/block_chain.go
+++ b/ethchain/block_chain.go
@@ -44,7 +44,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block {
hash := ZeroHash256
if bc.CurrentBlock != nil {
- root = bc.CurrentBlock.state.trie.Root
+ root = bc.CurrentBlock.state.Trie.Root
hash = bc.LastBlockHash
lastBlockTime = bc.CurrentBlock.Time
}
@@ -297,7 +297,7 @@ func (bc *BlockChain) setLastBlock() {
} else {
AddTestNetFunds(bc.genesisBlock)
- bc.genesisBlock.state.trie.Sync()
+ bc.genesisBlock.state.Trie.Sync()
// Prepare the genesis block
bc.Add(bc.genesisBlock)
diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go
index 6a6c67492..9408cf331 100644
--- a/ethchain/state_manager.go
+++ b/ethchain/state_manager.go
@@ -6,7 +6,7 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
"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/ethwire"
"math/big"
@@ -50,8 +50,6 @@ type StateManager struct {
mutex sync.Mutex
// Canonical block chain
bc *BlockChain
- // Stack for processing contracts
- stack *Stack
// non-persistent key/value memory storage
mem map[string]*big.Int
// Proof of work used for validating
@@ -62,10 +60,10 @@ type StateManager struct {
// Transiently state. The trans state isn't ever saved, validated and
// it could be used for setting account nonces without effecting
// the main states.
- transState *State
+ transState *ethstate.State
// Mining state. The mining state is used purely and solely by the mining
// operation.
- miningState *State
+ miningState *ethstate.State
// The last attempted block is mainly used for debugging purposes
// 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 {
sm := &StateManager{
- stack: NewStack(),
mem: make(map[string]*big.Int),
Pow: &EasyPow{},
Ethereum: ethereum,
@@ -87,19 +84,19 @@ func NewStateManager(ethereum EthManager) *StateManager {
return sm
}
-func (sm *StateManager) CurrentState() *State {
+func (sm *StateManager) CurrentState() *ethstate.State {
return sm.Ethereum.BlockChain().CurrentBlock.State()
}
-func (sm *StateManager) TransState() *State {
+func (sm *StateManager) TransState() *ethstate.State {
return sm.transState
}
-func (sm *StateManager) MiningState() *State {
+func (sm *StateManager) MiningState() *ethstate.State {
return sm.miningState
}
-func (sm *StateManager) NewMiningState() *State {
+func (sm *StateManager) NewMiningState() *ethstate.State {
sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy()
return sm.miningState
@@ -109,7 +106,7 @@ func (sm *StateManager) BlockChain() *BlockChain {
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 (
receipts Receipts
handled, unhandled Transactions
@@ -123,9 +120,9 @@ done:
cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block)
- //fmt.Printf("#%d\n", i+1)
err = st.TransitionState()
if err != nil {
+ statelogger.Infoln(err)
switch {
case IsNonceErr(err):
err = nil // ignore error
@@ -225,7 +222,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
}
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
}
@@ -242,7 +239,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
if dontReact == false {
sm.Ethereum.Reactor().Post("newBlock", block)
- state.manifest.Reset()
+ state.Manifest().Reset()
}
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
}
-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.SetGasPool(block.CalcGasLimit(parent))
@@ -340,7 +337,7 @@ func CalculateUncleReward(block *Block) *big.Int {
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
account := state.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address
@@ -364,14 +361,14 @@ func (sm *StateManager) Stop() {
sm.bc.Stop()
}
-func (sm *StateManager) notifyChanges(state *State) {
- for addr, stateObject := range state.manifest.objectChanges {
+func (sm *StateManager) notifyChanges(state *ethstate.State) {
+ for addr, stateObject := range state.Manifest().ObjectChanges {
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 {
- 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})
}
}
}
diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go
deleted file mode 100644
index 2588100d0..000000000
--- a/ethchain/state_object_test.go
+++ /dev/null
@@ -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)
-}
diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go
index 8ed528c9f..266328ce8 100644
--- a/ethchain/state_transition.go
+++ b/ethchain/state_transition.go
@@ -2,6 +2,10 @@ package ethchain
import (
"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"
)
@@ -27,17 +31,17 @@ type StateTransition struct {
gas, gasPrice *big.Int
value *big.Int
data []byte
- state *State
+ state *ethstate.State
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}
}
-func (self *StateTransition) Coinbase() *StateObject {
+func (self *StateTransition) Coinbase() *ethstate.StateObject {
if self.cb != nil {
return self.cb
}
@@ -45,7 +49,7 @@ func (self *StateTransition) Coinbase() *StateObject {
self.cb = self.state.GetOrNewStateObject(self.coinbase)
return self.cb
}
-func (self *StateTransition) Sender() *StateObject {
+func (self *StateTransition) Sender() *ethstate.StateObject {
if self.sen != nil {
return self.sen
}
@@ -54,7 +58,7 @@ func (self *StateTransition) Sender() *StateObject {
return self.sen
}
-func (self *StateTransition) Receiver() *StateObject {
+func (self *StateTransition) Receiver() *ethstate.StateObject {
if self.tx != nil && self.tx.CreatesContract() {
return nil
}
@@ -67,7 +71,7 @@ func (self *StateTransition) Receiver() *StateObject {
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)
return contract
@@ -154,7 +158,7 @@ func (self *StateTransition) TransitionState() (err error) {
var (
tx = self.tx
sender = self.Sender()
- receiver *StateObject
+ receiver *ethstate.StateObject
)
defer self.RefundGas()
@@ -163,13 +167,13 @@ func (self *StateTransition) TransitionState() (err error) {
sender.Nonce += 1
// Transaction gas
- if err = self.UseGas(GasTx); err != nil {
+ if err = self.UseGas(ethvm.GasTx); err != nil {
return
}
// Pay data gas
dataPrice := big.NewInt(int64(len(self.data)))
- dataPrice.Mul(dataPrice, GasData)
+ dataPrice.Mul(dataPrice, ethvm.GasData)
if err = self.UseGas(dataPrice); err != nil {
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)
}
- var snapshot *State
+ var snapshot *ethstate.State
// If the receiver is nil it's a contract (\0*32).
if tx.CreatesContract() {
// 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)
}
- receiver.script = code
+ receiver.Code = code
} else {
- if len(receiver.Script()) > 0 {
- _, err = self.Eval(receiver.Script(), receiver, "code")
+ if len(receiver.Code) > 0 {
+ _, err = self.Eval(receiver.Code, receiver, "code")
if err != nil {
self.state.Set(snapshot)
@@ -235,7 +239,7 @@ func (self *StateTransition) TransitionState() (err error) {
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 {
return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, sender.Amount)
}
@@ -248,34 +252,35 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error
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 (
- block = self.block
- initiator = self.Sender()
- state = self.state
+ transactor = self.Sender()
+ 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 := 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 := ethvm.New(env)
vm.Verbose = true
vm.Fn = typ
- ret, err = Call(vm, closure, self.data)
+ ret, _, err = callerClosure.Call(vm, self.tx.Data)
return
}
-func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) {
- ret, _, err = closure.Call(vm, data)
+// 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()
- return
+ contract := state.NewStateObject(addr)
+ contract.InitCode = tx.Data
+ contract.State = ethstate.NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
+
+ return contract
+ }
+
+ return nil
}
diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go
index 6ab8d83d9..21c6ea3de 100644
--- a/ethchain/transaction_pool.go
+++ b/ethchain/transaction_pool.go
@@ -5,6 +5,7 @@ import (
"container/list"
"fmt"
"github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethwire"
"math/big"
"sync"
@@ -252,7 +253,7 @@ func (pool *TxPool) CurrentTransactions() []*Transaction {
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() {
tx := e.Value.(*Transaction)
sender := state.GetAccount(tx.Sender())
diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go
new file mode 100644
index 000000000..ddead77fd
--- /dev/null
+++ b/ethchain/vm_env.go
@@ -0,0 +1,29 @@
+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,
+ tx: tx,
+ }
+}
+
+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 }
diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go
deleted file mode 100644
index c8023cd79..000000000
--- a/ethchain/vm_test.go
+++ /dev/null
@@ -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)
-}
diff --git a/ethpub/pub.go b/ethpub/pub.go
index 5d01a7a44..7cc7cf6ce 100644
--- a/ethpub/pub.go
+++ b/ethpub/pub.go
@@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"strings"
@@ -24,11 +25,11 @@ type helper struct {
func EthereumConfig(stateManager *ethchain.StateManager) helper {
return helper{stateManager}
}
-func (self helper) obj() *ethchain.StateObject {
+func (self helper) obj() *ethstate.StateObject {
return self.sm.CurrentState().GetStateObject(cnfCtr)
}
-func (self helper) NameReg() *ethchain.StateObject {
+func (self helper) NameReg() *ethstate.StateObject {
if self.obj() != nil {
addr := self.obj().GetStorage(big.NewInt(0))
if len(addr.Bytes()) > 0 {
@@ -48,6 +49,12 @@ type PEthereum struct {
}
func NewPEthereum(manager ethchain.EthManager) *PEthereum {
+ logger.Warnln("DEPRECATED: ethpub.New should be used in favour of ethpub.NewPEthereum")
+
+ return New(manager)
+}
+
+func New(manager ethchain.EthManager) *PEthereum {
return &PEthereum{
manager,
manager.StateManager(),
diff --git a/ethpub/types.go b/ethpub/types.go
index 9e5159a4c..5cfa2705e 100644
--- a/ethpub/types.go
+++ b/ethpub/types.go
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethcrypto"
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"strings"
@@ -154,10 +155,10 @@ func NewPReciept(contractCreation bool, creationAddress, hash, address []byte) *
}
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}
}
@@ -200,7 +201,7 @@ func (c *PStateObject) Nonce() int {
func (c *PStateObject) Root() string {
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>"
@@ -208,14 +209,14 @@ func (c *PStateObject) Root() string {
func (c *PStateObject) IsContract() bool {
if c.object != nil {
- return len(c.object.Script()) > 0
+ return len(c.object.Code) > 0
}
return false
}
func (self *PStateObject) EachStorage(cb ethtrie.EachCallback) {
- self.object.State().EachStorage(cb)
+ self.object.EachStorage(cb)
}
type KeyVal struct {
@@ -226,7 +227,7 @@ type KeyVal struct {
func (c *PStateObject) StateKeyVal(asJson bool) interface{} {
var values []KeyVal
if c.object != nil {
- c.object.State().EachStorage(func(name string, value *ethutil.Value) {
+ c.object.EachStorage(func(name string, value *ethutil.Value) {
values = append(values, KeyVal{name, ethutil.Bytes2Hex(value.Bytes())})
})
}
@@ -245,7 +246,7 @@ func (c *PStateObject) StateKeyVal(asJson bool) interface{} {
func (c *PStateObject) Script() string {
if c.object != nil {
- return strings.Join(ethchain.Disassemble(c.object.Script()), " ")
+ return strings.Join(ethchain.Disassemble(c.object.Code), " ")
}
return ""
@@ -253,7 +254,7 @@ func (c *PStateObject) Script() string {
func (c *PStateObject) HexScript() string {
if c.object != nil {
- return ethutil.Bytes2Hex(c.object.Script())
+ return ethutil.Bytes2Hex(c.object.Code)
}
return ""
@@ -265,6 +266,6 @@ type PStorageState struct {
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()}
}
diff --git a/ethstate/.ethtest b/ethstate/.ethtest
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ethstate/.ethtest
diff --git a/ethstate/errors.go b/ethstate/errors.go
new file mode 100644
index 000000000..d5d7db86b
--- /dev/null
+++ b/ethstate/errors.go
@@ -0,0 +1,23 @@
+package ethstate
+
+import (
+ "fmt"
+ "math/big"
+)
+
+type GasLimitErr struct {
+ Message string
+ Is, Max *big.Int
+}
+
+func IsGasLimitErr(err error) bool {
+ _, ok := err.(*GasLimitErr)
+
+ return ok
+}
+func (err *GasLimitErr) Error() string {
+ return err.Message
+}
+func GasLimitError(is, max *big.Int) *GasLimitErr {
+ return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max}
+}
diff --git a/ethchain/state.go b/ethstate/state.go
index 684b81102..51b585d4d 100644
--- a/ethchain/state.go
+++ b/ethstate/state.go
@@ -1,13 +1,15 @@
-package ethchain
+package ethstate
import (
- "fmt"
"github.com/ethereum/eth-go/ethcrypto"
+ "github.com/ethereum/eth-go/ethlog"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
+var statelogger = ethlog.NewLogger("STATE")
+
// 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:
@@ -15,7 +17,7 @@ import (
// * Accounts
type State struct {
// The trie for this structure
- trie *ethtrie.Trie
+ Trie *ethtrie.Trie
stateObjects map[string]*StateObject
@@ -24,13 +26,7 @@ type State struct {
// 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()}
-}
-
-// Iterate over each storage address and yield callback
-func (s *State) EachStorage(cb ethtrie.EachCallback) {
- it := s.trie.NewIterator()
- it.Each(cb)
+ return &State{Trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
}
// Retrieve the balance from the given address or 0 if object not found
@@ -60,16 +56,16 @@ func (self *State) GetNonce(addr []byte) uint64 {
func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
- ethutil.Config.Db.Put(ethcrypto.Sha3Bin(stateObject.Script()), stateObject.Script())
+ 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)
}
// Delete the given state object and delete it from the state trie
func (self *State) DeleteStateObject(stateObject *StateObject) {
- self.trie.Delete(string(stateObject.Address()))
+ self.Trie.Delete(string(stateObject.Address()))
delete(self.stateObjects, string(stateObject.Address()))
}
@@ -83,7 +79,7 @@ func (self *State) GetStateObject(addr []byte) *StateObject {
return stateObject
}
- data := self.trie.Get(string(addr))
+ data := self.Trie.Get(string(addr))
if len(data) == 0 {
return nil
}
@@ -106,6 +102,8 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
// Create a state object whether it exist in the trie or not
func (self *State) NewStateObject(addr []byte) *StateObject {
+ addr = ethutil.Address(addr)
+
statelogger.Infof("(+) %x\n", addr)
stateObject := NewStateObject(addr)
@@ -124,12 +122,12 @@ func (self *State) GetAccount(addr []byte) *StateObject {
//
func (s *State) Cmp(other *State) bool {
- return s.trie.Cmp(other.trie)
+ return s.Trie.Cmp(other.Trie)
}
func (self *State) Copy() *State {
- if self.trie != nil {
- state := NewState(self.trie.Copy())
+ if self.Trie != nil {
+ state := NewState(self.Trie.Copy())
for k, stateObject := range self.stateObjects {
state.stateObjects[k] = stateObject.Copy()
}
@@ -145,21 +143,21 @@ func (self *State) Set(state *State) {
panic("Tried setting 'state' to nil through 'Set'")
}
- self.trie = state.trie
+ self.Trie = state.Trie
self.stateObjects = state.stateObjects
}
func (s *State) Root() interface{} {
- return s.trie.Root
+ return s.Trie.Root
}
// Resets the trie and all siblings
func (s *State) Reset() {
- s.trie.Undo()
+ s.Trie.Undo()
// Reset all nested states
for _, stateObject := range s.stateObjects {
- if stateObject.state == nil {
+ if stateObject.State == nil {
continue
}
@@ -176,14 +174,14 @@ func (s *State) Sync() {
for _, stateObject := range s.stateObjects {
//s.UpdateStateObject(stateObject)
- if stateObject.state == nil {
+ if stateObject.State == nil {
continue
}
- stateObject.state.Sync()
+ stateObject.State.Sync()
}
- s.trie.Sync()
+ s.Trie.Sync()
s.Empty()
}
@@ -204,24 +202,25 @@ func (self *State) Update() {
}
// FIXME trie delete is broken
- valid, t2 := ethtrie.ParanoiaCheck(self.trie)
+ 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)
+ statelogger.Infof("Warn: PARANOIA: Different state root during copy %x vs %x\n", self.Trie.Root, t2.Root)
- self.trie = t2
+ self.Trie = t2
}
}
// Debug stuff
func (self *State) CreateOutputForDiff() {
- for addr, stateObject := range self.stateObjects {
- fmt.Printf("%x %x %x %x\n", addr, stateObject.state.Root(), stateObject.Amount.Bytes(), stateObject.Nonce)
- stateObject.state.EachStorage(func(addr string, value *ethutil.Value) {
- fmt.Printf("%x %x\n", addr, value.Bytes())
- })
+ for _, stateObject := range self.stateObjects {
+ stateObject.CreateOutputForDiff()
}
}
+func (self *State) Manifest() *Manifest {
+ return self.manifest
+}
+
// Object manifest
//
// The object manifest is used to keep changes to the state so we can keep track of the changes
@@ -231,8 +230,8 @@ type Manifest struct {
objectAddresses map[string]bool
storageAddresses map[string]map[string]bool
- objectChanges map[string]*StateObject
- storageChanges map[string]map[string]*big.Int
+ ObjectChanges map[string]*StateObject
+ StorageChanges map[string]map[string]*big.Int
}
func NewManifest() *Manifest {
@@ -243,18 +242,18 @@ func NewManifest() *Manifest {
}
func (m *Manifest) Reset() {
- m.objectChanges = make(map[string]*StateObject)
- m.storageChanges = make(map[string]map[string]*big.Int)
+ 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
+ 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)
+ 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
+ m.StorageChanges[string(stateObject.Address())][string(storageAddr)] = storage
}
diff --git a/ethchain/state_object.go b/ethstate/state_object.go
index 8e7b5fece..ab14b8604 100644
--- a/ethchain/state_object.go
+++ b/ethstate/state_object.go
@@ -1,4 +1,4 @@
-package ethchain
+package ethstate
import (
"fmt"
@@ -6,13 +6,12 @@ import (
"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), " ")
+ return string(self) //strings.Join(Disassemble(self), " ")
}
type Storage map[string]*ethutil.Value
@@ -31,13 +30,13 @@ type StateObject struct {
// Address of the object
address []byte
// Shared attributes
- Amount *big.Int
- ScriptHash []byte
- Nonce uint64
+ Amount *big.Int
+ CodeHash []byte
+ Nonce uint64
// Contract related attributes
- state *State
- script Code
- initScript Code
+ State *State
+ Code Code
+ InitCode Code
storage Storage
@@ -54,9 +53,10 @@ type StateObject struct {
func (self *StateObject) Reset() {
self.storage = make(Storage)
- self.state.Reset()
+ 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
@@ -64,7 +64,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
addr := tx.CreationAddress()
contract := state.NewStateObject(addr)
- contract.initScript = tx.Data
+ contract.initCode = tx.Data
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
return contract
@@ -72,13 +72,14 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
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.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
object.storage = make(Storage)
object.gasPool = new(big.Int)
@@ -88,7 +89,7 @@ func NewStateObject(addr []byte) *StateObject {
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)))
+ contract.State = NewState(ethtrie.NewTrie(ethutil.Config.Db, string(root)))
return contract
}
@@ -106,11 +107,11 @@ func (self *StateObject) MarkForDeletion() {
}
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{}) {
- 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 {
@@ -140,59 +141,52 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value {
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
- }
+// 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)
+ }
- self.SetAddr(key, value)
- */
+ 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))
+ self.State.Trie.Delete(string(key))
continue
}
self.SetAddr([]byte(key), value)
}
- valid, t2 := ethtrie.ParanoiaCheck(self.state.trie)
+ 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)
+ 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
}
-
- /*
- 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() {
+ if int64(len(c.Code)-1) < pc.Int64() {
return ethutil.NewValue(0)
}
- return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]})
+ return ethutil.NewValueFromBytes([]byte{c.Code[pc.Int64()]})
}
func (c *StateObject) AddAmount(amount *big.Int) {
@@ -216,7 +210,7 @@ func (c *StateObject) SetAmount(amount *big.Int) {
//
// 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) ReturnGas(gas, price *big.Int) {}
func (c *StateObject) ConvertGas(gas, price *big.Int) error {
total := new(big.Int).Mul(gas, price)
if total.Cmp(c.Amount) > 0 {
@@ -259,13 +253,13 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
func (self *StateObject) Copy() *StateObject {
stateObject := NewStateObject(self.Address())
stateObject.Amount.Set(self.Amount)
- stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash)
+ stateObject.CodeHash = ethutil.CopyBytes(self.CodeHash)
stateObject.Nonce = self.Nonce
- if self.state != nil {
- stateObject.state = self.state.Copy()
+ if self.State != nil {
+ stateObject.State = self.State.Copy()
}
- stateObject.script = ethutil.CopyBytes(self.script)
- stateObject.initScript = ethutil.CopyBytes(self.initScript)
+ stateObject.Code = ethutil.CopyBytes(self.Code)
+ stateObject.InitCode = ethutil.CopyBytes(self.InitCode)
stateObject.storage = self.storage.Copy()
stateObject.gasPool.Set(self.gasPool)
@@ -280,10 +274,6 @@ func (self *StateObject) Set(stateObject *StateObject) {
// Attribute accessors
//
-func (c *StateObject) State() *State {
- return c.state
-}
-
func (c *StateObject) N() *big.Int {
return big.NewInt(int64(c.Nonce))
}
@@ -293,14 +283,17 @@ func (c *StateObject) Address() []byte {
return c.address
}
-// Returns the main script body
-func (c *StateObject) Script() Code {
- return c.script
+// Returns the initialization Code
+func (c *StateObject) Init() Code {
+ return c.InitCode
}
-// 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())
+ })
}
//
@@ -310,13 +303,13 @@ func (c *StateObject) Init() Code {
// State object encoding methods
func (c *StateObject) RlpEncode() []byte {
var root interface{}
- if c.state != nil {
- root = c.state.trie.Root
+ if c.State != nil {
+ root = c.State.Trie.Root
} else {
root = ""
}
- return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.script)})
+ return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethcrypto.Sha3Bin(c.Code)})
}
func (c *StateObject) RlpDecode(data []byte) {
@@ -324,13 +317,13 @@ func (c *StateObject) RlpDecode(data []byte) {
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.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.CodeHash = decoder.Get(3).Bytes()
- c.script, _ = ethutil.Config.Db.Get(c.ScriptHash)
+ c.Code, _ = ethutil.Config.Db.Get(c.CodeHash)
}
// Storage change object. Used by the manifest for notifying changes to
diff --git a/ethchain/state_test.go b/ethstate/state_test.go
index 95be0f373..cd13e80bc 100644
--- a/ethchain/state_test.go
+++ b/ethstate/state_test.go
@@ -1,19 +1,23 @@
-package ethchain
+package ethstate
import (
"github.com/ethereum/eth-go/ethdb"
+ "github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil"
"testing"
)
-func TestSnapshot(t *testing.T) {
- ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
+var ZeroHash256 = make([]byte, 32)
+func TestSnapshot(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
- state := NewState(ethutil.NewTrie(db, ""))
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
+ ethutil.Config.Db = db
+
+ state := NewState(ethtrie.NewTrie(db, ""))
+
+ stateObject := state.GetOrNewStateObject([]byte("aa"))
- stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
- state.UpdateStateObject(stateObject)
stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42))
snapshot := state.Copy()
@@ -24,7 +28,8 @@ func TestSnapshot(t *testing.T) {
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")
+ res := stateObject.GetStorage(ethutil.Big("0"))
+ if !res.Cmp(ethutil.NewValue(42)) {
+ t.Error("Expected storage 0 to be 42", res)
}
}
diff --git a/ethutil/big.go b/ethutil/big.go
index 7af6f7414..ec263b818 100644
--- a/ethutil/big.go
+++ b/ethutil/big.go
@@ -4,14 +4,6 @@ import (
"math/big"
)
-var BigInt0 *big.Int = big.NewInt(0)
-
-// True
-var BigTrue *big.Int = big.NewInt(1)
-
-// False
-var BigFalse *big.Int = big.NewInt(0)
-
// Big pow
//
// Returns the power of two big integers
@@ -73,3 +65,14 @@ func BigMax(x, y *big.Int) *big.Int {
return x
}
+
+// Big min
+//
+// Returns the minimum size big integer
+func BigMin(x, y *big.Int) *big.Int {
+ if x.Cmp(y) >= 0 {
+ return y
+ }
+
+ return x
+}
diff --git a/ethutil/common.go b/ethutil/common.go
index 2fd031a20..cbd94e7ad 100644
--- a/ethutil/common.go
+++ b/ethutil/common.go
@@ -58,9 +58,11 @@ func CurrencyToString(num *big.Int) string {
// Common big integers often used
var (
- Big1 = big.NewInt(1)
- Big2 = big.NewInt(2)
- Big0 = big.NewInt(0)
- Big32 = big.NewInt(32)
- Big256 = big.NewInt(0xff)
+ Big1 = big.NewInt(1)
+ Big2 = big.NewInt(2)
+ Big0 = big.NewInt(0)
+ BigTrue = Big1
+ BigFalse = Big0
+ Big32 = big.NewInt(32)
+ Big256 = big.NewInt(0xff)
)
diff --git a/ethutil/value.go b/ethutil/value.go
index fba7426d1..735a71dbc 100644
--- a/ethutil/value.go
+++ b/ethutil/value.go
@@ -68,6 +68,8 @@ func (val *Value) Uint() uint64 {
return uint64(Val)
} else if Val, ok := val.Val.([]byte); ok {
return ReadVarint(bytes.NewReader(Val))
+ } else if Val, ok := val.Val.(*big.Int); ok {
+ return Val.Uint64()
}
return 0
diff --git a/ethvm/.ethtest b/ethvm/.ethtest
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/ethvm/.ethtest
diff --git a/ethvm/asm.go b/ethvm/asm.go
new file mode 100644
index 000000000..7ff15a240
--- /dev/null
+++ b/ethvm/asm.go
@@ -0,0 +1,44 @@
+package ethvm
+
+import (
+ "fmt"
+ "github.com/ethereum/eth-go/ethutil"
+ "math/big"
+)
+
+func Disassemble(script []byte) (asm []string) {
+ pc := new(big.Int)
+ for {
+ if pc.Cmp(big.NewInt(int64(len(script)))) >= 0 {
+ return
+ }
+
+ // Get the memory location of pc
+ val := script[pc.Int64()]
+ // Get the opcode (it must be an opcode!)
+ op := OpCode(val)
+
+ asm = append(asm, fmt.Sprintf("%v", op))
+
+ switch op {
+ 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:
+ pc.Add(pc, ethutil.Big1)
+ a := int64(op) - int64(PUSH1) + 1
+ if int(pc.Int64()+a) > len(script) {
+ return nil
+ }
+
+ data := script[pc.Int64() : pc.Int64()+a]
+ if len(data) == 0 {
+ data = []byte{0}
+ }
+ asm = append(asm, fmt.Sprintf("0x%x", data))
+
+ pc.Add(pc, big.NewInt(a-1))
+ }
+
+ pc.Add(pc, ethutil.Big1)
+ }
+
+ return
+}
diff --git a/ethchain/closure.go b/ethvm/closure.go
index 1f7f8d703..505fd43fb 100644
--- a/ethchain/closure.go
+++ b/ethvm/closure.go
@@ -1,26 +1,25 @@
-package ethchain
+package ethvm
// TODO Re write VM to use values instead of big integers?
import (
+ "github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type ClosureRef interface {
- ReturnGas(*big.Int, *big.Int, *State)
+ ReturnGas(*big.Int, *big.Int)
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
+ object *ethstate.StateObject
+ Code []byte
Gas, UsedGas, Price *big.Int
@@ -28,8 +27,8 @@ type Closure struct {
}
// 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}
+func NewClosure(caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure {
+ c := &Closure{caller: caller, object: object, Code: code, Args: nil}
// Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition
@@ -57,11 +56,11 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value {
}
func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
- if x.Int64() >= int64(len(c.Script)) || y.Int64() >= int64(len(c.Script)) {
+ if x.Int64() >= int64(len(c.Code)) || y.Int64() >= int64(len(c.Code)) {
return ethutil.NewValue(0)
}
- partial := c.Script[x.Int64() : x.Int64()+y.Int64()]
+ partial := c.Code[x.Int64() : x.Int64()+y.Int64()]
return ethutil.NewValue(partial)
}
@@ -84,7 +83,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) {
func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the caller
- c.caller.ReturnGas(c.Gas, c.Price, c.State)
+ c.caller.ReturnGas(c.Gas, c.Price)
return ret
}
@@ -102,20 +101,16 @@ func (c *Closure) UseGas(gas *big.Int) bool {
}
// Implement the caller interface
-func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
+func (c *Closure) ReturnGas(gas, price *big.Int) {
// Return the gas to the closure
c.Gas.Add(c.Gas, gas)
c.UsedGas.Sub(c.UsedGas, gas)
}
-func (c *Closure) Object() *StateObject {
+func (c *Closure) Object() *ethstate.StateObject {
return c.object
}
func (c *Closure) Caller() ClosureRef {
return c.caller
}
-
-func (c *Closure) N() *big.Int {
- return c.object.N()
-}
diff --git a/ethvm/common.go b/ethvm/common.go
new file mode 100644
index 000000000..5a3aec648
--- /dev/null
+++ b/ethvm/common.go
@@ -0,0 +1,27 @@
+package ethvm
+
+import (
+ "github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethutil"
+ "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)
+
+ Pow256 = ethutil.BigPow(2, 256)
+
+ LogTyPretty byte = 0x1
+ LogTyDiff byte = 0x2
+)
diff --git a/ethchain/stack.go b/ethvm/stack.go
index a9fa2e522..c06d63652 100644
--- a/ethchain/stack.go
+++ b/ethvm/stack.go
@@ -1,4 +1,4 @@
-package ethchain
+package ethvm
import (
"fmt"
diff --git a/ethvm/types.go b/ethvm/types.go
new file mode 100644
index 000000000..1c3f66139
--- /dev/null
+++ b/ethvm/types.go
@@ -0,0 +1,346 @@
+package ethvm
+
+import (
+ "fmt"
+)
+
+type OpCode int
+
+// Op codes
+const (
+ // 0x0 range - arithmetic ops
+ STOP = 0x00
+ ADD = 0x01
+ MUL = 0x02
+ SUB = 0x03
+ DIV = 0x04
+ SDIV = 0x05
+ MOD = 0x06
+ SMOD = 0x07
+ EXP = 0x08
+ NEG = 0x09
+ LT = 0x0a
+ GT = 0x0b
+ SLT = 0x0c
+ SGT = 0x0d
+ EQ = 0x0e
+ NOT = 0x0f
+
+ // 0x10 range - bit ops
+ AND = 0x10
+ OR = 0x11
+ XOR = 0x12
+ BYTE = 0x13
+
+ // 0x20 range - crypto
+ SHA3 = 0x20
+
+ // 0x30 range - closure state
+ ADDRESS = 0x30
+ BALANCE = 0x31
+ ORIGIN = 0x32
+ CALLER = 0x33
+ CALLVALUE = 0x34
+ CALLDATALOAD = 0x35
+ CALLDATASIZE = 0x36
+ CALLDATACOPY = 0x37
+ CODESIZE = 0x38
+ CODECOPY = 0x39
+ GASPRICE = 0x3a
+
+ // 0x40 range - block operations
+ PREVHASH = 0x40
+ COINBASE = 0x41
+ TIMESTAMP = 0x42
+ NUMBER = 0x43
+ DIFFICULTY = 0x44
+ GASLIMIT = 0x45
+
+ // 0x50 range - 'storage' and execution
+ POP = 0x50
+ DUP = 0x51
+ SWAP = 0x52
+ MLOAD = 0x53
+ MSTORE = 0x54
+ MSTORE8 = 0x55
+ SLOAD = 0x56
+ SSTORE = 0x57
+ JUMP = 0x58
+ JUMPI = 0x59
+ PC = 0x5a
+ MSIZE = 0x5b
+ GAS = 0x5c
+
+ // 0x60 range
+ PUSH1 = 0x60
+ PUSH2 = 0x61
+ PUSH3 = 0x62
+ PUSH4 = 0x63
+ PUSH5 = 0x64
+ PUSH6 = 0x65
+ PUSH7 = 0x66
+ PUSH8 = 0x67
+ PUSH9 = 0x68
+ PUSH10 = 0x69
+ PUSH11 = 0x6a
+ PUSH12 = 0x6b
+ PUSH13 = 0x6c
+ PUSH14 = 0x6d
+ PUSH15 = 0x6e
+ PUSH16 = 0x6f
+ PUSH17 = 0x70
+ PUSH18 = 0x71
+ PUSH19 = 0x72
+ PUSH20 = 0x73
+ PUSH21 = 0x74
+ PUSH22 = 0x75
+ PUSH23 = 0x76
+ PUSH24 = 0x77
+ PUSH25 = 0x78
+ PUSH26 = 0x79
+ PUSH27 = 0x7a
+ PUSH28 = 0x7b
+ PUSH29 = 0x7c
+ PUSH30 = 0x7d
+ PUSH31 = 0x7e
+ PUSH32 = 0x7f
+
+ // 0xf0 range - closures
+ CREATE = 0xf0
+ CALL = 0xf1
+ RETURN = 0xf2
+
+ // 0x70 range - other
+ LOG = 0xfe // XXX Unofficial
+ SUICIDE = 0xff
+)
+
+// Since the opcodes aren't all in order we can't use a regular slice
+var opCodeToString = map[OpCode]string{
+ // 0x0 range - arithmetic ops
+ STOP: "STOP",
+ ADD: "ADD",
+ MUL: "MUL",
+ SUB: "SUB",
+ DIV: "DIV",
+ SDIV: "SDIV",
+ MOD: "MOD",
+ SMOD: "SMOD",
+ EXP: "EXP",
+ NEG: "NEG",
+ LT: "LT",
+ GT: "GT",
+ SLT: "SLT",
+ SGT: "SGT",
+ EQ: "EQ",
+ NOT: "NOT",
+
+ // 0x10 range - bit ops
+ AND: "AND",
+ OR: "OR",
+ XOR: "XOR",
+ BYTE: "BYTE",
+
+ // 0x20 range - crypto
+ SHA3: "SHA3",
+
+ // 0x30 range - closure state
+ ADDRESS: "ADDRESS",
+ BALANCE: "BALANCE",
+ ORIGIN: "ORIGIN",
+ CALLER: "CALLER",
+ CALLVALUE: "CALLVALUE",
+ CALLDATALOAD: "CALLDATALOAD",
+ CALLDATASIZE: "CALLDATASIZE",
+ CALLDATACOPY: "CALLDATACOPY",
+ CODESIZE: "CODESIZE",
+ CODECOPY: "CODECOPY",
+ GASPRICE: "TXGASPRICE",
+
+ // 0x40 range - block operations
+ PREVHASH: "PREVHASH",
+ COINBASE: "COINBASE",
+ TIMESTAMP: "TIMESTAMP",
+ NUMBER: "NUMBER",
+ DIFFICULTY: "DIFFICULTY",
+ GASLIMIT: "GASLIMIT",
+
+ // 0x50 range - 'storage' and execution
+ POP: "POP",
+ DUP: "DUP",
+ SWAP: "SWAP",
+ MLOAD: "MLOAD",
+ MSTORE: "MSTORE",
+ MSTORE8: "MSTORE8",
+ SLOAD: "SLOAD",
+ SSTORE: "SSTORE",
+ JUMP: "JUMP",
+ JUMPI: "JUMPI",
+ PC: "PC",
+ MSIZE: "MSIZE",
+ GAS: "GAS",
+
+ // 0x60 range - push
+ PUSH1: "PUSH1",
+ PUSH2: "PUSH2",
+ PUSH3: "PUSH3",
+ PUSH4: "PUSH4",
+ PUSH5: "PUSH5",
+ PUSH6: "PUSH6",
+ PUSH7: "PUSH7",
+ PUSH8: "PUSH8",
+ PUSH9: "PUSH9",
+ PUSH10: "PUSH10",
+ PUSH11: "PUSH11",
+ PUSH12: "PUSH12",
+ PUSH13: "PUSH13",
+ PUSH14: "PUSH14",
+ PUSH15: "PUSH15",
+ PUSH16: "PUSH16",
+ PUSH17: "PUSH17",
+ PUSH18: "PUSH18",
+ PUSH19: "PUSH19",
+ PUSH20: "PUSH20",
+ PUSH21: "PUSH21",
+ PUSH22: "PUSH22",
+ PUSH23: "PUSH23",
+ PUSH24: "PUSH24",
+ PUSH25: "PUSH25",
+ PUSH26: "PUSH26",
+ PUSH27: "PUSH27",
+ PUSH28: "PUSH28",
+ PUSH29: "PUSH29",
+ PUSH30: "PUSH30",
+ PUSH31: "PUSH31",
+ PUSH32: "PUSH32",
+
+ // 0xf0 range
+ CREATE: "CREATE",
+ CALL: "CALL",
+ RETURN: "RETURN",
+
+ // 0x70 range - other
+ LOG: "LOG",
+ SUICIDE: "SUICIDE",
+}
+
+func (o OpCode) String() string {
+ str := opCodeToString[o]
+ if len(str) == 0 {
+ return fmt.Sprintf("Missing opcode 0x%x", int(o))
+ }
+
+ return str
+}
+
+// Op codes for assembling
+var OpCodes = map[string]byte{
+ // 0x0 range - arithmetic ops
+ "STOP": 0x00,
+ "ADD": 0x01,
+ "MUL": 0x02,
+ "SUB": 0x03,
+ "DIV": 0x04,
+ "SDIV": 0x05,
+ "MOD": 0x06,
+ "SMOD": 0x07,
+ "EXP": 0x08,
+ "NEG": 0x09,
+ "LT": 0x0a,
+ "GT": 0x0b,
+ "EQ": 0x0c,
+ "NOT": 0x0d,
+
+ // 0x10 range - bit ops
+ "AND": 0x10,
+ "OR": 0x11,
+ "XOR": 0x12,
+ "BYTE": 0x13,
+
+ // 0x20 range - crypto
+ "SHA3": 0x20,
+
+ // 0x30 range - closure state
+ "ADDRESS": 0x30,
+ "BALANCE": 0x31,
+ "ORIGIN": 0x32,
+ "CALLER": 0x33,
+ "CALLVALUE": 0x34,
+ "CALLDATALOAD": 0x35,
+ "CALLDATASIZE": 0x36,
+ "GASPRICE": 0x38,
+
+ // 0x40 range - block operations
+ "PREVHASH": 0x40,
+ "COINBASE": 0x41,
+ "TIMESTAMP": 0x42,
+ "NUMBER": 0x43,
+ "DIFFICULTY": 0x44,
+ "GASLIMIT": 0x45,
+
+ // 0x50 range - 'storage' and execution
+ "POP": 0x51,
+ "DUP": 0x52,
+ "SWAP": 0x53,
+ "MLOAD": 0x54,
+ "MSTORE": 0x55,
+ "MSTORE8": 0x56,
+ "SLOAD": 0x57,
+ "SSTORE": 0x58,
+ "JUMP": 0x59,
+ "JUMPI": 0x5a,
+ "PC": 0x5b,
+ "MSIZE": 0x5c,
+
+ // 0x70 range - 'push'
+ "PUSH1": 0x60,
+ "PUSH2": 0x61,
+ "PUSH3": 0x62,
+ "PUSH4": 0x63,
+ "PUSH5": 0x64,
+ "PUSH6": 0x65,
+ "PUSH7": 0x66,
+ "PUSH8": 0x67,
+ "PUSH9": 0x68,
+ "PUSH10": 0x69,
+ "PUSH11": 0x6a,
+ "PUSH12": 0x6b,
+ "PUSH13": 0x6c,
+ "PUSH14": 0x6d,
+ "PUSH15": 0x6e,
+ "PUSH16": 0x6f,
+ "PUSH17": 0x70,
+ "PUSH18": 0x71,
+ "PUSH19": 0x72,
+ "PUSH20": 0x73,
+ "PUSH21": 0x74,
+ "PUSH22": 0x75,
+ "PUSH23": 0x76,
+ "PUSH24": 0x77,
+ "PUSH25": 0x78,
+ "PUSH26": 0x70,
+ "PUSH27": 0x7a,
+ "PUSH28": 0x7b,
+ "PUSH29": 0x7c,
+ "PUSH30": 0x7d,
+ "PUSH31": 0x7e,
+ "PUSH32": 0x7f,
+
+ // 0xf0 range - closures
+ "CREATE": 0xf0,
+ "CALL": 0xf1,
+ "RETURN": 0xf2,
+
+ // 0x70 range - other
+ "LOG": 0xfe,
+ "SUICIDE": 0x7f,
+}
+
+func IsOpCode(s string) bool {
+ for key, _ := range OpCodes {
+ if key == s {
+ return true
+ }
+ }
+ return false
+}
diff --git a/ethchain/vm.go b/ethvm/vm.go
index 07e9a0f2c..a93b56e60 100644
--- a/ethchain/vm.go
+++ b/ethvm/vm.go
@@ -1,35 +1,17 @@
-package ethchain
+package ethvm
import (
"fmt"
"github.com/ethereum/eth-go/ethcrypto"
- "github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethstate"
"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
+ BreakHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool
+ StepHook(step int, op OpCode, mem *Memory, stack *Stack, object *ethstate.StateObject) bool
BreakPoints() []int64
SetCode(byteCode []byte)
}
@@ -40,11 +22,7 @@ type Vm struct {
// non-persistent key/value memory storage
mem map[string]*big.Int
- vars RuntimeVars
-
- state *State
-
- stateManager *StateManager
+ env Environment
Verbose bool
@@ -59,71 +37,59 @@ type Vm struct {
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
+ Recoverable bool
}
-func (self *Vm) Printf(format string, v ...interface{}) *Vm {
- if self.Verbose && self.logTy == LogTyPretty {
- self.logStr += fmt.Sprintf(format, v...)
- }
+type Environment interface {
+ State() *ethstate.State
- return self
+ Origin() []byte
+ BlockNumber() *big.Int
+ PrevHash() []byte
+ Coinbase() []byte
+ Time() int64
+ Difficulty() *big.Int
+ Value() *big.Int
}
-func (self *Vm) Endl() *Vm {
- if self.Verbose && self.logTy == LogTyPretty {
- vmlogger.Debugln(self.logStr)
- self.logStr = ""
- }
-
- return self
+type Object interface {
+ GetStorage(key *big.Int) *ethutil.Value
+ SetStorage(key *big.Int, value *ethutil.Value)
}
-func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
+func New(env Environment) *Vm {
lt := LogTyPretty
if ethutil.Config.Diff {
lt = LogTyDiff
}
- return &Vm{vars: vars, state: state, stateManager: stateManager, logTy: lt}
+ return &Vm{env: env, logTy: lt, Recoverable: true}
}
-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)
- }
- }()
+func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
+ if self.Recoverable {
+ // 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)
+ if self.Dbg != nil {
+ self.Dbg.SetCode(closure.Code)
}
// Don't bother with the execution if there's no code.
- if len(closure.Script) == 0 {
+ if len(closure.Code) == 0 {
return closure.Return(nil), nil
}
- vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", vm.Fn, closure.Address(), closure.Gas, closure.Args)
+ vmlogger.Debugf("(%s) %x gas: %v (d) %x\n", self.Fn, closure.Address(), closure.Gas, closure.Args)
var (
op OpCode
@@ -135,7 +101,6 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
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))
}
}
@@ -154,22 +119,23 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// 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.state.EachStorage(func(key string, value *ethutil.Value) {
- value.Decode()
- fmt.Printf("%x %x\n", new(big.Int).SetBytes([]byte(key)).Bytes(), value.Bytes())
- })
- }
+ if self.logTy == LogTyDiff {
+ /*
+ switch op {
+ case STOP, RETURN, SUICIDE:
+ 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}
- }
+ 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())
+ fmt.Printf("%x %x %x %x\n", closure.Address(), b, []byte{byte(op)}, closure.Gas.Bytes())
+ */
}
gas := new(big.Int)
@@ -261,8 +227,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
return closure.Return(nil), err
}
- vm.Printf("(pc) %-3d -o- %-14s", pc, op.String())
- vm.Printf(" (g) %-3v (%v)", gas, closure.Gas)
+ self.Printf("(pc) %-3d -o- %-14s", pc, op.String())
+ self.Printf(" (g) %-3v (%v)", gas, closure.Gas)
mem.Resize(newMemSize)
@@ -274,98 +240,87 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case ADD:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v + %v", y, x)
+ self.Printf(" %v + %v", y, x)
base.Add(y, x)
- vm.Printf(" = %v", base)
+ self.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)
+ self.Printf(" %v - %v", y, x)
base.Sub(y, x)
- vm.Printf(" = %v", base)
+ self.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)
+ self.Printf(" %v * %v", y, x)
base.Mul(y, x)
- vm.Printf(" = %v", base)
+ self.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)
+ self.Printf(" %v / %v", y, x)
if x.Cmp(ethutil.Big0) != 0 {
base.Div(y, x)
}
- vm.Printf(" = %v", base)
+ self.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)
+ self.Printf(" %v / %v", y, x)
+
+ if x.Cmp(ethutil.Big0) != 0 {
+ base.Div(y, x)
}
- // Push result on to the stack
- stack.Push(z)
+
+ self.Printf(" = %v", base)
+ // Pop result back on the stack
+ stack.Push(base)
case MOD:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v %% %v", y, x)
+ self.Printf(" %v %% %v", y, x)
base.Mod(y, x)
- vm.Printf(" = %v", base)
+ self.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)
+
+ self.Printf(" %v %% %v", y, x)
+
+ base.Mod(y, x)
+
+ self.Printf(" = %v", base)
+ stack.Push(base)
+
case EXP:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v ** %v", y, x)
+ self.Printf(" %v ** %v", y, x)
base.Exp(y, x, Pow256)
- vm.Printf(" = %v", base)
+ self.Printf(" = %v", base)
stack.Push(base)
case NEG:
@@ -375,7 +330,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case LT:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v < %v", y, x)
+ self.Printf(" %v < %v", y, x)
// x < y
if y.Cmp(x) < 0 {
stack.Push(ethutil.BigTrue)
@@ -385,7 +340,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case GT:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v > %v", y, x)
+ self.Printf(" %v > %v", y, x)
// x > y
if y.Cmp(x) > 0 {
@@ -397,7 +352,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case SLT:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v < %v", y, x)
+ self.Printf(" %v < %v", y, x)
// x < y
if y.Cmp(x) < 0 {
stack.Push(ethutil.BigTrue)
@@ -407,7 +362,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case SGT:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v > %v", y, x)
+ self.Printf(" %v > %v", y, x)
// x > y
if y.Cmp(x) > 0 {
@@ -419,7 +374,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case EQ:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v == %v", y, x)
+ self.Printf(" %v == %v", y, x)
// x == y
if x.Cmp(y) == 0 {
@@ -440,29 +395,29 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
case AND:
require(2)
x, y := stack.Popn()
- vm.Printf(" %v & %v", y, x)
+ self.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)
+ self.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)
+ self.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()]))
+ byt := big.NewInt(int64(ethutil.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
stack.Push(byt)
- vm.Printf(" => 0x%x", byt.Bytes())
+ self.Printf(" => 0x%x", byt.Bytes())
} else {
stack.Push(ethutil.BigFalse)
}
@@ -475,53 +430,61 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
stack.Push(ethutil.BigD(data))
- vm.Printf(" => %x", data)
+ self.Printf(" => %x", data)
// 0x30 range
case ADDRESS:
stack.Push(ethutil.BigD(closure.Address()))
- vm.Printf(" => %x", closure.Address())
+ self.Printf(" => %x", closure.Address())
case BALANCE:
require(1)
addr := stack.Pop().Bytes()
- balance := vm.state.GetBalance(addr)
+ balance := self.env.State().GetBalance(addr)
stack.Push(balance)
- vm.Printf(" => %v (%x)", balance, addr)
+ self.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
- stack.Push(ethutil.BigD(vm.vars.Origin))
+ origin := self.env.Origin()
- vm.Printf(" => %x", vm.vars.Origin)
+ stack.Push(ethutil.BigD(origin))
+
+ self.Printf(" => %x", origin)
case CALLER:
caller := closure.caller.Address()
stack.Push(ethutil.BigD(caller))
- vm.Printf(" => %x", caller)
+ self.Printf(" => %x", caller)
case CALLVALUE:
- stack.Push(vm.vars.Value)
+ value := self.env.Value()
+
+ stack.Push(value)
- vm.Printf(" => %v", vm.vars.Value)
+ self.Printf(" => %v", value)
case CALLDATALOAD:
require(1)
- offset := stack.Pop().Int64()
+ var (
+ offset = stack.Pop()
+ data = make([]byte, 32)
+ lenData = big.NewInt(int64(len(closure.Args)))
+ )
- data := make([]byte, 32)
- if big.NewInt(int64(len(closure.Args))).Cmp(big.NewInt(offset)) >= 0 {
- l := int64(math.Min(float64(offset+32), float64(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:l])
+ copy(data, closure.Args[offset.Int64():length.Int64()])
}
- vm.Printf(" => 0x%x", data)
+ self.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)
+ self.Printf(" => %d", l)
case CALLDATACOPY:
var (
size = int64(len(closure.Args))
@@ -541,13 +504,13 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
mem.Set(mOff, l, code)
case CODESIZE:
- l := big.NewInt(int64(len(closure.Script)))
+ l := big.NewInt(int64(len(closure.Code)))
stack.Push(l)
- vm.Printf(" => %d", l)
+ self.Printf(" => %d", l)
case CODECOPY:
var (
- size = int64(len(closure.Script))
+ size = int64(len(closure.Code))
mOff = stack.Pop().Int64()
cOff = stack.Pop().Int64()
l = stack.Pop().Int64()
@@ -560,25 +523,45 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
l = 0
}
- code := closure.Script[cOff : cOff+l]
- //fmt.Println("len:", l, "code off:", cOff, "mem off:", mOff)
+ code := closure.Code[cOff : cOff+l]
mem.Set(mOff, l, code)
- //fmt.Println(Code(mem.Get(mOff, l)))
case GASPRICE:
stack.Push(closure.Price)
+ self.Printf(" => %v", closure.Price)
+
// 0x40 range
case PREVHASH:
- stack.Push(ethutil.BigD(vm.vars.PrevHash))
+ prevHash := self.env.PrevHash()
+
+ stack.Push(ethutil.BigD(prevHash))
+
+ self.Printf(" => 0x%x", prevHash)
case COINBASE:
- stack.Push(ethutil.BigD(vm.vars.Coinbase))
+ coinbase := self.env.Coinbase()
+
+ stack.Push(ethutil.BigD(coinbase))
+
+ self.Printf(" => 0x%x", coinbase)
case TIMESTAMP:
- stack.Push(big.NewInt(vm.vars.Time))
+ time := self.env.Time()
+
+ stack.Push(big.NewInt(time))
+
+ self.Printf(" => 0x%x", time)
case NUMBER:
- stack.Push(vm.vars.BlockNumber)
+ number := self.env.BlockNumber()
+
+ stack.Push(number)
+
+ self.Printf(" => 0x%x", number.Bytes())
case DIFFICULTY:
- stack.Push(vm.vars.Diff)
+ difficulty := self.env.Difficulty()
+
+ stack.Push(difficulty)
+
+ self.Printf(" => 0x%x", difficulty.Bytes())
case GASLIMIT:
// TODO
stack.Push(big.NewInt(0))
@@ -595,7 +578,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
step += int(op) - int(PUSH1) + 1
- vm.Printf(" => 0x%x", data.Bytes())
+ self.Printf(" => 0x%x", data.Bytes())
case POP:
require(1)
stack.Pop()
@@ -603,7 +586,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
require(1)
stack.Push(stack.Peek())
- vm.Printf(" => 0x%x", stack.Peek().Bytes())
+ self.Printf(" => 0x%x", stack.Peek().Bytes())
case SWAP:
require(2)
x, y := stack.Popn()
@@ -615,14 +598,14 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
val := ethutil.BigD(mem.Get(offset.Int64(), 32))
stack.Push(val)
- vm.Printf(" => 0x%x", val.Bytes())
+ self.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)
+ self.Printf(" => 0x%x", val)
case MSTORE8:
require(2)
val, mStart := stack.Popn()
@@ -630,7 +613,7 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
//mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256))
mem.store[mStart.Int64()] = byte(val.Int64() & 0xff)
- vm.Printf(" => 0x%x", val)
+ self.Printf(" => 0x%x", val)
case SLOAD:
require(1)
loc := stack.Pop()
@@ -638,21 +621,21 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
stack.Push(val.BigInt())
- vm.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
+ self.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)
+ self.env.State().Manifest().AddStorageChange(closure.Object(), loc.Bytes(), val)
- vm.Printf(" {0x%x : 0x%x}", loc, val)
+ self.Printf(" {0x%x : 0x%x}", loc.Bytes(), val.Bytes())
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()
+ self.Printf(" ~> %v", pc).Endl()
continue
case JUMPI:
@@ -661,11 +644,11 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
if cond.Cmp(ethutil.BigTrue) >= 0 {
pc = pos
- vm.Printf(" ~> %v (t)", pc).Endl()
+ self.Printf(" ~> %v (t)", pc).Endl()
continue
} else {
- vm.Printf(" (f)")
+ self.Printf(" (f)")
}
case PC:
stack.Push(pc)
@@ -684,20 +667,20 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
// Snapshot the current stack so we are able to
// revert back to it later.
- snapshot = vm.state.Copy()
+ snapshot = self.env.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)
+ addr := ethcrypto.CreateAddress(closure.Address(), closure.object.Nonce)
+ for i := uint64(0); self.env.State().GetStateObject(addr) != nil; i++ {
+ ethcrypto.CreateAddress(closure.Address(), closure.object.Nonce+i)
}
closure.object.Nonce++
- vm.Printf(" (*) %x", addr).Endl()
+ self.Printf(" (*) %x", addr).Endl()
// Create a new contract
- contract := vm.state.NewStateObject(addr)
+ contract := self.env.State().NewStateObject(addr)
if contract.Amount.Cmp(value) >= 0 {
closure.object.SubAmount(value)
contract.AddAmount(value)
@@ -711,10 +694,10 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
closure.UseGas(closure.Gas)
// Create the closure
- c := NewClosure(closure, contract, initCode, vm.state, gas, closure.Price)
+ c := NewClosure(closure, contract, initCode, gas, closure.Price)
// Call the closure and set the return value as
// main script.
- contract.script, err = Call(vm, c, nil)
+ contract.Code, _, err = c.Call(self, nil)
} else {
err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount)
}
@@ -723,23 +706,23 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
stack.Push(ethutil.BigFalse)
// Revert the state as it was before.
- vm.state.Set(snapshot)
+ self.env.State().Set(snapshot)
- vm.Printf("CREATE err %v", err)
+ self.Printf("CREATE err %v", err)
} else {
stack.Push(ethutil.BigD(addr))
- vm.Printf("CREATE success")
+ self.Printf("CREATE success")
}
- vm.Endl()
+ self.Endl()
// Debug hook
- if vm.Dbg != nil {
- vm.Dbg.SetCode(closure.Script)
+ if self.Dbg != nil {
+ self.Dbg.SetCode(closure.Code)
}
case CALL:
require(7)
- vm.Endl()
+ self.Endl()
gas := stack.Pop()
// Pop gas and value of the stack.
@@ -755,27 +738,27 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
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)
+ closure.ReturnGas(gas, nil)
stack.Push(ethutil.BigFalse)
} else {
- snapshot := vm.state.Copy()
+ snapshot := self.env.State().Copy()
- stateObject := vm.state.GetOrNewStateObject(addr.Bytes())
+ stateObject := self.env.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)
+ c := NewClosure(closure, stateObject, stateObject.Code, gas, closure.Price)
// Executer the closure and get the return value (if any)
- ret, err := Call(vm, c, args)
+ ret, _, err := c.Call(self, args)
if err != nil {
stack.Push(ethutil.BigFalse)
vmlogger.Debugf("Closure execution failed. %v\n", err)
- vm.state.Set(snapshot)
+ self.env.State().Set(snapshot)
} else {
stack.Push(ethutil.BigTrue)
@@ -783,8 +766,8 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
}
// Debug hook
- if vm.Dbg != nil {
- vm.Dbg.SetCode(closure.Script)
+ if self.Dbg != nil {
+ self.Dbg.SetCode(closure.Code)
}
}
case RETURN:
@@ -792,13 +775,13 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
size, offset := stack.Popn()
ret := mem.Get(offset.Int64(), size.Int64())
- vm.Printf(" => (%d) 0x%x", len(ret), ret).Endl()
+ self.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 := self.env.State().GetOrNewStateObject(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount)
@@ -806,30 +789,29 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
fallthrough
case STOP: // Stop the closure
- vm.Endl()
+ self.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()
+ self.Endl()
- if vm.Dbg != nil {
- for _, instrNo := range vm.Dbg.BreakPoints() {
+ if self.Dbg != nil {
+ for _, instrNo := range self.Dbg.BreakPoints() {
if pc.Cmp(big.NewInt(instrNo)) == 0 {
- vm.Stepping = true
+ self.Stepping = true
- if !vm.Dbg.BreakHook(prevStep, op, mem, stack, closure.Object()) {
+ if !self.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()) {
+ } else if self.Stepping {
+ if !self.Dbg.StepHook(prevStep, op, mem, stack, closure.Object()) {
return nil, nil
}
}
@@ -838,3 +820,20 @@ func (vm *Vm) RunClosure(closure *Closure) (ret []byte, err error) {
}
}
+
+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
+}
diff --git a/ethvm/vm_test.go b/ethvm/vm_test.go
new file mode 100644
index 000000000..501d0c284
--- /dev/null
+++ b/ethvm/vm_test.go
@@ -0,0 +1,45 @@
+package ethvm
+
+import (
+ "fmt"
+ "github.com/ethereum/eth-go/ethdb"
+ "github.com/ethereum/eth-go/ethlog"
+ "github.com/ethereum/eth-go/ethstate"
+ "github.com/ethereum/eth-go/ethutil"
+ "log"
+ "math/big"
+ "os"
+ "testing"
+)
+
+type TestEnv struct {
+}
+
+func (self TestEnv) Origin() []byte { return nil }
+func (self TestEnv) BlockNumber() *big.Int { return nil }
+func (self TestEnv) PrevHash() []byte { return nil }
+func (self TestEnv) Coinbase() []byte { return nil }
+func (self TestEnv) Time() int64 { return 0 }
+func (self TestEnv) Difficulty() *big.Int { return nil }
+func (self TestEnv) Value() *big.Int { return nil }
+func (self TestEnv) State() *ethstate.State { return nil }
+
+func TestVm(t *testing.T) {
+ ethlog.AddLogSystem(ethlog.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlog.LogLevel(4)))
+
+ db, _ := ethdb.NewMemDatabase()
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
+ ethutil.Config.Db = db
+
+ stateObject := ethstate.NewStateObject([]byte{'j', 'e', 'f', 'f'})
+ callerClosure := NewClosure(stateObject, stateObject, []byte{0x60, 0x01}, big.NewInt(1000000), big.NewInt(0))
+
+ vm := New(TestEnv{})
+ vm.Verbose = true
+
+ ret, _, e := callerClosure.Call(vm, nil)
+ if e != nil {
+ fmt.Println("error", e)
+ }
+ fmt.Println(ret)
+}
diff --git a/peer.go b/peer.go
index 89032364e..ffba695ca 100644
--- a/peer.go
+++ b/peer.go
@@ -121,10 +121,8 @@ type Peer struct {
versionKnown bool
// Last received pong message
- lastPong int64
- // Indicates whether a MsgGetPeersTy was requested of the peer
- // this to prevent receiving false peers.
- requestedPeerList bool
+ lastPong int64
+ lastBlockReceived time.Time
host []byte
port uint16
@@ -180,10 +178,9 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
// Set up the connection in another goroutine so we don't block the main thread
go func() {
- conn, err := net.DialTimeout("tcp", addr, 10*time.Second)
-
+ conn, err := p.Connect(addr)
if err != nil {
- peerlogger.Debugln("Connection to peer failed", err)
+ peerlogger.Debugln("Connection to peer failed. Giving up.", err)
p.Stop()
return
}
@@ -199,6 +196,21 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
return p
}
+func (self *Peer) Connect(addr string) (conn net.Conn, err error) {
+ for attempts := 0; attempts < 5; attempts++ {
+ conn, err = net.DialTimeout("tcp", addr, 10*time.Second)
+ if err != nil {
+ peerlogger.Debugf("Peer connection failed. Retrying (%d/5)\n", attempts+1)
+ continue
+ }
+
+ // Success
+ return
+ }
+
+ return
+}
+
// Getters
func (p *Peer) PingTime() string {
return p.pingTime.String()
@@ -397,10 +409,7 @@ func (p *Peer) HandleInbound() {
for i := msg.Data.Len() - 1; i >= 0; i-- {
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
- //p.ethereum.StateManager().PrepareDefault(block)
- //state := p.ethereum.StateManager().CurrentState()
err = p.ethereum.StateManager().Process(block, false)
-
if err != nil {
if ethutil.Config.Debug {
peerlogger.Infof("Block %x failed\n", block.Hash())
@@ -411,6 +420,8 @@ func (p *Peer) HandleInbound() {
} else {
lastBlock = block
}
+
+ p.lastBlockReceived = time.Now()
}
if msg.Data.Len() <= 1 {
@@ -463,30 +474,21 @@ func (p *Peer) HandleInbound() {
p.ethereum.TxPool().QueueTransaction(tx)
}
case ethwire.MsgGetPeersTy:
- // Flag this peer as a 'requested of new peers' this to
- // prevent malicious peers being forced.
- p.requestedPeerList = true
// Peer asked for list of connected peers
p.pushPeers()
case ethwire.MsgPeersTy:
// Received a list of peers (probably because MsgGetPeersTy was send)
- // Only act on message if we actually requested for a peers list
- if p.requestedPeerList {
- data := msg.Data
- // Create new list of possible peers for the ethereum to process
- peers := make([]string, data.Len())
- // Parse each possible peer
- for i := 0; i < data.Len(); i++ {
- 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
-
+ data := msg.Data
+ // Create new list of possible peers for the ethereum to process
+ peers := make([]string, data.Len())
+ // Parse each possible peer
+ for i := 0; i < data.Len(); i++ {
+ value := data.Get(i)
+ peers[i] = unpackAddr(value.Get(0), value.Get(1).Uint())
}
+
+ // Connect to the list of peers
+ p.ethereum.ProcessPeerList(peers)
case ethwire.MsgGetChainTy:
var parent *ethchain.Block
// Length minus one since the very last element in the array is a count
@@ -559,6 +561,25 @@ func (p *Peer) HandleInbound() {
p.Stop()
}
+// General update method
+func (self *Peer) update() {
+ serviceTimer := time.NewTicker(5 * time.Second)
+
+out:
+ for {
+ select {
+ case <-serviceTimer.C:
+ if time.Since(self.lastBlockReceived) > 10*time.Second {
+ self.catchingUp = false
+ }
+ case <-self.quit:
+ break out
+ }
+ }
+
+ serviceTimer.Stop()
+}
+
func (p *Peer) Start() {
peerHost, peerPort, _ := net.SplitHostPort(p.conn.LocalAddr().String())
servHost, servPort, _ := net.SplitHostPort(p.conn.RemoteAddr().String())
@@ -581,6 +602,8 @@ func (p *Peer) Start() {
go p.HandleOutbound()
// Run the inbound handler in a new goroutine
go p.HandleInbound()
+ // Run the general update handler
+ go p.update()
// Wait a few seconds for startup and then ask for an initial ping
time.Sleep(2 * time.Second)
@@ -698,11 +721,13 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
ethlogger.Infof("Added peer (%s) %d / %d\n", p.conn.RemoteAddr(), p.ethereum.Peers().Len(), p.ethereum.MaxPeers)
- // Catch up with the connected peer
- if !p.ethereum.IsUpToDate() {
- peerlogger.Debugln("Already syncing up with a peer; sleeping")
- time.Sleep(10 * time.Second)
- }
+ /*
+ // Catch up with the connected peer
+ if !p.ethereum.IsUpToDate() {
+ peerlogger.Debugln("Already syncing up with a peer; sleeping")
+ time.Sleep(10 * time.Second)
+ }
+ */
p.SyncWithPeerToLastKnown()
peerlogger.Debugln(p)