Commit 702cf5a3 authored by obscuren's avatar obscuren

Merge branch 'feature/refactor_vm' into develop

parents 92b16618 dcf4fad9
...@@ -6,7 +6,7 @@ Ethereum ...@@ -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.
......
...@@ -25,7 +25,7 @@ func Disassemble(script []byte) (asm []string) { ...@@ -25,7 +25,7 @@ func Disassemble(script []byte) (asm []string) {
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
a := int64(op) - int64(PUSH1) + 1 a := int64(op) - int64(PUSH1) + 1
if int(pc.Int64()+a) > len(script) { if int(pc.Int64()+a) > len(script) {
return nil return
} }
data := script[pc.Int64() : pc.Int64()+a] data := script[pc.Int64() : pc.Int64()+a]
...@@ -40,5 +40,5 @@ func Disassemble(script []byte) (asm []string) { ...@@ -40,5 +40,5 @@ func Disassemble(script []byte) (asm []string) {
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
} }
return return asm
} }
...@@ -4,6 +4,7 @@ import ( ...@@ -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 { ...@@ -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{}, ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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{} { ...@@ -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 { ...@@ -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,
......
...@@ -44,7 +44,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { ...@@ -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() { ...@@ -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)
......
...@@ -6,7 +6,7 @@ import ( ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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
...@@ -123,9 +120,9 @@ done: ...@@ -123,9 +120,9 @@ done:
cb := state.GetStateObject(coinbase.Address()) cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block) st := NewStateTransition(cb, tx, state, block)
//fmt.Printf("#%d\n", i+1)
err = st.TransitionState() err = st.TransitionState()
if err != nil { if err != nil {
statelogger.Infoln(err)
switch { switch {
case IsNonceErr(err): case IsNonceErr(err):
err = nil // ignore error err = nil // ignore error
...@@ -225,7 +222,7 @@ func (sm *StateManager) Process(block *Block, dontReact bool) (err error) { ...@@ -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) { ...@@ -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) { ...@@ -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 { ...@@ -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() { ...@@ -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})
} }
} }
} }
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)
}
...@@ -2,6 +2,10 @@ package ethchain ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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,35 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error ...@@ -248,34 +252,35 @@ 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)
return return
} }
func Call(vm *Vm, closure *Closure, data []byte) (ret []byte, err error) { // Converts an transaction in to a state object
ret, _, err = closure.Call(vm, data) 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
} }
...@@ -5,6 +5,7 @@ import ( ...@@ -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 { ...@@ -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())
......
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 }
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)
}
...@@ -6,6 +6,7 @@ import ( ...@@ -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 { ...@@ -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 {
...@@ -48,6 +49,12 @@ type PEthereum struct { ...@@ -48,6 +49,12 @@ type PEthereum struct {
} }
func NewPEthereum(manager ethchain.EthManager) *PEthereum { 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{ return &PEthereum{
manager, manager,
manager.StateManager(), manager.StateManager(),
......
...@@ -5,6 +5,7 @@ import ( ...@@ -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) * ...@@ -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 { ...@@ -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 { ...@@ -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{} { ...@@ -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 { ...@@ -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 { ...@@ -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()}
} }
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}
}
package ethchain package ethstate
import ( import (
"github.com/ethereum/eth-go/ethcrypto" "github.com/ethereum/eth-go/ethcrypto"
"github.com/ethereum/eth-go/ethlog"
"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"
) )
var statelogger = ethlog.NewLogger("STATE")
// States within the ethereum protocol are used to store anything // States within the ethereum protocol are used to store anything
// within the merkle trie. States take care of caching and storing // within the merkle trie. States take care of caching and storing
// nested states. It's the general query interface to retrieve: // nested states. It's the general query interface to retrieve:
...@@ -14,7 +17,7 @@ import ( ...@@ -14,7 +17,7 @@ import (
// * 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
...@@ -23,7 +26,7 @@ type State struct { ...@@ -23,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
...@@ -53,16 +56,16 @@ func (self *State) GetNonce(addr []byte) uint64 { ...@@ -53,16 +56,16 @@ func (self *State) GetNonce(addr []byte) uint64 {
func (self *State) UpdateStateObject(stateObject *StateObject) { func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address() 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) 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()))
} }
...@@ -76,7 +79,7 @@ func (self *State) GetStateObject(addr []byte) *StateObject { ...@@ -76,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
} }
...@@ -99,6 +102,8 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject { ...@@ -99,6 +102,8 @@ func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
// Create a state object whether it exist in the trie or not // Create a state object whether it exist in the trie or not
func (self *State) NewStateObject(addr []byte) *StateObject { func (self *State) NewStateObject(addr []byte) *StateObject {
addr = ethutil.Address(addr)
statelogger.Infof("(+) %x\n", addr) statelogger.Infof("(+) %x\n", addr)
stateObject := NewStateObject(addr) stateObject := NewStateObject(addr)
...@@ -117,12 +122,12 @@ func (self *State) GetAccount(addr []byte) *StateObject { ...@@ -117,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()
} }
...@@ -138,21 +143,21 @@ func (self *State) Set(state *State) { ...@@ -138,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
} }
...@@ -169,14 +174,14 @@ func (s *State) Sync() { ...@@ -169,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()
} }
...@@ -197,11 +202,11 @@ func (self *State) Update() { ...@@ -197,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
} }
} }
...@@ -212,6 +217,10 @@ func (self *State) CreateOutputForDiff() { ...@@ -212,6 +217,10 @@ func (self *State) CreateOutputForDiff() {
} }
} }
func (self *State) Manifest() *Manifest {
return self.manifest
}
// Object manifest // Object manifest
// //
// The object manifest is used to keep changes to the state so we can keep track of the changes // The object manifest is used to keep changes to the state so we can keep track of the changes
...@@ -221,8 +230,8 @@ type Manifest struct { ...@@ -221,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 {
...@@ -233,18 +242,18 @@ func NewManifest() *Manifest { ...@@ -233,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
} }
package ethchain package ethstate
import ( import (
"fmt" "fmt"
...@@ -6,13 +6,12 @@ import ( ...@@ -6,13 +6,12 @@ import (
"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"
"strings"
) )
type Code []byte type Code []byte
func (self Code) String() string { func (self Code) String() string {
return strings.Join(Disassemble(self), " ") return string(self) //strings.Join(Disassemble(self), " ")
} }
type Storage map[string]*ethutil.Value type Storage map[string]*ethutil.Value
...@@ -31,13 +30,13 @@ type StateObject struct { ...@@ -31,13 +30,13 @@ type StateObject struct {
// Address of the object // Address of the object
address []byte address []byte
// Shared attributes // Shared attributes
Amount *big.Int Amount *big.Int
ScriptHash []byte CodeHash []byte
Nonce uint64 Nonce uint64
// Contract related attributes // Contract related attributes
state *State State *State
script Code Code Code
initScript Code InitCode Code
storage Storage storage Storage
...@@ -54,9 +53,10 @@ type StateObject struct { ...@@ -54,9 +53,10 @@ 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()
} }
/*
// Converts an transaction in to a state object // Converts an transaction in to a state object
func MakeContract(tx *Transaction, state *State) *StateObject { func MakeContract(tx *Transaction, state *State) *StateObject {
// Create contract if there's no recipient // Create contract if there's no recipient
...@@ -64,7 +64,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { ...@@ -64,7 +64,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
addr := tx.CreationAddress() addr := tx.CreationAddress()
contract := state.NewStateObject(addr) contract := state.NewStateObject(addr)
contract.initScript = tx.Data contract.initCode = tx.Data
contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, "")) contract.state = NewState(ethtrie.NewTrie(ethutil.Config.Db, ""))
return contract return contract
...@@ -72,13 +72,14 @@ func MakeContract(tx *Transaction, state *State) *StateObject { ...@@ -72,13 +72,14 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
return nil return nil
} }
*/
func NewStateObject(addr []byte) *StateObject { 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. // This to ensure that it has 20 bytes (and not 0 bytes), thus left or right pad doesn't matter.
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)
...@@ -88,7 +89,7 @@ func NewStateObject(addr []byte) *StateObject { ...@@ -88,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
} }
...@@ -106,11 +107,11 @@ func (self *StateObject) MarkForDeletion() { ...@@ -106,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 {
...@@ -140,15 +141,6 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value { ...@@ -140,15 +141,6 @@ func (self *StateObject) getStorage(k []byte) *ethutil.Value {
func (self *StateObject) setStorage(k []byte, value *ethutil.Value) { func (self *StateObject) setStorage(k []byte, value *ethutil.Value) {
key := ethutil.LeftPadBytes(k, 32) key := ethutil.LeftPadBytes(k, 32)
self.storage[string(key)] = value.Copy() 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 // Iterate over each storage address and yield callback
...@@ -160,7 +152,7 @@ func (self *StateObject) EachStorage(cb ethtrie.EachCallback) { ...@@ -160,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 {
...@@ -170,47 +162,31 @@ func (self *StateObject) EachStorage(cb ethtrie.EachCallback) { ...@@ -170,47 +162,31 @@ func (self *StateObject) EachStorage(cb ethtrie.EachCallback) {
} }
func (self *StateObject) Sync() { 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 { for key, value := range self.storage {
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
} }
/*
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 { 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.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) { func (c *StateObject) AddAmount(amount *big.Int) {
...@@ -234,7 +210,7 @@ func (c *StateObject) SetAmount(amount *big.Int) { ...@@ -234,7 +210,7 @@ func (c *StateObject) SetAmount(amount *big.Int) {
// //
// Return the gas back to the origin. Used by the Virtual machine or Closures // 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 { func (c *StateObject) ConvertGas(gas, price *big.Int) error {
total := new(big.Int).Mul(gas, price) total := new(big.Int).Mul(gas, price)
if total.Cmp(c.Amount) > 0 { if total.Cmp(c.Amount) > 0 {
...@@ -277,13 +253,13 @@ func (self *StateObject) RefundGas(gas, price *big.Int) { ...@@ -277,13 +253,13 @@ func (self *StateObject) RefundGas(gas, price *big.Int) {
func (self *StateObject) Copy() *StateObject { func (self *StateObject) Copy() *StateObject {
stateObject := NewStateObject(self.Address()) stateObject := NewStateObject(self.Address())
stateObject.Amount.Set(self.Amount) stateObject.Amount.Set(self.Amount)
stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash) 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.script = ethutil.CopyBytes(self.script) stateObject.Code = ethutil.CopyBytes(self.Code)
stateObject.initScript = ethutil.CopyBytes(self.initScript) 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)
...@@ -298,10 +274,6 @@ func (self *StateObject) Set(stateObject *StateObject) { ...@@ -298,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))
} }
...@@ -311,19 +283,14 @@ func (c *StateObject) Address() []byte { ...@@ -311,19 +283,14 @@ func (c *StateObject) Address() []byte {
return c.address return c.address
} }
// Returns the main script body // Returns the initialization Code
func (c *StateObject) Script() Code {
return c.script
}
// Returns the initialization script
func (c *StateObject) Init() Code { func (c *StateObject) Init() Code {
return c.initScript 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())
}) })
...@@ -336,13 +303,13 @@ func (self *StateObject) CreateOutputForDiff() { ...@@ -336,13 +303,13 @@ 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 = ""
} }
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) { func (c *StateObject) RlpDecode(data []byte) {
...@@ -350,13 +317,13 @@ func (c *StateObject) RlpDecode(data []byte) { ...@@ -350,13 +317,13 @@ 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)
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 // Storage change object. Used by the manifest for notifying changes to
......
package ethchain package ethstate
import ( import (
"github.com/ethereum/eth-go/ethdb" "github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethtrie"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"testing" "testing"
) )
func TestSnapshot(t *testing.T) { var ZeroHash256 = make([]byte, 32)
ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "", "ETH")
func TestSnapshot(t *testing.T) {
db, _ := ethdb.NewMemDatabase() 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)) stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42))
snapshot := state.Copy() snapshot := state.Copy()
...@@ -24,7 +28,8 @@ func TestSnapshot(t *testing.T) { ...@@ -24,7 +28,8 @@ func TestSnapshot(t *testing.T) {
state.Set(snapshot) state.Set(snapshot)
stateObject = state.GetStateObject([]byte("aa")) stateObject = state.GetStateObject([]byte("aa"))
if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { res := stateObject.GetStorage(ethutil.Big("0"))
t.Error("Expected storage 0 to be 42") if !res.Cmp(ethutil.NewValue(42)) {
t.Error("Expected storage 0 to be 42", res)
} }
} }
...@@ -68,6 +68,8 @@ func (val *Value) Uint() uint64 { ...@@ -68,6 +68,8 @@ func (val *Value) Uint() uint64 {
return uint64(Val) return uint64(Val)
} else if Val, ok := val.Val.([]byte); ok { } else if Val, ok := val.Val.([]byte); ok {
return ReadVarint(bytes.NewReader(Val)) return ReadVarint(bytes.NewReader(Val))
} else if Val, ok := val.Val.(*big.Int); ok {
return Val.Uint64()
} }
return 0 return 0
......
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
}
package ethchain package ethvm
// TODO Re write VM to use values instead of big integers? // TODO Re write VM to use values instead of big integers?
import ( import (
"github.com/ethereum/eth-go/ethstate"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
) )
type ClosureRef interface { type ClosureRef interface {
ReturnGas(*big.Int, *big.Int, *State) ReturnGas(*big.Int, *big.Int)
Address() []byte Address() []byte
GetStorage(*big.Int) *ethutil.Value GetStorage(*big.Int) *ethutil.Value
SetStorage(*big.Int, *ethutil.Value) SetStorage(*big.Int, *ethutil.Value)
N() *big.Int
} }
// Basic inline closure object which implement the 'closure' interface // Basic inline closure object which implement the 'closure' interface
type Closure struct { type Closure struct {
caller ClosureRef caller ClosureRef
object *StateObject object *ethstate.StateObject
Script []byte Code []byte
State *State
Gas, UsedGas, Price *big.Int Gas, UsedGas, Price *big.Int
...@@ -28,8 +27,8 @@ type Closure struct { ...@@ -28,8 +27,8 @@ type Closure struct {
} }
// Create a new closure for the given data items // Create a new closure for the given data items
func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { func NewClosure(caller ClosureRef, object *ethstate.StateObject, code []byte, gas, price *big.Int) *Closure {
c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil} c := &Closure{caller: caller, object: object, Code: code, Args: nil}
// Gas should be a pointer so it can safely be reduced through the run // Gas should be a pointer so it can safely be reduced through the run
// This pointer will be off the state transition // This pointer will be off the state transition
...@@ -57,11 +56,11 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value { ...@@ -57,11 +56,11 @@ func (c *Closure) Get(x *big.Int) *ethutil.Value {
} }
func (c *Closure) Gets(x, y *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) 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) return ethutil.NewValue(partial)
} }
...@@ -84,7 +83,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) { ...@@ -84,7 +83,7 @@ func (c *Closure) Call(vm *Vm, args []byte) ([]byte, *big.Int, error) {
func (c *Closure) Return(ret []byte) []byte { func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the caller // 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 return ret
} }
...@@ -102,20 +101,16 @@ func (c *Closure) UseGas(gas *big.Int) bool { ...@@ -102,20 +101,16 @@ func (c *Closure) UseGas(gas *big.Int) bool {
} }
// Implement the caller interface // 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 // Return the gas to the closure
c.Gas.Add(c.Gas, gas) c.Gas.Add(c.Gas, gas)
c.UsedGas.Sub(c.UsedGas, gas) c.UsedGas.Sub(c.UsedGas, gas)
} }
func (c *Closure) Object() *StateObject { func (c *Closure) Object() *ethstate.StateObject {
return c.object return c.object
} }
func (c *Closure) Caller() ClosureRef { func (c *Closure) Caller() ClosureRef {
return c.caller return c.caller
} }
func (c *Closure) N() *big.Int {
return c.object.N()
}
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
)
package ethchain package ethvm
import ( import (
"fmt" "fmt"
......
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
}
This diff is collapsed.
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)
}
...@@ -122,9 +122,6 @@ type Peer struct { ...@@ -122,9 +122,6 @@ type Peer struct {
// Last received pong message // Last received pong message
lastPong int64 lastPong int64
// Indicates whether a MsgGetPeersTy was requested of the peer
// this to prevent receiving false peers.
requestedPeerList bool
host []byte host []byte
port uint16 port uint16
...@@ -180,10 +177,9 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { ...@@ -180,10 +177,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 // Set up the connection in another goroutine so we don't block the main thread
go func() { go func() {
conn, err := net.DialTimeout("tcp", addr, 10*time.Second) conn, err := p.Connect(addr)
if err != nil { if err != nil {
peerlogger.Debugln("Connection to peer failed", err) peerlogger.Debugln("Connection to peer failed. Giving up.", err)
p.Stop() p.Stop()
return return
} }
...@@ -199,6 +195,21 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer { ...@@ -199,6 +195,21 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
return p 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 // Getters
func (p *Peer) PingTime() string { func (p *Peer) PingTime() string {
return p.pingTime.String() return p.pingTime.String()
...@@ -463,30 +474,21 @@ func (p *Peer) HandleInbound() { ...@@ -463,30 +474,21 @@ func (p *Peer) HandleInbound() {
p.ethereum.TxPool().QueueTransaction(tx) p.ethereum.TxPool().QueueTransaction(tx)
} }
case ethwire.MsgGetPeersTy: 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 // Peer asked for list of connected peers
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)
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
...@@ -698,11 +700,13 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) { ...@@ -698,11 +700,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) 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() { // Catch up with the connected peer
peerlogger.Debugln("Already syncing up with a peer; sleeping") if !p.ethereum.IsUpToDate() {
time.Sleep(10 * time.Second) peerlogger.Debugln("Already syncing up with a peer; sleeping")
} time.Sleep(10 * time.Second)
}
*/
p.SyncWithPeerToLastKnown() p.SyncWithPeerToLastKnown()
peerlogger.Debugln(p) peerlogger.Debugln(p)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment