forked from cerc-io/plugeth
Implemented closure arguments
This commit is contained in:
parent
9cf8ce9ef8
commit
fa1db8d2dc
@ -68,12 +68,16 @@ const (
|
|||||||
oJUMP = 0x59
|
oJUMP = 0x59
|
||||||
oJUMPI = 0x5a
|
oJUMPI = 0x5a
|
||||||
oPC = 0x5b
|
oPC = 0x5b
|
||||||
oMEMSIZE = 0x5c
|
oMSIZE = 0x5c
|
||||||
|
|
||||||
// 0x60 range - closures
|
// 0x60 range - closures
|
||||||
oCREATE = 0x60
|
oCREATE = 0x60
|
||||||
oCALL = 0x61
|
oCALL = 0x61
|
||||||
oRETURN = 0x62
|
oRETURN = 0x62
|
||||||
|
|
||||||
|
// 0x70 range - other
|
||||||
|
oLOG = 0x70 // XXX Unofficial
|
||||||
|
oSUICIDE = 0x7f
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
@ -136,12 +140,16 @@ var opCodeToString = map[OpCode]string{
|
|||||||
oJUMP: "JUMP",
|
oJUMP: "JUMP",
|
||||||
oJUMPI: "JUMPI",
|
oJUMPI: "JUMPI",
|
||||||
oPC: "PC",
|
oPC: "PC",
|
||||||
oMEMSIZE: "MEMSIZE",
|
oMSIZE: "MSIZE",
|
||||||
|
|
||||||
// 0x60 range - closures
|
// 0x60 range - closures
|
||||||
oCREATE: "CREATE",
|
oCREATE: "CREATE",
|
||||||
oCALL: "CALL",
|
oCALL: "CALL",
|
||||||
oRETURN: "RETURN",
|
oRETURN: "RETURN",
|
||||||
|
|
||||||
|
// 0x70 range - other
|
||||||
|
oLOG: "LOG",
|
||||||
|
oSUICIDE: "SUICIDE",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o OpCode) String() string {
|
func (o OpCode) String() string {
|
||||||
@ -215,20 +223,30 @@ type Memory struct {
|
|||||||
|
|
||||||
func (m *Memory) Set(offset, size int64, value []byte) {
|
func (m *Memory) Set(offset, size int64, value []byte) {
|
||||||
totSize := offset + size
|
totSize := offset + size
|
||||||
lenSize := int64(len(m.store))
|
lenSize := int64(len(m.store) - 1)
|
||||||
if totSize > lenSize {
|
if totSize > lenSize {
|
||||||
// Calculate the diff between the sizes
|
// Calculate the diff between the sizes
|
||||||
diff := totSize - lenSize
|
diff := totSize - lenSize
|
||||||
if diff > 0 {
|
if diff > 0 {
|
||||||
// Create a new empty slice and append it
|
// Create a new empty slice and append it
|
||||||
newSlice := make([]byte, diff+1)
|
newSlice := make([]byte, diff-1)
|
||||||
// Resize slice
|
// Resize slice
|
||||||
m.store = append(m.store, newSlice...)
|
m.store = append(m.store, newSlice...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
copy(m.store[offset:offset+size+1], value)
|
copy(m.store[offset:offset+size], value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Memory) Get(offset, size int64) []byte {
|
func (m *Memory) Get(offset, size int64) []byte {
|
||||||
return m.store[offset : offset+size]
|
return m.store[offset : offset+size]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Memory) Print() {
|
||||||
|
fmt.Println("### MEM ###")
|
||||||
|
if len(m.store) > 0 {
|
||||||
|
fmt.Println(m.store)
|
||||||
|
} else {
|
||||||
|
fmt.Println("-- empty --")
|
||||||
|
}
|
||||||
|
fmt.Println("###########")
|
||||||
|
}
|
||||||
|
184
ethchain/vm.go
184
ethchain/vm.go
@ -2,7 +2,7 @@ package ethchain
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "bytes"
|
_ "bytes"
|
||||||
"fmt"
|
_ "fmt"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
_ "github.com/obscuren/secp256k1-go"
|
_ "github.com/obscuren/secp256k1-go"
|
||||||
"log"
|
"log"
|
||||||
@ -36,6 +36,8 @@ func NewVm(state *State, vars RuntimeVars) *Vm {
|
|||||||
return &Vm{vars: vars, state: state}
|
return &Vm{vars: vars, state: state}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Pow256 = ethutil.BigPow(2, 256)
|
||||||
|
|
||||||
func (vm *Vm) RunClosure(closure *Closure) []byte {
|
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 {
|
||||||
@ -48,9 +50,10 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
|
|||||||
stack := NewStack()
|
stack := NewStack()
|
||||||
// Instruction pointer
|
// Instruction pointer
|
||||||
pc := int64(0)
|
pc := int64(0)
|
||||||
// Current address
|
// Current step count
|
||||||
//addr := vars.address
|
|
||||||
step := 0
|
step := 0
|
||||||
|
// The base for all big integer arithmetic
|
||||||
|
base := new(big.Int)
|
||||||
|
|
||||||
if ethutil.Config.Debug {
|
if ethutil.Config.Debug {
|
||||||
ethutil.Config.Log.Debugf("# op\n")
|
ethutil.Config.Log.Debugf("# op\n")
|
||||||
@ -75,27 +78,171 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
|
case oLOG:
|
||||||
|
stack.Print()
|
||||||
|
mem.Print()
|
||||||
case oSTOP: // Stop the closure
|
case oSTOP: // Stop the closure
|
||||||
return closure.Return(nil)
|
return closure.Return(nil)
|
||||||
|
|
||||||
|
// 0x20 range
|
||||||
|
case oADD:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// (x + y) % 2 ** 256
|
||||||
|
base.Add(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
stack.Push(base)
|
||||||
|
case oSUB:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// (x - y) % 2 ** 256
|
||||||
|
base.Sub(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
stack.Push(base)
|
||||||
|
case oMUL:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// (x * y) % 2 ** 256
|
||||||
|
base.Mul(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
stack.Push(base)
|
||||||
|
case oDIV:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// floor(x / y)
|
||||||
|
base.Div(x, y)
|
||||||
|
// Pop result back on the stack
|
||||||
|
stack.Push(base)
|
||||||
|
case oSDIV:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// n > 2**255
|
||||||
|
if x.Cmp(Pow256) > 0 {
|
||||||
|
x.Sub(Pow256, x)
|
||||||
|
}
|
||||||
|
if y.Cmp(Pow256) > 0 {
|
||||||
|
y.Sub(Pow256, y)
|
||||||
|
}
|
||||||
|
z := new(big.Int)
|
||||||
|
z.Div(x, y)
|
||||||
|
if z.Cmp(Pow256) > 0 {
|
||||||
|
z.Sub(Pow256, z)
|
||||||
|
}
|
||||||
|
// Push result on to the stack
|
||||||
|
stack.Push(z)
|
||||||
|
case oMOD:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
base.Mod(x, y)
|
||||||
|
stack.Push(base)
|
||||||
|
case oSMOD:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// n > 2**255
|
||||||
|
if x.Cmp(Pow256) > 0 {
|
||||||
|
x.Sub(Pow256, x)
|
||||||
|
}
|
||||||
|
if y.Cmp(Pow256) > 0 {
|
||||||
|
y.Sub(Pow256, y)
|
||||||
|
}
|
||||||
|
z := new(big.Int)
|
||||||
|
z.Mod(x, y)
|
||||||
|
if z.Cmp(Pow256) > 0 {
|
||||||
|
z.Sub(Pow256, z)
|
||||||
|
}
|
||||||
|
// Push result on to the stack
|
||||||
|
stack.Push(z)
|
||||||
|
case oEXP:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
base.Exp(x, y, Pow256)
|
||||||
|
|
||||||
|
stack.Push(base)
|
||||||
|
case oNEG:
|
||||||
|
base.Sub(Pow256, stack.Pop())
|
||||||
|
stack.Push(base)
|
||||||
|
case oLT:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// x < y
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
stack.Push(ethutil.BigTrue)
|
||||||
|
} else {
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
}
|
||||||
|
case oGT:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// x > y
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
stack.Push(ethutil.BigTrue)
|
||||||
|
} else {
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
}
|
||||||
|
case oNOT:
|
||||||
|
x, y := stack.Popn()
|
||||||
|
// x != y
|
||||||
|
if x.Cmp(y) != 0 {
|
||||||
|
stack.Push(ethutil.BigTrue)
|
||||||
|
} else {
|
||||||
|
stack.Push(ethutil.BigFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x10 range
|
||||||
|
case oAND:
|
||||||
|
case oOR:
|
||||||
|
case oXOR:
|
||||||
|
case oBYTE:
|
||||||
|
|
||||||
|
// 0x20 range
|
||||||
|
case oSHA3:
|
||||||
|
|
||||||
|
// 0x30 range
|
||||||
|
case oADDRESS:
|
||||||
|
case oBALANCE:
|
||||||
|
case oORIGIN:
|
||||||
|
case oCALLER:
|
||||||
|
case oCALLVALUE:
|
||||||
|
case oCALLDATA:
|
||||||
|
offset := stack.Pop()
|
||||||
|
mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args)
|
||||||
|
case oCALLDATASIZE:
|
||||||
|
case oRETURNDATASIZE:
|
||||||
|
case oTXGASPRICE:
|
||||||
|
|
||||||
|
// 0x40 range
|
||||||
|
case oPREVHASH:
|
||||||
|
case oPREVNONCE:
|
||||||
|
case oCOINBASE:
|
||||||
|
case oTIMESTAMP:
|
||||||
|
case oNUMBER:
|
||||||
|
case oDIFFICULTY:
|
||||||
|
case oGASLIMIT:
|
||||||
|
|
||||||
|
// 0x50 range
|
||||||
case oPUSH: // Push PC+1 on to the stack
|
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 oPOP:
|
||||||
|
case oDUP:
|
||||||
|
case oSWAP:
|
||||||
|
case oMLOAD:
|
||||||
|
offset := stack.Pop()
|
||||||
|
stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32)))
|
||||||
case oMSTORE: // Store the value at stack top-1 in to memory at location stack top
|
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, mStart := stack.Popn()
|
val, mStart := stack.Popn()
|
||||||
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256))
|
||||||
|
case oMSTORE8:
|
||||||
|
case oSLOAD:
|
||||||
|
case oSSTORE:
|
||||||
|
case oJUMP:
|
||||||
|
case oJUMPI:
|
||||||
|
case oPC:
|
||||||
|
case oMSIZE:
|
||||||
|
|
||||||
case oCALLDATA:
|
// 0x60 range
|
||||||
offset := stack.Pop()
|
|
||||||
mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args)
|
|
||||||
case oCALL:
|
case oCALL:
|
||||||
// Pop return size and offset
|
// Pop return size and offset
|
||||||
retSize, retOffset := stack.Popn()
|
retSize, retOffset := stack.Popn()
|
||||||
// Pop input size and offset
|
// Pop input size and offset
|
||||||
inSize, inOffset := stack.Popn()
|
inSize, inOffset := stack.Popn()
|
||||||
// TODO remove me.
|
// Get the arguments from the memory
|
||||||
fmt.Sprintln(inSize, inOffset)
|
args := mem.Get(inOffset.Int64(), inSize.Int64())
|
||||||
// Pop gas and value of the stack.
|
// Pop gas and value of the stack.
|
||||||
gas, value := stack.Popn()
|
gas, value := stack.Popn()
|
||||||
// Closure addr
|
// Closure addr
|
||||||
@ -105,7 +252,7 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
|
|||||||
// Create a new callable closure
|
// Create a new callable closure
|
||||||
closure := NewClosure(closure, contract, vm.state, gas, value)
|
closure := NewClosure(closure, contract, vm.state, gas, value)
|
||||||
// Executer the closure and get the return value (if any)
|
// Executer the closure and get the return value (if any)
|
||||||
ret := closure.Call(vm, nil)
|
ret := closure.Call(vm, args)
|
||||||
|
|
||||||
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
|
||||||
case oRETURN:
|
case oRETURN:
|
||||||
@ -113,6 +260,25 @@ func (vm *Vm) RunClosure(closure *Closure) []byte {
|
|||||||
ret := mem.Get(offset.Int64(), size.Int64())
|
ret := mem.Get(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
return closure.Return(ret)
|
return closure.Return(ret)
|
||||||
|
case oSUICIDE:
|
||||||
|
/*
|
||||||
|
recAddr := stack.Pop().Bytes()
|
||||||
|
// Purge all memory
|
||||||
|
deletedMemory := contract.state.Purge()
|
||||||
|
// Add refunds to the pop'ed address
|
||||||
|
refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory)))
|
||||||
|
account := state.GetAccount(recAddr)
|
||||||
|
account.Amount.Add(account.Amount, refund)
|
||||||
|
// Update the refunding address
|
||||||
|
state.UpdateAccount(recAddr, account)
|
||||||
|
// Delete the contract
|
||||||
|
state.trie.Update(string(addr), "")
|
||||||
|
|
||||||
|
ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr)
|
||||||
|
break out
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
ethutil.Config.Log.Debugln("Invalid opcode", op)
|
||||||
}
|
}
|
||||||
|
|
||||||
pc++
|
pc++
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ethchain
|
package ethchain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ethereum/eth-go/ethdb"
|
"github.com/ethereum/eth-go/ethdb"
|
||||||
"github.com/ethereum/eth-go/ethutil"
|
"github.com/ethereum/eth-go/ethutil"
|
||||||
@ -119,11 +120,13 @@ func TestRun3(t *testing.T) {
|
|||||||
"PUSH", "300",
|
"PUSH", "300",
|
||||||
"PUSH", "0",
|
"PUSH", "0",
|
||||||
"MSTORE",
|
"MSTORE",
|
||||||
"PUSH", "300",
|
|
||||||
"PUSH", "31",
|
"PUSH", "32",
|
||||||
"MSTORE",
|
"CALLDATA",
|
||||||
"PUSH", "62",
|
|
||||||
|
"PUSH", "64",
|
||||||
"PUSH", "0",
|
"PUSH", "0",
|
||||||
|
"LOG",
|
||||||
"RETURN",
|
"RETURN",
|
||||||
})
|
})
|
||||||
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
|
tx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), script)
|
||||||
@ -133,14 +136,21 @@ func TestRun3(t *testing.T) {
|
|||||||
state.UpdateContract(contract)
|
state.UpdateContract(contract)
|
||||||
|
|
||||||
callerScript := Compile([]string{
|
callerScript := Compile([]string{
|
||||||
"PUSH", "62", // ret size
|
"PUSH", "1337", // Argument
|
||||||
|
"PUSH", "65", // argument mem offset
|
||||||
|
"MSTORE",
|
||||||
|
"PUSH", "64", // ret size
|
||||||
"PUSH", "0", // ret offset
|
"PUSH", "0", // ret offset
|
||||||
|
|
||||||
"PUSH", "32", // arg size
|
"PUSH", "32", // arg size
|
||||||
"PUSH", "63", // arg offset
|
"PUSH", "65", // arg offset
|
||||||
"PUSH", "1000", /// Gas
|
"PUSH", "1000", /// Gas
|
||||||
"PUSH", "0", /// value
|
"PUSH", "0", /// value
|
||||||
"PUSH", string(addr), // Sender
|
"PUSH", string(addr), // Sender
|
||||||
"CALL",
|
"CALL",
|
||||||
|
"PUSH", "64",
|
||||||
|
"PUSH", "0",
|
||||||
|
"RETURN",
|
||||||
})
|
})
|
||||||
callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript)
|
callerTx := NewTransaction(ContractAddr, ethutil.Big("100000000000000000000000000000000000000000000000000"), callerScript)
|
||||||
|
|
||||||
@ -158,5 +168,10 @@ func TestRun3(t *testing.T) {
|
|||||||
// XXX Tx data? Could be just an argument to the closure instead
|
// XXX Tx data? Could be just an argument to the closure instead
|
||||||
txData: nil,
|
txData: nil,
|
||||||
})
|
})
|
||||||
callerClosure.Call(vm, 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,12 +65,16 @@ var OpCodes = map[string]byte{
|
|||||||
"JUMP": 0x59,
|
"JUMP": 0x59,
|
||||||
"JUMPI": 0x5a,
|
"JUMPI": 0x5a,
|
||||||
"PC": 0x5b,
|
"PC": 0x5b,
|
||||||
"MEMSIZE": 0x5c,
|
"MSIZE": 0x5c,
|
||||||
|
|
||||||
// 0x60 range - closures
|
// 0x60 range - closures
|
||||||
"CREATE": 0x60,
|
"CREATE": 0x60,
|
||||||
"CALL": 0x61,
|
"CALL": 0x61,
|
||||||
"RETURN": 0x62,
|
"RETURN": 0x62,
|
||||||
|
|
||||||
|
// 0x70 range - other
|
||||||
|
"LOG": 0x70,
|
||||||
|
"SUICIDE": 0x7f,
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsOpCode(s string) bool {
|
func IsOpCode(s string) bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user