Fixed MSTORE and added some more commets

This commit is contained in:
obscuren 2014-03-20 19:50:53 +01:00
parent f21eb88ad1
commit c68ff9886b
4 changed files with 51 additions and 18 deletions

View File

@ -21,15 +21,17 @@ type ClosureBody interface {
type Closure struct { type Closure struct {
callee Callee callee Callee
object ClosureBody object ClosureBody
state *State State *State
gas *big.Int gas *big.Int
val *big.Int val *big.Int
args []byte
} }
// Create a new closure for the given data items // Create a new closure for the given data items
func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure { func NewClosure(callee Callee, object ClosureBody, state *State, gas, val *big.Int) *Closure {
return &Closure{callee, object, state, gas, val} return &Closure{callee, object, state, gas, val, nil}
} }
// Retuns the x element in data slice // Retuns the x element in data slice
@ -42,14 +44,20 @@ func (c *Closure) GetMem(x int64) *ethutil.Value {
return m return m
} }
func (c *Closure) Call(vm *Vm, args []byte) []byte {
c.args = args
return vm.RunClosure(c)
}
func (c *Closure) Return(ret []byte) []byte { func (c *Closure) Return(ret []byte) []byte {
// Return the remaining gas to the callee // Return the remaining gas to the callee
// If no callee is present return it to // If no callee is present return it to
// the origin (i.e. contract or tx) // the origin (i.e. contract or tx)
if c.callee != nil { if c.callee != nil {
c.callee.ReturnGas(c.gas, c.state) c.callee.ReturnGas(c.gas, c.State)
} else { } else {
c.object.ReturnGas(c.gas, c.state) c.object.ReturnGas(c.gas, c.State)
// TODO incase it's a POST contract we gotta serialise the contract again. // TODO incase it's a POST contract we gotta serialise the contract again.
// But it's not yet defined // But it's not yet defined
} }

View File

@ -235,6 +235,7 @@ func (st *ValueStack) Peekn() (*ethutil.Value, *ethutil.Value) {
func (st *ValueStack) Push(d *ethutil.Value) { func (st *ValueStack) Push(d *ethutil.Value) {
st.data = append(st.data, d) st.data = append(st.data, d)
} }
func (st *ValueStack) Print() { func (st *ValueStack) Print() {
fmt.Println("### STACK ###") fmt.Println("### STACK ###")
if len(st.data) > 0 { if len(st.data) > 0 {

View File

@ -18,6 +18,8 @@ type Vm struct {
mem map[string]*big.Int mem map[string]*big.Int
vars RuntimeVars vars RuntimeVars
state *State
} }
type RuntimeVars struct { type RuntimeVars struct {
@ -32,7 +34,11 @@ type RuntimeVars struct {
txData []string txData []string
} }
func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byte { func NewVm(state *State, vars RuntimeVars) *Vm {
return &Vm{vars: vars, state: state}
}
func (vm *Vm) RunClosure(closure *Closure) []byte {
// If the amount of gas supplied is less equal to 0 // If the amount of gas supplied is less equal to 0
if closure.GetGas().Cmp(big.NewInt(0)) <= 0 { if closure.GetGas().Cmp(big.NewInt(0)) <= 0 {
// TODO Do something // TODO Do something
@ -71,17 +77,28 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt
} }
switch op { switch op {
case oSTOP: case oSTOP: // Stop the closure
return closure.Return(nil) return closure.Return(nil)
case oPUSH: case oPUSH: // Push PC+1 on to the stack
pc++ pc++
val := closure.GetMem(pc).BigInt() val := closure.GetMem(pc).BigInt()
stack.Push(val) stack.Push(val)
case oMSTORE: case oMSTORE: // Store the value at stack top-1 in to memory at location stack top
// Pop value of the stack // Pop value of the stack
val := stack.Pop() val, mStart := stack.Popn()
// Set the bytes to the memory field // Ensure that memory is large enough to hold the data
mem = append(mem, ethutil.BigToBytes(val, 256)...) // If it isn't resize the memory slice so that it may hold the value
bytesLen := big.NewInt(32)
totSize := new(big.Int).Add(mStart, bytesLen)
lenSize := big.NewInt(int64(len(mem)))
if totSize.Cmp(lenSize) > 0 {
// Calculate the diff between the sizes
diff := new(big.Int).Sub(totSize, lenSize)
// Create a new empty slice and append it
newSlice := make([]byte, diff.Int64()+1)
mem = append(mem, newSlice...)
}
copy(mem[mStart.Int64():mStart.Int64()+bytesLen.Int64()+1], ethutil.BigToBytes(val, 256))
case oCALL: case oCALL:
// Pop return size and offset // Pop return size and offset
retSize, retOffset := stack.Popn() retSize, retOffset := stack.Popn()
@ -93,20 +110,25 @@ func (vm *Vm) RunClosure(closure *Closure, state *State, vars RuntimeVars) []byt
gas, value := stack.Popn() gas, value := stack.Popn()
// Closure addr // Closure addr
addr := stack.Pop() addr := stack.Pop()
// Fetch the contract which will serve as the closure body
contract := state.GetContract(addr.Bytes()) contract := vm.state.GetContract(addr.Bytes())
closure := NewClosure(closure, contract, state, gas, value) // Create a new callable closure
ret := vm.RunClosure(closure, state, vars) closure := NewClosure(closure, contract, vm.state, gas, value)
// Executer the closure and get the return value (if any)
ret := closure.Call(vm, nil)
// Ensure that memory is large enough to hold the returned data // Ensure that memory is large enough to hold the returned data
// If it isn't resize the memory slice so that it may hold the value
totSize := new(big.Int).Add(retOffset, retSize) totSize := new(big.Int).Add(retOffset, retSize)
lenSize := big.NewInt(int64(len(mem))) lenSize := big.NewInt(int64(len(mem)))
// Resize the current memory slice so that the return value may fit
if totSize.Cmp(lenSize) > 0 { if totSize.Cmp(lenSize) > 0 {
// Calculate the diff between the sizes
diff := new(big.Int).Sub(totSize, lenSize) diff := new(big.Int).Sub(totSize, lenSize)
// Create a new empty slice and append it
newSlice := make([]byte, diff.Int64()+1) newSlice := make([]byte, diff.Int64()+1)
mem = append(mem, newSlice...) mem = append(mem, newSlice...)
} }
// Copy over the returned values to the memory given the offset and size
copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret) copy(mem[retOffset.Int64():retOffset.Int64()+retSize.Int64()+1], ret)
case oRETURN: case oRETURN:
size, offset := stack.Popn() size, offset := stack.Popn()

View File

@ -117,8 +117,10 @@ func TestRun3(t *testing.T) {
script := Compile([]string{ script := Compile([]string{
"PUSH", "300", "PUSH", "300",
"PUSH", "0",
"MSTORE", "MSTORE",
"PUSH", "300", "PUSH", "300",
"PUSH", "31",
"MSTORE", "MSTORE",
"PUSH", "62", "PUSH", "62",
"PUSH", "0", "PUSH", "0",
@ -147,8 +149,7 @@ func TestRun3(t *testing.T) {
executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) executer.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int)) callerClosure := NewClosure(executer, MakeContract(callerTx, state), state, big.NewInt(1000000000), new(big.Int))
vm := &Vm{} vm := NewVm(state, RuntimeVars{
vm.RunClosure(callerClosure, state, RuntimeVars{
address: callerAddr, address: callerAddr,
blockNumber: 1, blockNumber: 1,
sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"), sender: ethutil.FromHex("cd1722f3947def4cf144679da39c4c32bdc35681"),
@ -159,4 +160,5 @@ func TestRun3(t *testing.T) {
txValue: big.NewInt(10000), txValue: big.NewInt(10000),
txData: nil, txData: nil,
}) })
callerClosure.Call(vm, nil)
} }