Merge branch 'release/poc5-rc2'
This commit is contained in:
commit
3af35d922e
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,8 +42,14 @@ 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 {
|
||||
@ -60,11 +58,12 @@ func NewStateManager(ethereum EthManager) *StateManager {
|
||||
mem: make(map[string]*big.Int),
|
||||
Pow: &EasyPow{},
|
||||
Ethereum: ethereum,
|
||||
stateObjectCache: NewStateObjectCache(),
|
||||
bc: ethereum.BlockChain(),
|
||||
manifest: NewManifest(),
|
||||
//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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
*/
|
||||
|
||||
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()
|
||||
@ -353,26 +352,16 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
|
||||
stack.Push(big.NewInt(0))
|
||||
|
||||
// 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)
|
||||
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()
|
||||
|
||||
|
@ -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(),
|
||||
|
12
ethereum.go
12
ethereum.go
@ -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,7 +272,12 @@ func (s *Ethereum) Start() {
|
||||
// Start the reaping processes
|
||||
go s.ReapDeadPeerHandler()
|
||||
|
||||
if ethutil.Config.Seed {
|
||||
if seed {
|
||||
s.Seed()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Ethereum) Seed() {
|
||||
ethutil.Config.Log.Debugln("Seeding")
|
||||
// DNS Bootstrapping
|
||||
_, nodes, err := net.LookupSRV("eth", "tcp", "ethereum.org")
|
||||
@ -314,7 +319,6 @@ func (s *Ethereum) Start() {
|
||||
s.ConnectToPeer(string(body))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Ethereum) peerHandler(listener net.Listener) {
|
||||
for {
|
||||
@ -339,7 +343,9 @@ func (s *Ethereum) Stop() {
|
||||
|
||||
close(s.quit)
|
||||
|
||||
if s.RpcServer != nil {
|
||||
s.RpcServer.Stop()
|
||||
}
|
||||
s.txPool.Stop()
|
||||
s.stateManager.Stop()
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)")
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user