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))
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)
data := script[pc.Int64() : pc.Int64()+32]
a := int64(op) - int64(oPUSH1) + 1
data := script[pc.Int64() : pc.Int64()+a]
val := ethutil.BigD(data)
var b []byte
@ -35,21 +36,7 @@ func Disassemble(script []byte) (asm []string) {
asm = append(asm, fmt.Sprintf("0x%x", b))
pc.Add(pc, big.NewInt(31))
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, big.NewInt(a-1))
}
pc.Add(pc, ethutil.Big1)

View File

@ -11,7 +11,7 @@ type ClosureRef interface {
ReturnGas(*big.Int, *big.Int, *State)
Address() []byte
GetMem(*big.Int) *ethutil.Value
SetMem(*big.Int, *ethutil.Value)
SetStore(*big.Int, *ethutil.Value)
N() *big.Int
}
@ -24,20 +24,18 @@ type Closure struct {
Gas *big.Int
Price *big.Int
Value *big.Int
Args []byte
}
// 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}
// In most cases gas, price and value are pointers to transaction objects
// and we don't want the transaction's values to change.
c.Gas = new(big.Int).Set(gas)
c.Price = new(big.Int).Set(price)
c.Value = new(big.Int).Set(val)
return c
}
@ -66,8 +64,8 @@ func (c *Closure) Gets(x, y *big.Int) *ethutil.Value {
return ethutil.NewValue(partial)
}
func (c *Closure) SetMem(x *big.Int, val *ethutil.Value) {
c.object.SetMem(x, val)
func (c *Closure) SetStorage(x *big.Int, val *ethutil.Value) {
c.object.SetStorage(x, val)
}
func (c *Closure) Address() []byte {

View File

@ -15,11 +15,13 @@ type State struct {
trie *ethutil.Trie
// Nested states
states map[string]*State
manifest *Manifest
}
// Create a new state from a given trie
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
@ -114,46 +116,6 @@ func (s *State) Copy() *State {
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
func (s *State) UpdateStateObject(object *StateObject) {
addr := object.Address()
@ -163,6 +125,7 @@ func (s *State) UpdateStateObject(object *StateObject) {
}
s.trie.Update(string(addr), string(object.RlpEncode()))
s.manifest.AddObjectChange(object)
}
func (s *State) Put(key, object []byte) {
@ -172,3 +135,40 @@ func (s *State) Put(key, object []byte) {
func (s *State) Root() interface{} {
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 {
// Mutex for locking the block processor. Blocks can only be handled one at a time
mutex sync.Mutex
// Canonical block chain
bc *BlockChain
// States for addresses. You can watch any address
// at any given time
stateObjectCache *StateObjectCache
// Stack for processing contracts
stack *Stack
// non-persistent key/value memory storage
mem map[string]*big.Int
// Proof of work used for validating
Pow PoW
// The ethereum manager interface
Ethereum EthManager
SecondaryBlockProcessor BlockProcessor
// The managed states
// Processor state. Anything processed will be applied to this
// state
@ -50,21 +42,28 @@ type StateManager struct {
// Comparative state it used for comparing and validating end
// results
compState *State
manifest *Manifest
// Transiently state. The trans state isn't ever saved, validated and
// it could be used for setting account nonces without effecting
// the main states.
transState *State
// 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 {
sm := &StateManager{
stack: NewStack(),
mem: make(map[string]*big.Int),
Pow: &EasyPow{},
Ethereum: ethereum,
stateObjectCache: NewStateObjectCache(),
bc: ethereum.BlockChain(),
manifest: NewManifest(),
stack: NewStack(),
mem: make(map[string]*big.Int),
Pow: &EasyPow{},
Ethereum: ethereum,
bc: ethereum.BlockChain(),
//manifest: NewManifest(),
}
sm.procState = ethereum.BlockChain().CurrentBlock.State()
sm.transState = sm.procState.Copy()
return sm
}
@ -72,22 +71,8 @@ func (sm *StateManager) ProcState() *State {
return sm.procState
}
// Watches any given address and puts it in the address state store
func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject {
//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) TransState() *State {
return sm.transState
}
func (sm *StateManager) BlockChain() *BlockChain {
@ -201,19 +186,13 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// Add the block to the chain
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())
if dontReact == false {
sm.Ethereum.Reactor().Post("newBlock", block)
sm.notifyChanges()
sm.manifest.Reset()
sm.procState.manifest.Reset()
}
} else {
fmt.Println("total diff failed")
@ -323,7 +302,7 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
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{
Origin: account.Address(),
BlockNumber: block.BlockInfo().Number,
@ -331,59 +310,24 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: tx.Value,
//Price: tx.GasPrice,
})
closure.Call(vm, tx.Data, nil)
// Update the account (refunds)
sm.procState.UpdateStateObject(account)
sm.manifest.AddObjectChange(account)
sm.procState.UpdateStateObject(object)
sm.manifest.AddObjectChange(object)
}
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)
}
for stateObjectAddr, mappedObjects := range sm.manifest.storageChanges {
for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges {
for addr, value := range mappedObjects {
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()))
}
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)
c.SetAddr(addr, val)
}
@ -160,33 +160,8 @@ func (c *StateObject) RlpDecode(data []byte) {
c.script = decoder.Get(3).Bytes()
}
// The cached state and state object cache are helpers which will give you somewhat
// control over the nonce. When creating new transactions you're interested in the 'next'
// 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
}
// Storage change object. Used by the manifest for notifying changes to
// the sub channels.
type StorageState struct {
StateAddress []byte
Address []byte

View File

@ -148,8 +148,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
}
// Get the sender
accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender())
sender := accountState.Object
sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender())
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

View File

@ -48,8 +48,6 @@ const (
oGASLIMIT = 0x45
// 0x50 range - 'storage' and execution
oPUSH = 0x50
oPUSH20 = 0x80
oPOP = 0x51
oDUP = 0x52
oSWAP = 0x53
@ -63,14 +61,48 @@ const (
oPC = 0x5b
oMSIZE = 0x5c
// 0x60 range - closures
oCREATE = 0x60
oCALL = 0x61
oRETURN = 0x62
// 0x60 range
oPUSH1 = 0x60
oPUSH2 = 0x61
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
oLOG = 0x70 // XXX Unofficial
oSUICIDE = 0x7f
oLOG = 0xfe // XXX Unofficial
oSUICIDE = 0xff
)
// 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",
// 0x50 range - 'storage' and execution
oPUSH: "PUSH",
oPOP: "POP",
oDUP: "DUP",
oSWAP: "SWAP",
oMLOAD: "MLOAD",
@ -133,7 +163,41 @@ var opCodeToString = map[OpCode]string{
oPC: "PC",
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",
oCALL: "CALL",
oRETURN: "RETURN",
@ -193,10 +257,6 @@ var OpCodes = map[string]byte{
"GASLIMIT": 0x45,
// 0x50 range - 'storage' and execution
"PUSH": 0x50,
"PUSH20": 0x80,
"POP": 0x51,
"DUP": 0x52,
"SWAP": 0x53,
@ -210,13 +270,47 @@ var OpCodes = map[string]byte{
"PC": 0x5b,
"MSIZE": 0x5c,
// 0x60 range - closures
"CREATE": 0x60,
"CALL": 0x61,
"RETURN": 0x62,
// 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": 0x70,
"LOG": 0xfe,
"SUICIDE": 0x7f,
}

View File

@ -53,6 +53,7 @@ type RuntimeVars struct {
Time int64
Diff *big.Int
TxData []string
Value *big.Int
}
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 {
ethutil.Config.Log.Debugf("# op\n")
}
fmt.Println(closure.Script)
for {
// 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)
// Get the opcode (it must be an opcode!)
op := OpCode(val.Uint())
/*
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
}
*/
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
}
gas := new(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:
stack.Push(ethutil.BigD(closure.Object().Address()))
case oBALANCE:
stack.Push(closure.Value)
stack.Push(closure.object.Amount)
case oORIGIN:
stack.Push(ethutil.BigD(vm.vars.Origin))
case oCALLER:
stack.Push(ethutil.BigD(closure.Callee().Address()))
case oCALLVALUE:
// FIXME: Original value of the call, not the current value
stack.Push(closure.Value)
stack.Push(vm.vars.Value)
case oCALLDATALOAD:
require(1)
offset := stack.Pop().Int64()
@ -352,27 +351,17 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// TODO
stack.Push(big.NewInt(0))
// 0x50 range
case oPUSH: // Push PC+1 on to the stack
// 0x50 range
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)
data := closure.Gets(pc, big.NewInt(32))
data := closure.Gets(pc, a)
val := ethutil.BigD(data.Bytes())
// Push value to stack
stack.Push(val)
pc.Add(pc, big.NewInt(31))
pc.Add(pc, a.Sub(a, big.NewInt(1)))
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:
require(1)
stack.Pop()
@ -406,21 +395,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case oSSTORE:
require(2)
val, loc := stack.Popn()
closure.SetMem(loc, ethutil.NewValue(val))
closure.SetStorage(loc, ethutil.NewValue(val))
// 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:
require(1)
pc = stack.Pop()
// 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:
require(2)
cond, pos := stack.Popn()
if cond.Cmp(ethutil.BigTrue) == 0 {
pc = pos
pc.Sub(pc, ethutil.Big1)
//pc.Sub(pc, ethutil.Big1)
continue
}
case oPC:
stack.Push(pc)
@ -449,8 +440,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
contract.initScript,
vm.state,
gas,
closure.Price,
value)
closure.Price)
// Call the closure and set the return value as
// main script.
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
}
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
// Fetch the contract which will serve as the closure body
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)
}
closure.Gas.Sub(closure.Gas, gas)
// Add the value to the state object
contract.AddAmount(value)
// 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)
ret, err := closure.Call(vm, args, hook)
if err != nil {
@ -500,10 +496,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
//contract.State().Reset()
} else {
stack.Push(ethutil.BigTrue)
// Notify of the changes
vm.stateManager.manifest.AddObjectChange(contract)
}
vm.state.SetStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
} else {
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.AddAmount(closure.object.Amount)
vm.stateManager.manifest.AddObjectChange(receiver)
vm.state.SetStateObject(receiver)
closure.object.state.Purge()

View File

@ -11,71 +11,6 @@ import (
"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) {
ethutil.ReadConfig("")
@ -86,7 +21,7 @@ func TestRun4(t *testing.T) {
int32 a = 10
int32 b = 20
if a > b {
int32 c = this.Caller()
int32 c = this.caller()
}
Exit()
`), false)
@ -98,21 +33,21 @@ func TestRun4(t *testing.T) {
callerScript, err := mutan.Compile(strings.NewReader(`
// Check if there's any cash in the initial store
if store[1000] == 0 {
store[1000] = 10^20
if this.store[1000] == 0 {
this.store[1000] = 10^20
}
store[1001] = this.Value() * 20
store[this.Origin()] = store[this.Origin()] + 1000
this.store[1001] = this.value() * 20
this.store[this.origin()] = this.store[this.origin()] + 1000
if store[1001] > 20 {
store[1001] = 10^50
if this.store[1001] > 20 {
this.store[1001] = 10^50
}
int8 ret = 0
int8 arg = 10
Call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret)
big t
for int8 i = 0; i < 10; i++ {
@ -142,7 +77,7 @@ func TestRun4(t *testing.T) {
fmt.Println(err)
}
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{
Origin: account.Address(),

View File

@ -253,7 +253,7 @@ func (s *Ethereum) ReapDeadPeerHandler() {
}
// Start the ethereum
func (s *Ethereum) Start() {
func (s *Ethereum) Start(seed bool) {
// Bind to addr and port
ln, err := net.Listen("tcp", ":"+s.Port)
if err != nil {
@ -272,47 +272,51 @@ func (s *Ethereum) Start() {
// Start the reaping processes
go s.ReapDeadPeerHandler()
if ethutil.Config.Seed {
ethutil.Config.Log.Debugln("Seeding")
// DNS Bootstrapping
_, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
if err == nil {
peers := []string{}
// Iterate SRV nodes
for _, n := range nodes {
target := n.Target
port := strconv.Itoa(int(n.Port))
// Resolve target to ip (Go returns list, so may resolve to multiple ips?)
addr, err := net.LookupHost(target)
if err == nil {
for _, a := range addr {
// Build string out of SRV port and Resolved IP
peer := net.JoinHostPort(a, port)
log.Println("Found DNS Bootstrap Peer:", peer)
peers = append(peers, peer)
}
} else {
log.Println("Couldn't resolve :", target)
}
}
// Connect to Peer list
s.ProcessPeerList(peers)
} else {
// Fallback to servers.poc3.txt
resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
if err != nil {
log.Println("Fetching seed failed:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("Reading seed failed:", err)
return
}
if seed {
s.Seed()
}
}
s.ConnectToPeer(string(body))
func (s *Ethereum) Seed() {
ethutil.Config.Log.Debugln("Seeding")
// DNS Bootstrapping
_, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
if err == nil {
peers := []string{}
// Iterate SRV nodes
for _, n := range nodes {
target := n.Target
port := strconv.Itoa(int(n.Port))
// Resolve target to ip (Go returns list, so may resolve to multiple ips?)
addr, err := net.LookupHost(target)
if err == nil {
for _, a := range addr {
// Build string out of SRV port and Resolved IP
peer := net.JoinHostPort(a, port)
log.Println("Found DNS Bootstrap Peer:", peer)
peers = append(peers, peer)
}
} else {
log.Println("Couldn't resolve :", target)
}
}
// Connect to Peer list
s.ProcessPeerList(peers)
} else {
// Fallback to servers.poc3.txt
resp, err := http.Get("http://www.ethereum.org/servers.poc3.txt")
if err != nil {
log.Println("Fetching seed failed:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println("Reading seed failed:", err)
return
}
s.ConnectToPeer(string(body))
}
}
@ -339,7 +343,9 @@ func (s *Ethereum) Stop() {
close(s.quit)
s.RpcServer.Stop()
if s.RpcServer != nil {
s.RpcServer.Stop()
}
s.txPool.Stop()
s.stateManager.Stop()

View File

@ -92,7 +92,14 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
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 {
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))
}
acc := lib.stateManager.GetAddrState(keyPair.Address())
acc := lib.stateManager.TransState().GetStateObject(keyPair.Address())
//acc := lib.stateManager.GetAddrState(keyPair.Address())
tx.Nonce = acc.Nonce
lib.stateManager.TransState().SetStateObject(acc)
tx.Sign(keyPair.PrivateKey)
lib.txPool.QueueTransaction(tx)

View File

@ -4,7 +4,8 @@ import (
"encoding/json"
"errors"
"github.com/ethereum/eth-go/ethpub"
_ "log"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type EthereumApi struct {
@ -173,7 +174,10 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error {
return err
}
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})
return nil
}

View File

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

View File

@ -27,7 +27,6 @@ type config struct {
Ver string
ClientString string
Pubkey []byte
Seed bool
}
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.SetClientString("/Ethereum(G)")
}

View File

@ -2,7 +2,6 @@ package ethutil
import (
"bytes"
"fmt"
"math/big"
"reflect"
"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) {
strRes := "\x83dog"
bytes := Encode("dog")
@ -131,7 +121,10 @@ func TestEncodeDecodeBytes(t *testing.T) {
func TestEncodeZero(t *testing.T) {
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) {