aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-04-27 22:50:44 +0800
committerobscuren <geffobscura@gmail.com>2014-04-27 22:53:35 +0800
commit16e52327a4baa5547c38965fce53b3ff40b98173 (patch)
tree27fb43512c802e2c3c0fe8bd8d97a55aa2499758 /ethchain
parent05d2d8f27d0bea5b20be9bc3b4a259a12298ecab (diff)
downloadgo-tangerine-16e52327a4baa5547c38965fce53b3ff40b98173.tar.gz
go-tangerine-16e52327a4baa5547c38965fce53b3ff40b98173.tar.zst
go-tangerine-16e52327a4baa5547c38965fce53b3ff40b98173.zip
Upped version number
Diffstat (limited to 'ethchain')
-rw-r--r--ethchain/closure.go23
-rw-r--r--ethchain/stack.go12
-rw-r--r--ethchain/state.go29
-rw-r--r--ethchain/state_object.go4
-rw-r--r--ethchain/vm.go54
5 files changed, 112 insertions, 10 deletions
diff --git a/ethchain/closure.go b/ethchain/closure.go
index f8135c514..57abaa91e 100644
--- a/ethchain/closure.go
+++ b/ethchain/closure.go
@@ -8,21 +8,24 @@ import (
)
type Callee interface {
- ReturnGas(*big.Int, *big.Int, *State)
- Address() []byte
}
type Reference interface {
Callee
- ethutil.RlpEncodable
+}
+
+type ClosureRef interface {
+ ReturnGas(*big.Int, *big.Int, *State)
+ Address() []byte
GetMem(*big.Int) *ethutil.Value
SetMem(*big.Int, *ethutil.Value)
+ N() *big.Int
}
// Basic inline closure object which implement the 'closure' interface
type Closure struct {
- callee Callee
- object Reference
+ callee ClosureRef
+ object ClosureRef
Script []byte
State *State
@@ -34,7 +37,7 @@ type Closure struct {
}
// Create a new closure for the given data items
-func NewClosure(callee Callee, object Reference, script []byte, state *State, gas, price, val *big.Int) *Closure {
+func NewClosure(callee, object ClosureRef, script []byte, state *State, gas, price, val *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
@@ -105,10 +108,14 @@ func (c *Closure) ReturnGas(gas, price *big.Int, state *State) {
c.Gas.Add(c.Gas, gas)
}
-func (c *Closure) Object() Reference {
+func (c *Closure) Object() ClosureRef {
return c.object
}
-func (c *Closure) Callee() Callee {
+func (c *Closure) Callee() ClosureRef {
return c.callee
}
+
+func (c *Closure) N() *big.Int {
+ return c.object.N()
+}
diff --git a/ethchain/stack.go b/ethchain/stack.go
index 288360062..e9297b324 100644
--- a/ethchain/stack.go
+++ b/ethchain/stack.go
@@ -67,6 +67,18 @@ func (st *Stack) Peekn() (*big.Int, *big.Int) {
func (st *Stack) Push(d *big.Int) {
st.data = append(st.data, d)
}
+
+func (st *Stack) Get(amount *big.Int) []*big.Int {
+ // offset + size <= len(data)
+ length := big.NewInt(int64(len(st.data)))
+ if amount.Cmp(length) <= 0 {
+ start := new(big.Int).Sub(length, amount)
+ return st.data[start.Int64():length.Int64()]
+ }
+
+ return nil
+}
+
func (st *Stack) Print() {
fmt.Println("### stack ###")
if len(st.data) > 0 {
diff --git a/ethchain/state.go b/ethchain/state.go
index fa63accf8..1b5655d4c 100644
--- a/ethchain/state.go
+++ b/ethchain/state.go
@@ -47,6 +47,7 @@ func (s *State) Purge() int {
return s.trie.NewIterator().Purge()
}
+// XXX Deprecated
func (s *State) GetContract(addr []byte) *StateObject {
data := s.trie.Get(string(addr))
if data == "" {
@@ -68,6 +69,32 @@ func (s *State) GetContract(addr []byte) *StateObject {
return contract
}
+func (s *State) GetStateObject(addr []byte) *StateObject {
+ data := s.trie.Get(string(addr))
+ if data == "" {
+ return nil
+ }
+
+ stateObject := NewStateObjectFromBytes(addr, []byte(data))
+
+ // Check if there's a cached state for this contract
+ cachedStateObject := s.states[string(addr)]
+ if cachedStateObject != nil {
+ stateObject.state = cachedStateObject
+ } else {
+ // If it isn't cached, cache the state
+ s.states[string(addr)] = stateObject.state
+ }
+
+ return stateObject
+}
+
+func (s *State) SetStateObject(stateObject *StateObject) {
+ s.states[string(stateObject.address)] = stateObject.state
+
+ s.UpdateStateObject(stateObject)
+}
+
func (s *State) GetAccount(addr []byte) (account *StateObject) {
data := s.trie.Get(string(addr))
if data == "" {
@@ -97,6 +124,7 @@ const (
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) {
@@ -124,6 +152,7 @@ func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) {
return val, typ
}
+*/
// Updates any given state object
func (s *State) UpdateStateObject(object *StateObject) {
diff --git a/ethchain/state_object.go b/ethchain/state_object.go
index 8d86ef44e..8e921795d 100644
--- a/ethchain/state_object.go
+++ b/ethchain/state_object.go
@@ -65,6 +65,10 @@ func (c *StateObject) State() *State {
return c.state
}
+func (c *StateObject) N() *big.Int {
+ return big.NewInt(int64(c.Nonce))
+}
+
func (c *StateObject) Addr(addr []byte) *ethutil.Value {
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
}
diff --git a/ethchain/vm.go b/ethchain/vm.go
index a4b4d351b..b983e88ff 100644
--- a/ethchain/vm.go
+++ b/ethchain/vm.go
@@ -20,6 +20,17 @@ var (
GasMemory = big.NewInt(1)
)
+func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int {
+ totalGas := new(big.Int)
+ totalGas.Add(totalGas, GasCreate)
+
+ txTotalBytes := new(big.Int).Add(initSize, scriptSize)
+ txTotalBytes.Div(txTotalBytes, ethutil.Big32)
+ totalGas.Add(totalGas, new(big.Int).Mul(txTotalBytes, GasSStore))
+
+ return totalGas
+}
+
type Vm struct {
txPool *TxPool
// Stack for processing contracts
@@ -125,7 +136,12 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case oBALANCE:
useGas(GasBalance)
case oCREATE:
- useGas(GasCreate)
+ require(3)
+
+ args := stack.Get(big.NewInt(3))
+ initSize := new(big.Int).Add(args[1], args[0])
+
+ useGas(CalculateTxGas(initSize, ethutil.Big0))
case oCALL:
useGas(GasCall)
case oMLOAD, oMSIZE, oMSTORE8, oMSTORE:
@@ -413,6 +429,39 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
stack.Push(big.NewInt(int64(mem.Len())))
// 0x60 range
case oCREATE:
+ require(3)
+
+ value := stack.Pop()
+ size, offset := stack.Popn()
+
+ // Generate a new address
+ addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N())
+ // Create a new contract
+ contract := NewContract(addr, value, []byte(""))
+ // Set the init script
+ contract.initScript = mem.Get(offset.Int64(), size.Int64())
+ // Transfer all remaining gas to the new
+ // contract so it may run the init script
+ gas := new(big.Int).Set(closure.Gas)
+ closure.Gas.Sub(closure.Gas, gas)
+ // Create the closure
+ closure := NewClosure(closure.callee,
+ closure.Object(),
+ contract.initScript,
+ vm.state,
+ gas,
+ closure.Price,
+ value)
+ // Call the closure and set the return value as
+ // main script.
+ closure.Script, err = closure.Call(vm, nil, hook)
+ if err != nil {
+ stack.Push(ethutil.BigFalse)
+ } else {
+ stack.Push(ethutil.BigD(addr))
+
+ vm.state.SetStateObject(contract)
+ }
case oCALL:
require(7)
// Closure addr
@@ -438,7 +487,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// Prepay for the gas
// If gas is set to 0 use all remaining gas for the next call
if gas.Cmp(big.NewInt(0)) == 0 {
- gas = closure.Gas
+ // Copy
+ gas = new(big.Int).Set(closure.Gas)
}
closure.Gas.Sub(closure.Gas, gas)
// Create a new callable closure