Merge branch 'release/poc5-rc2'

This commit is contained in:
obscuren 2014-05-10 02:04:06 +02:00
commit 3af35d922e
15 changed files with 301 additions and 362 deletions

View File

@ -21,9 +21,10 @@ func Disassemble(script []byte) (asm []string) {
asm = append(asm, fmt.Sprintf("%v", op)) asm = append(asm, fmt.Sprintf("%v", op))
switch op { switch op {
case oPUSH: // Push PC+1 on to the stack case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32:
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+32] a := int64(op) - int64(oPUSH1) + 1
data := script[pc.Int64() : pc.Int64()+a]
val := ethutil.BigD(data) val := ethutil.BigD(data)
var b []byte var b []byte
@ -35,21 +36,7 @@ func Disassemble(script []byte) (asm []string) {
asm = append(asm, fmt.Sprintf("0x%x", b)) asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31)) pc.Add(pc, big.NewInt(a-1))
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := script[pc.Int64() : pc.Int64()+20]
val := ethutil.BigD(data)
var b []byte
if val.Int64() == 0 {
b = []byte{0}
} else {
b = val.Bytes()
}
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(19))
} }
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)

View File

@ -11,7 +11,7 @@ type ClosureRef interface {
ReturnGas(*big.Int, *big.Int, *State) ReturnGas(*big.Int, *big.Int, *State)
Address() []byte Address() []byte
GetMem(*big.Int) *ethutil.Value GetMem(*big.Int) *ethutil.Value
SetMem(*big.Int, *ethutil.Value) SetStore(*big.Int, *ethutil.Value)
N() *big.Int N() *big.Int
} }
@ -24,20 +24,18 @@ type Closure struct {
Gas *big.Int Gas *big.Int
Price *big.Int Price *big.Int
Value *big.Int
Args []byte Args []byte
} }
// Create a new closure for the given data items // Create a new closure for the given data items
func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price, val *big.Int) *Closure { func NewClosure(callee, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure {
c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil}
// In most cases gas, price and value are pointers to transaction objects // In most cases gas, price and value are pointers to transaction objects
// and we don't want the transaction's values to change. // and we don't want the transaction's values to change.
c.Gas = new(big.Int).Set(gas) c.Gas = new(big.Int).Set(gas)
c.Price = new(big.Int).Set(price) c.Price = new(big.Int).Set(price)
c.Value = new(big.Int).Set(val)
return c return c
} }
@ -66,8 +64,8 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
return ethutil.NewValue(partial) return ethutil.NewValue(partial)
} }
func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) { func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) {
c.object.SetMem(x, val) c.object.SetStorage(x, val)
} }
func (c *Closure) Address() []byte { func (c *Closure) Address() []byte {

View File

@ -15,11 +15,13 @@ type State struct {
trie *ethutil.Trie trie *ethutil.Trie
// Nested states // Nested states
states map[string]*State states map[string]*State
manifest *Manifest
} }
// Create a new state from a given trie // Create a new state from a given trie
func NewState(trie *ethutil.Trie) *State { func NewState(trie *ethutil.Trie) *State {
return &State{trie: trie, states: make(map[string]*State)} return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()}
} }
// Resets the trie and all siblings // Resets the trie and all siblings
@ -114,46 +116,6 @@ func (s *State) Copy() *State {
return NewState(s.trie.Copy()) return NewState(s.trie.Copy())
} }
type ObjType byte
const (
NilTy ObjType = iota
AccountTy
ContractTy
UnknownTy
)
/*
// Returns the object stored at key and the type stored at key
// Returns nil if nothing is stored
func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) {
// Fetch data from the trie
data := s.trie.Get(string(key))
// Returns the nil type, indicating nothing could be retrieved.
// Anything using this function should check for this ret val
if data == "" {
return nil, NilTy
}
var typ ObjType
val := ethutil.NewValueFromBytes([]byte(data))
// Check the length of the retrieved value.
// Len 2 = Account
// Len 3 = Contract
// Other = invalid for now. If other types emerge, add them here
if val.Len() == 2 {
typ = AccountTy
} else if val.Len() == 3 {
typ = ContractTy
} else {
typ = UnknownTy
}
return val, typ
}
*/
// Updates any given state object // Updates any given state object
func (s *State) UpdateStateObject(object *StateObject) { func (s *State) UpdateStateObject(object *StateObject) {
addr := object.Address() addr := object.Address()
@ -163,6 +125,7 @@ func (s *State) UpdateStateObject(object *StateObject) {
} }
s.trie.Update(string(addr), string(object.RlpEncode())) s.trie.Update(string(addr), string(object.RlpEncode()))
s.manifest.AddObjectChange(object)
} }
func (s *State) Put(key, object []byte) { func (s *State) Put(key, object []byte) {
@ -172,3 +135,40 @@ func (s *State) Put(key, object []byte) {
func (s *State) Root() interface{} { func (s *State) Root() interface{} {
return s.trie.Root return s.trie.Root
} }
// Object manifest
//
// The object manifest is used to keep changes to the state so we can keep track of the changes
// that occurred during a state transitioning phase.
type Manifest struct {
// XXX These will be handy in the future. Not important for now.
objectAddresses map[string]bool
storageAddresses map[string]map[string]bool
objectChanges map[string]*StateObject
storageChanges map[string]map[string]*big.Int
}
func NewManifest() *Manifest {
m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)}
m.Reset()
return m
}
func (m *Manifest) Reset() {
m.objectChanges = make(map[string]*StateObject)
m.storageChanges = make(map[string]map[string]*big.Int)
}
func (m *Manifest) AddObjectChange(stateObject *StateObject) {
m.objectChanges[string(stateObject.Address())] = stateObject
}
func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) {
if m.storageChanges[string(stateObject.Address())] == nil {
m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int)
}
m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage
}

View File

@ -25,24 +25,16 @@ type EthManager interface {
type StateManager struct { type StateManager struct {
// Mutex for locking the block processor. Blocks can only be handled one at a time // Mutex for locking the block processor. Blocks can only be handled one at a time
mutex sync.Mutex mutex sync.Mutex
// Canonical block chain // Canonical block chain
bc *BlockChain bc *BlockChain
// States for addresses. You can watch any address
// at any given time
stateObjectCache *StateObjectCache
// Stack for processing contracts // Stack for processing contracts
stack *Stack 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
Pow PoW Pow PoW
// The ethereum manager interface
Ethereum EthManager Ethereum EthManager
SecondaryBlockProcessor BlockProcessor
// The managed states // The managed states
// Processor state. Anything processed will be applied to this // Processor state. Anything processed will be applied to this
// state // state
@ -50,8 +42,14 @@ type StateManager struct {
// Comparative state it used for comparing and validating end // Comparative state it used for comparing and validating end
// results // results
compState *State compState *State
// Transiently state. The trans state isn't ever saved, validated and
manifest *Manifest // it could be used for setting account nonces without effecting
// the main states.
transState *State
// Manifest for keeping changes regarding state objects. See `notify`
// XXX Should we move the manifest to the State object. Benefit:
// * All states can keep their own local changes
//manifest *Manifest
} }
func NewStateManager(ethereum EthManager) *StateManager { func NewStateManager(ethereum EthManager) *StateManager {
@ -60,11 +58,12 @@ func NewStateManager(ethereum EthManager) *StateManager {
mem: make(map[string]*big.Int), mem: make(map[string]*big.Int),
Pow: &EasyPow{}, Pow: &EasyPow{},
Ethereum: ethereum, Ethereum: ethereum,
stateObjectCache: NewStateObjectCache(),
bc: ethereum.BlockChain(), bc: ethereum.BlockChain(),
manifest: NewManifest(), //manifest: NewManifest(),
} }
sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.procState = ethereum.BlockChain().CurrentBlock.State()
sm.transState = sm.procState.Copy()
return sm return sm
} }
@ -72,22 +71,8 @@ func (sm *StateManager) ProcState() *State {
return sm.procState return sm.procState
} }
// Watches any given address and puts it in the address state store func (sm *StateManager) TransState() *State {
func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject { return sm.transState
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
account := sm.procState.GetAccount(addr)
return sm.stateObjectCache.Add(addr, account)
}
func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject {
account := sm.stateObjectCache.Get(addr)
if account == nil {
a := sm.procState.GetAccount(addr)
account = &CachedStateObject{Nonce: a.Nonce, Object: a}
}
return account
} }
func (sm *StateManager) BlockChain() *BlockChain { func (sm *StateManager) BlockChain() *BlockChain {
@ -201,19 +186,13 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// Add the block to the chain // Add the block to the chain
sm.bc.Add(block) sm.bc.Add(block)
// If there's a block processor present, pass in the block for further
// processing
if sm.SecondaryBlockProcessor != nil {
sm.SecondaryBlockProcessor.ProcessBlock(block)
}
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
if dontReact == false { if dontReact == false {
sm.Ethereum.Reactor().Post("newBlock", block) sm.Ethereum.Reactor().Post("newBlock", block)
sm.notifyChanges() sm.notifyChanges()
sm.manifest.Reset() sm.procState.manifest.Reset()
} }
} else { } else {
fmt.Println("total diff failed") fmt.Println("total diff failed")
@ -323,7 +302,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
return return
} }
closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice, tx.Value) closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice)
vm := NewVm(sm.procState, sm, RuntimeVars{ vm := NewVm(sm.procState, sm, RuntimeVars{
Origin: account.Address(), Origin: account.Address(),
BlockNumber: block.BlockInfo().Number, BlockNumber: block.BlockInfo().Number,
@ -331,59 +310,24 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
Coinbase: block.Coinbase, Coinbase: block.Coinbase,
Time: block.Time, Time: block.Time,
Diff: block.Difficulty, Diff: block.Difficulty,
Value: tx.Value,
//Price: tx.GasPrice, //Price: tx.GasPrice,
}) })
closure.Call(vm, tx.Data, nil) closure.Call(vm, tx.Data, nil)
// Update the account (refunds) // Update the account (refunds)
sm.procState.UpdateStateObject(account) sm.procState.UpdateStateObject(account)
sm.manifest.AddObjectChange(account)
sm.procState.UpdateStateObject(object) sm.procState.UpdateStateObject(object)
sm.manifest.AddObjectChange(object)
} }
func (sm *StateManager) notifyChanges() { func (sm *StateManager) notifyChanges() {
for addr, stateObject := range sm.manifest.objectChanges { for addr, stateObject := range sm.procState.manifest.objectChanges {
sm.Ethereum.Reactor().Post("object:"+addr, stateObject) sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
} }
for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges { for stateObjectAddr, mappedObjects := range sm.procState.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, &StorageState{[]byte(stateObjectAddr), []byte(addr), value})
} }
} }
} }
type Manifest struct {
// XXX These will be handy in the future. Not important for now.
objectAddresses map[string]bool
storageAddresses map[string]map[string]bool
objectChanges map[string]*StateObject
storageChanges map[string]map[string]*big.Int
}
func NewManifest() *Manifest {
m := &Manifest{objectAddresses: make(map[string]bool), storageAddresses: make(map[string]map[string]bool)}
m.Reset()
return m
}
func (m *Manifest) Reset() {
m.objectChanges = make(map[string]*StateObject)
m.storageChanges = make(map[string]map[string]*big.Int)
}
func (m *Manifest) AddObjectChange(stateObject *StateObject) {
m.objectChanges[string(stateObject.Address())] = stateObject
}
func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte, storage *big.Int) {
if m.storageChanges[string(stateObject.Address())] == nil {
m.storageChanges[string(stateObject.Address())] = make(map[string]*big.Int)
}
m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage
}

View File

@ -77,7 +77,7 @@ 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 (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) {
addr := ethutil.BigToBytes(num, 256) addr := ethutil.BigToBytes(num, 256)
c.SetAddr(addr, val) c.SetAddr(addr, val)
} }
@ -160,33 +160,8 @@ func (c *StateObject) RlpDecode(data []byte) {
c.script = decoder.Get(3).Bytes() c.script = decoder.Get(3).Bytes()
} }
// The cached state and state object cache are helpers which will give you somewhat // Storage change object. Used by the manifest for notifying changes to
// control over the nonce. When creating new transactions you're interested in the 'next' // the sub channels.
// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions.
type StateObjectCache struct {
cachedObjects map[string]*CachedStateObject
}
func NewStateObjectCache() *StateObjectCache {
return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)}
}
func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject {
state := &CachedStateObject{Nonce: object.Nonce, Object: object}
s.cachedObjects[string(addr)] = state
return state
}
func (s *StateObjectCache) Get(addr []byte) *CachedStateObject {
return s.cachedObjects[string(addr)]
}
type CachedStateObject struct {
Nonce uint64
Object *StateObject
}
type StorageState struct { type StorageState struct {
StateAddress []byte StateAddress []byte
Address []byte Address []byte

View File

@ -148,8 +148,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
} }
// Get the sender // Get the sender
accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender()) sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender())
sender := accountState.Object
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
// Make sure there's enough in the sender's account. Having insufficient // Make sure there's enough in the sender's account. Having insufficient

View File

@ -48,8 +48,6 @@ const (
oGASLIMIT = 0x45 oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution // 0x50 range - 'storage' and execution
oPUSH = 0x50
oPUSH20 = 0x80
oPOP = 0x51 oPOP = 0x51
oDUP = 0x52 oDUP = 0x52
oSWAP = 0x53 oSWAP = 0x53
@ -63,14 +61,48 @@ const (
oPC = 0x5b oPC = 0x5b
oMSIZE = 0x5c oMSIZE = 0x5c
// 0x60 range - closures // 0x60 range
oCREATE = 0x60 oPUSH1 = 0x60
oCALL = 0x61 oPUSH2 = 0x61
oRETURN = 0x62 oPUSH3 = 0x62
oPUSH4 = 0x63
oPUSH5 = 0x64
oPUSH6 = 0x65
oPUSH7 = 0x66
oPUSH8 = 0x67
oPUSH9 = 0x68
oPUSH10 = 0x69
oPUSH11 = 0x6a
oPUSH12 = 0x6b
oPUSH13 = 0x6c
oPUSH14 = 0x6d
oPUSH15 = 0x6e
oPUSH16 = 0x6f
oPUSH17 = 0x70
oPUSH18 = 0x71
oPUSH19 = 0x72
oPUSH20 = 0x73
oPUSH21 = 0x74
oPUSH22 = 0x75
oPUSH23 = 0x76
oPUSH24 = 0x77
oPUSH25 = 0x78
oPUSH26 = 0x79
oPUSH27 = 0x7a
oPUSH28 = 0x7b
oPUSH29 = 0x7c
oPUSH30 = 0x7d
oPUSH31 = 0x7e
oPUSH32 = 0x7f
// 0xf0 range - closures
oCREATE = 0xf0
oCALL = 0xf1
oRETURN = 0xf2
// 0x70 range - other // 0x70 range - other
oLOG = 0x70 // XXX Unofficial oLOG = 0xfe // XXX Unofficial
oSUICIDE = 0x7f oSUICIDE = 0xff
) )
// Since the opcodes aren't all in order we can't use a regular slice // Since the opcodes aren't all in order we can't use a regular slice
@ -119,8 +151,6 @@ var opCodeToString = map[OpCode]string{
oGASLIMIT: "GASLIMIT", oGASLIMIT: "GASLIMIT",
// 0x50 range - 'storage' and execution // 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP", oDUP: "DUP",
oSWAP: "SWAP", oSWAP: "SWAP",
oMLOAD: "MLOAD", oMLOAD: "MLOAD",
@ -133,7 +163,41 @@ var opCodeToString = map[OpCode]string{
oPC: "PC", oPC: "PC",
oMSIZE: "MSIZE", oMSIZE: "MSIZE",
// 0x60 range - closures // 0x60 range - push
oPUSH1: "PUSH1",
oPUSH2: "PUSH2",
oPUSH3: "PUSH3",
oPUSH4: "PUSH4",
oPUSH5: "PUSH5",
oPUSH6: "PUSH6",
oPUSH7: "PUSH7",
oPUSH8: "PUSH8",
oPUSH9: "PUSH9",
oPUSH10: "PUSH10",
oPUSH11: "PUSH11",
oPUSH12: "PUSH12",
oPUSH13: "PUSH13",
oPUSH14: "PUSH14",
oPUSH15: "PUSH15",
oPUSH16: "PUSH16",
oPUSH17: "PUSH17",
oPUSH18: "PUSH18",
oPUSH19: "PUSH19",
oPUSH20: "PUSH20",
oPUSH21: "PUSH21",
oPUSH22: "PUSH22",
oPUSH23: "PUSH23",
oPUSH24: "PUSH24",
oPUSH25: "PUSH25",
oPUSH26: "PUSH26",
oPUSH27: "PUSH27",
oPUSH28: "PUSH28",
oPUSH29: "PUSH29",
oPUSH30: "PUSH30",
oPUSH31: "PUSH31",
oPUSH32: "PUSH32",
// 0xf0 range
oCREATE: "CREATE", oCREATE: "CREATE",
oCALL: "CALL", oCALL: "CALL",
oRETURN: "RETURN", oRETURN: "RETURN",
@ -193,10 +257,6 @@ var OpCodes = map[string]byte{
"GASLIMIT": 0x45, "GASLIMIT": 0x45,
// 0x50 range - 'storage' and execution // 0x50 range - 'storage' and execution
"PUSH": 0x50,
"PUSH20": 0x80,
"POP": 0x51, "POP": 0x51,
"DUP": 0x52, "DUP": 0x52,
"SWAP": 0x53, "SWAP": 0x53,
@ -210,13 +270,47 @@ var OpCodes = map[string]byte{
"PC": 0x5b, "PC": 0x5b,
"MSIZE": 0x5c, "MSIZE": 0x5c,
// 0x60 range - closures // 0x70 range - 'push'
"CREATE": 0x60, "PUSH1": 0x60,
"CALL": 0x61, "PUSH2": 0x61,
"RETURN": 0x62, "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 // 0x70 range - other
"LOG": 0x70, "LOG": 0xfe,
"SUICIDE": 0x7f, "SUICIDE": 0x7f,
} }

View File

@ -53,6 +53,7 @@ type RuntimeVars struct {
Time int64 Time int64
Diff *big.Int Diff *big.Int
TxData []string TxData []string
Value *big.Int
} }
func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm { func NewVm(state *State, stateManager *StateManager, vars RuntimeVars) *Vm {
@ -94,6 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
if ethutil.Config.Debug { if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("# op\n") ethutil.Config.Log.Debugf("# op\n")
} }
fmt.Println(closure.Script)
for { for {
// The base for all big integer arithmetic // The base for all big integer arithmetic
@ -104,11 +106,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
val := closure.Get(pc) val := closure.Get(pc)
// Get the opcode (it must be an opcode!) // Get the opcode (it must be an opcode!)
op := OpCode(val.Uint()) op := OpCode(val.Uint())
/*
if ethutil.Config.Debug { if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
} }
*/
gas := new(big.Int) gas := new(big.Int)
useGas := func(amount *big.Int) { useGas := func(amount *big.Int) {
@ -318,14 +318,13 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case oADDRESS: case oADDRESS:
stack.Push(ethutil.BigD(closure.Object().Address())) stack.Push(ethutil.BigD(closure.Object().Address()))
case oBALANCE: case oBALANCE:
stack.Push(closure.Value) stack.Push(closure.object.Amount)
case oORIGIN: case oORIGIN:
stack.Push(ethutil.BigD(vm.vars.Origin)) stack.Push(ethutil.BigD(vm.vars.Origin))
case oCALLER: case oCALLER:
stack.Push(ethutil.BigD(closure.Callee().Address())) stack.Push(ethutil.BigD(closure.Callee().Address()))
case oCALLVALUE: case oCALLVALUE:
// FIXME: Original value of the call, not the current value stack.Push(vm.vars.Value)
stack.Push(closure.Value)
case oCALLDATALOAD: case oCALLDATALOAD:
require(1) require(1)
offset := stack.Pop().Int64() offset := stack.Pop().Int64()
@ -353,26 +352,16 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
stack.Push(big.NewInt(0)) stack.Push(big.NewInt(0))
// 0x50 range // 0x50 range
case oPUSH: // Push PC+1 on to the stack case oPUSH1, oPUSH2, oPUSH3, oPUSH4, oPUSH5, oPUSH6, oPUSH7, oPUSH8, oPUSH9, oPUSH10, oPUSH11, oPUSH12, oPUSH13, oPUSH14, oPUSH15, oPUSH16, oPUSH17, oPUSH18, oPUSH19, oPUSH20, oPUSH21, oPUSH22, oPUSH23, oPUSH24, oPUSH25, oPUSH26, oPUSH27, oPUSH28, oPUSH29, oPUSH30, oPUSH31, oPUSH32:
a := big.NewInt(int64(op) - int64(oPUSH1) + 1)
pc.Add(pc, ethutil.Big1) pc.Add(pc, ethutil.Big1)
data := closure.Gets(pc, big.NewInt(32)) data := closure.Gets(pc, a)
val := ethutil.BigD(data.Bytes()) val := ethutil.BigD(data.Bytes())
// Push value to stack // Push value to stack
stack.Push(val) stack.Push(val)
pc.Add(pc, a.Sub(a, big.NewInt(1)))
pc.Add(pc, big.NewInt(31))
step++ step++
case oPUSH20:
pc.Add(pc, ethutil.Big1)
data := closure.Gets(pc, big.NewInt(20))
val := ethutil.BigD(data.Bytes())
// Push value to stack
stack.Push(val)
pc.Add(pc, big.NewInt(19))
step++
case oPOP: case oPOP:
require(1) require(1)
stack.Pop() stack.Pop()
@ -406,21 +395,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case oSSTORE: case oSSTORE:
require(2) require(2)
val, loc := stack.Popn() val, loc := stack.Popn()
closure.SetMem(loc, ethutil.NewValue(val)) closure.SetStorage(loc, ethutil.NewValue(val))
// Add the change to manifest // Add the change to manifest
vm.stateManager.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val) vm.state.manifest.AddStorageChange(closure.Object(), loc.Bytes(), val)
case oJUMP: case oJUMP:
require(1) require(1)
pc = stack.Pop() pc = stack.Pop()
// Reduce pc by one because of the increment that's at the end of this for loop // Reduce pc by one because of the increment that's at the end of this for loop
pc.Sub(pc, ethutil.Big1) //pc.Sub(pc, ethutil.Big1)
continue
case oJUMPI: case oJUMPI:
require(2) require(2)
cond, pos := stack.Popn() cond, pos := stack.Popn()
if cond.Cmp(ethutil.BigTrue) == 0 { if cond.Cmp(ethutil.BigTrue) == 0 {
pc = pos pc = pos
pc.Sub(pc, ethutil.Big1) //pc.Sub(pc, ethutil.Big1)
continue
} }
case oPC: case oPC:
stack.Push(pc) stack.Push(pc)
@ -449,8 +440,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
contract.initScript, contract.initScript,
vm.state, vm.state,
gas, gas,
closure.Price, closure.Price)
value)
// Call the closure and set the return value as // Call the closure and set the return value as
// main script. // main script.
closure.Script, err = closure.Call(vm, nil, hook) closure.Script, err = closure.Call(vm, nil, hook)
@ -477,8 +467,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
break break
} }
// Get the arguments from the memory // Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64()) args := mem.Get(inOffset.Int64(), inSize.Int64())
// Fetch the contract which will serve as the closure body // Fetch the contract which will serve as the closure body
contract := vm.state.GetContract(addr.Bytes()) contract := vm.state.GetContract(addr.Bytes())
@ -490,8 +482,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
gas = new(big.Int).Set(closure.Gas) gas = new(big.Int).Set(closure.Gas)
} }
closure.Gas.Sub(closure.Gas, gas) closure.Gas.Sub(closure.Gas, gas)
// Add the value to the state object
contract.AddAmount(value)
// Create a new callable closure // Create a new callable closure
closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price, value) closure := NewClosure(closure.Object(), contract, contract.script, vm.state, gas, closure.Price)
// Executer the closure and get the return value (if any) // Executer the closure and get the return value (if any)
ret, err := closure.Call(vm, args, hook) ret, err := closure.Call(vm, args, hook)
if err != nil { if err != nil {
@ -500,10 +496,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
//contract.State().Reset() //contract.State().Reset()
} else { } else {
stack.Push(ethutil.BigTrue) stack.Push(ethutil.BigTrue)
// Notify of the changes
vm.stateManager.manifest.AddObjectChange(contract)
} }
vm.state.SetStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret) mem.Set(retOffset.Int64(), retSize.Int64(), ret)
} else { } else {
ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes())
@ -520,8 +516,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
receiver := vm.state.GetAccount(stack.Pop().Bytes()) receiver := vm.state.GetAccount(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount) receiver.AddAmount(closure.object.Amount)
vm.state.SetStateObject(receiver)
vm.stateManager.manifest.AddObjectChange(receiver)
closure.object.state.Purge() closure.object.state.Purge()

View File

@ -11,71 +11,6 @@ import (
"testing" "testing"
) )
/*
func TestRun3(t *testing.T) {
ethutil.ReadConfig("")
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
script := Compile([]string{
"PUSH", "300",
"PUSH", "0",
"MSTORE",
"PUSH", "32",
"CALLDATA",
"PUSH", "64",
"PUSH", "0",
"RETURN",
})
tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), script)
addr := tx.Hash()[12:]
contract := MakeContract(tx, state)
state.UpdateContract(contract)
callerScript := ethutil.Assemble(
"PUSH", 1337, // Argument
"PUSH", 65, // argument mem offset
"MSTORE",
"PUSH", 64, // ret size
"PUSH", 0, // ret offset
"PUSH", 32, // arg size
"PUSH", 65, // arg offset
"PUSH", 1000, /// Gas
"PUSH", 0, /// value
"PUSH", addr, // Sender
"CALL",
"PUSH", 64,
"PUSH", 0,
"RETURN",
)
callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), callerScript)
// Contract addr as test address
account := NewAccount(ContractAddr, big.NewInt(10000000))
callerClosure := NewClosure(account, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int))
vm := NewVm(state, RuntimeVars{
origin: account.Address(),
blockNumber: 1,
prevHash: ethutil.FromHex("5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"),
coinbase: ethutil.FromHex("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"),
time: 1,
diff: big.NewInt(256),
// XXX Tx data? Could be just an argument to the closure instead
txData: nil,
})
ret := callerClosure.Call(vm, nil)
exp := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 57}
if bytes.Compare(ret, exp) != 0 {
t.Errorf("expected return value to be %v, got %v", exp, ret)
}
}*/
func TestRun4(t *testing.T) { func TestRun4(t *testing.T) {
ethutil.ReadConfig("") ethutil.ReadConfig("")
@ -86,7 +21,7 @@ func TestRun4(t *testing.T) {
int32 a = 10 int32 a = 10
int32 b = 20 int32 b = 20
if a > b { if a > b {
int32 c = this.Caller() int32 c = this.caller()
} }
Exit() Exit()
`), false) `), false)
@ -98,21 +33,21 @@ func TestRun4(t *testing.T) {
callerScript, err := mutan.Compile(strings.NewReader(` callerScript, err := mutan.Compile(strings.NewReader(`
// Check if there's any cash in the initial store // Check if there's any cash in the initial store
if store[1000] == 0 { if this.store[1000] == 0 {
store[1000] = 10^20 this.store[1000] = 10^20
} }
store[1001] = this.Value() * 20 this.store[1001] = this.value() * 20
store[this.Origin()] = store[this.Origin()] + 1000 this.store[this.origin()] = this.store[this.origin()] + 1000
if store[1001] > 20 { if this.store[1001] > 20 {
store[1001] = 10^50 this.store[1001] = 10^50
} }
int8 ret = 0 int8 ret = 0
int8 arg = 10 int8 arg = 10
Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
big t big t
for int8 i = 0; i < 10; i++ { for int8 i = 0; i < 10; i++ {
@ -142,7 +77,7 @@ func TestRun4(t *testing.T) {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println("account.Amount =", account.Amount) fmt.Println("account.Amount =", account.Amount)
callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice, big.NewInt(0)) callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice)
vm := NewVm(state, nil, RuntimeVars{ vm := NewVm(state, nil, RuntimeVars{
Origin: account.Address(), Origin: account.Address(),

View File

@ -253,7 +253,7 @@ func (s *Ethereum) ReapDeadPeerHandler() {
} }
// Start the ethereum // Start the ethereum
func (s *Ethereum) Start() { func (s *Ethereum) Start(seed bool) {
// Bind to addr and port // Bind to addr and port
ln, err := net.Listen("tcp", ":"+s.Port) ln, err := net.Listen("tcp", ":"+s.Port)
if err != nil { if err != nil {
@ -272,7 +272,12 @@ func (s *Ethereum) Start() {
// Start the reaping processes // Start the reaping processes
go s.ReapDeadPeerHandler() go s.ReapDeadPeerHandler()
if ethutil.Config.Seed { if seed {
s.Seed()
}
}
func (s *Ethereum) Seed() {
ethutil.Config.Log.Debugln("Seeding") ethutil.Config.Log.Debugln("Seeding")
// DNS Bootstrapping // DNS Bootstrapping
_, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org") _, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
@ -313,7 +318,6 @@ func (s *Ethereum) Start() {
s.ConnectToPeer(string(body)) s.ConnectToPeer(string(body))
} }
}
} }
func (s *Ethereum) peerHandler(listener net.Listener) { func (s *Ethereum) peerHandler(listener net.Listener) {
@ -339,7 +343,9 @@ func (s *Ethereum) Stop() {
close(s.quit) close(s.quit)
if s.RpcServer != nil {
s.RpcServer.Stop() s.RpcServer.Stop()
}
s.txPool.Stop() s.txPool.Stop()
s.stateManager.Stop() s.stateManager.Stop()

View File

@ -92,7 +92,14 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
hash = ethutil.FromHex(recipient) hash = ethutil.FromHex(recipient)
} }
keyPair, err := ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key))) var keyPair *ethchain.KeyPair
var err error
if key[0:2] == "0x" {
keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key[0:2])))
} else {
keyPair, err = ethchain.NewKeyPairFromSec([]byte(ethutil.FromHex(key)))
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -132,8 +139,11 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr)) tx = ethchain.NewTransactionMessage(hash, value, gas, gasPrice, ethutil.FromHex(initStr))
} }
acc := lib.stateManager.GetAddrState(keyPair.Address()) acc := lib.stateManager.TransState().GetStateObject(keyPair.Address())
//acc := lib.stateManager.GetAddrState(keyPair.Address())
tx.Nonce = acc.Nonce tx.Nonce = acc.Nonce
lib.stateManager.TransState().SetStateObject(acc)
tx.Sign(keyPair.PrivateKey) tx.Sign(keyPair.PrivateKey)
lib.txPool.QueueTransaction(tx) lib.txPool.QueueTransaction(tx)

View File

@ -4,7 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/ethereum/eth-go/ethpub" "github.com/ethereum/eth-go/ethpub"
_ "log" "github.com/ethereum/eth-go/ethutil"
"math/big"
) )
type EthereumApi struct { type EthereumApi struct {
@ -173,7 +174,10 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error {
return err return err
} }
state := p.ethp.GetStateObject(args.Address) state := p.ethp.GetStateObject(args.Address)
value := state.GetStorage(args.Key) // Convert the incoming string (which is a bigint) into hex
i, _ := new(big.Int).SetString(args.Key, 10)
hx := ethutil.Hex(i.Bytes())
value := state.GetStorage(hx)
*reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value}) *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value})
return nil return nil
} }

View File

@ -26,7 +26,7 @@ func TestCommon(t *testing.T) {
t.Error("Got", szabo) t.Error("Got", szabo)
} }
if vito != "10 Vito" { if vito != "10 Vita" {
t.Error("Got", vito) t.Error("Got", vito)
} }

View File

@ -27,7 +27,6 @@ type config struct {
Ver string Ver string
ClientString string ClientString string
Pubkey []byte Pubkey []byte
Seed bool
} }
var Config *config var Config *config
@ -51,7 +50,7 @@ func ReadConfig(base string) *config {
} }
} }
Config = &config{ExecPath: path, Debug: true, Ver: "0.5 RC1"} Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC2"}
Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug)
Config.SetClientString("/Ethereum(G)") Config.SetClientString("/Ethereum(G)")
} }

View File

@ -2,7 +2,6 @@ package ethutil
import ( import (
"bytes" "bytes"
"fmt"
"math/big" "math/big"
"reflect" "reflect"
"testing" "testing"
@ -56,15 +55,6 @@ func TestValue(t *testing.T) {
} }
} }
func TestEncodeDecodeMaran(t *testing.T) {
b := NewValue([]interface{}{"dog", 15, []interface{}{"cat", "cat", []interface{}{}}, 1024, "tachikoma"})
a := b.Encode()
fmt.Println("voor maran", a)
f, i := Decode(a, 0)
fmt.Println("voor maran 2", f)
fmt.Println(i)
}
func TestEncode(t *testing.T) { func TestEncode(t *testing.T) {
strRes := "\x83dog" strRes := "\x83dog"
bytes := Encode("dog") bytes := Encode("dog")
@ -131,7 +121,10 @@ func TestEncodeDecodeBytes(t *testing.T) {
func TestEncodeZero(t *testing.T) { func TestEncodeZero(t *testing.T) {
b := NewValue(0).Encode() b := NewValue(0).Encode()
fmt.Println(b) exp := []byte{0xc0}
if bytes.Compare(b, exp) == 0 {
t.Error("Expected", exp, "got", b)
}
} }
func BenchmarkEncodeDecode(b *testing.B) { func BenchmarkEncodeDecode(b *testing.B) {