aboutsummaryrefslogtreecommitdiffstats
path: root/vm.go
diff options
context:
space:
mode:
Diffstat (limited to 'vm.go')
-rw-r--r--vm.go451
1 files changed, 234 insertions, 217 deletions
diff --git a/vm.go b/vm.go
index 5605cb7c7..96a3dfa05 100644
--- a/vm.go
+++ b/vm.go
@@ -1,267 +1,284 @@
package main
import (
- "math/big"
- "fmt"
- "strconv"
- "github.com/ethereum/ethutil-go"
+ "fmt"
+ "github.com/ethereum/ethutil-go"
+ "math/big"
+ "strconv"
)
// Op codes
const (
- oSTOP int = 0x00
- oADD int = 0x01
- oMUL int = 0x02
- oSUB int = 0x03
- oDIV int = 0x04
- oSDIV int = 0x05
- oMOD int = 0x06
- oSMOD int = 0x07
- oEXP int = 0x08
- oNEG int = 0x09
- oLT int = 0x0a
- oLE int = 0x0b
- oGT int = 0x0c
- oGE int = 0x0d
- oEQ int = 0x0e
- oNOT int = 0x0f
- oMYADDRESS int = 0x10
- oTXSENDER int = 0x11
- oTXVALUE int = 0x12
- oTXFEE int = 0x13
- oTXDATAN int = 0x14
- oTXDATA int = 0x15
- oBLK_PREVHASH int = 0x16
- oBLK_COINBASE int = 0x17
- oBLK_TIMESTAMP int = 0x18
- oBLK_NUMBER int = 0x19
- oBLK_DIFFICULTY int = 0x1a
- oSHA256 int = 0x20
- oRIPEMD160 int = 0x21
- oECMUL int = 0x22
- oECADD int = 0x23
- oECSIGN int = 0x24
- oECRECOVER int = 0x25
- oECVALID int = 0x26
- oPUSH int = 0x30
- oPOP int = 0x31
- oDUP int = 0x32
- oDUPN int = 0x33
- oSWAP int = 0x34
- oSWAPN int = 0x35
- oLOAD int = 0x36
- oSTORE int = 0x37
- oJMP int = 0x40
- oJMPI int = 0x41
- oIND int = 0x42
- oEXTRO int = 0x50
- oBALANCE int = 0x51
- oMKTX int = 0x60
- oSUICIDE int = 0xff
+ oSTOP int = 0x00
+ oADD int = 0x01
+ oMUL int = 0x02
+ oSUB int = 0x03
+ oDIV int = 0x04
+ oSDIV int = 0x05
+ oMOD int = 0x06
+ oSMOD int = 0x07
+ oEXP int = 0x08
+ oNEG int = 0x09
+ oLT int = 0x0a
+ oLE int = 0x0b
+ oGT int = 0x0c
+ oGE int = 0x0d
+ oEQ int = 0x0e
+ oNOT int = 0x0f
+ oMYADDRESS int = 0x10
+ oTXSENDER int = 0x11
+ oTXVALUE int = 0x12
+ oTXFEE int = 0x13
+ oTXDATAN int = 0x14
+ oTXDATA int = 0x15
+ oBLK_PREVHASH int = 0x16
+ oBLK_COINBASE int = 0x17
+ oBLK_TIMESTAMP int = 0x18
+ oBLK_NUMBER int = 0x19
+ oBLK_DIFFICULTY int = 0x1a
+ oSHA256 int = 0x20
+ oRIPEMD160 int = 0x21
+ oECMUL int = 0x22
+ oECADD int = 0x23
+ oECSIGN int = 0x24
+ oECRECOVER int = 0x25
+ oECVALID int = 0x26
+ oPUSH int = 0x30
+ oPOP int = 0x31
+ oDUP int = 0x32
+ oDUPN int = 0x33
+ oSWAP int = 0x34
+ oSWAPN int = 0x35
+ oLOAD int = 0x36
+ oSTORE int = 0x37
+ oJMP int = 0x40
+ oJMPI int = 0x41
+ oIND int = 0x42
+ oEXTRO int = 0x50
+ oBALANCE int = 0x51
+ oMKTX int = 0x60
+ oSUICIDE int = 0xff
)
type OpType int
+
const (
- tNorm = iota
- tData
- tExtro
- tCrypto
+ tNorm = iota
+ tData
+ tExtro
+ tCrypto
)
+
type TxCallback func(opType OpType) bool
// Simple push/pop stack mechanism
type Stack struct {
- data []string
+ data []string
}
+
func NewStack() *Stack {
- return &Stack{}
+ return &Stack{}
}
func (st *Stack) Pop() string {
- s := len(st.data)
+ s := len(st.data)
- str := st.data[s-1]
- st.data = st.data[:s-1]
+ str := st.data[s-1]
+ st.data = st.data[:s-1]
- return str
+ return str
}
func (st *Stack) Popn() (*big.Int, *big.Int) {
- s := len(st.data)
+ s := len(st.data)
- strs := st.data[s-2:]
- st.data = st.data[:s-2]
+ strs := st.data[s-2:]
+ st.data = st.data[:s-2]
- return ethutil.Big(strs[0]), ethutil.Big(strs[1])
+ return ethutil.Big(strs[0]), ethutil.Big(strs[1])
}
func (st *Stack) Push(d string) {
- st.data = append(st.data, d)
+ st.data = append(st.data, d)
}
func (st *Stack) Print() {
- fmt.Println(st.data)
+ fmt.Println(st.data)
}
type Vm struct {
- // Stack
- stack *Stack
+ // Stack
+ stack *Stack
}
func NewVm() *Vm {
- return &Vm{
- stack: NewStack(),
- }
+ return &Vm{
+ stack: NewStack(),
+ }
}
-func (vm *Vm) ProcContract( tx *ethutil.Transaction,
- block *ethutil.Block, cb TxCallback) {
- // Instruction pointer
- pc := 0
+func (vm *Vm) ProcContract(tx *ethutil.Transaction,
+ block *ethutil.Block, cb TxCallback) {
+ // Instruction pointer
+ pc := 0
- contract := block.GetContract(tx.Hash())
- if contract == nil {
- fmt.Println("Contract not found")
- return
- }
+ contract := block.GetContract(tx.Hash())
+ if contract == nil {
+ fmt.Println("Contract not found")
+ return
+ }
- Pow256 := ethutil.BigPow(2, 256)
+ Pow256 := ethutil.BigPow(2, 256)
- //fmt.Printf("# op arg\n")
+ //fmt.Printf("# op arg\n")
out:
- for {
- // The base big int for all calculations. Use this for any results.
- base := new(big.Int)
- // XXX Should Instr return big int slice instead of string slice?
- // Get the next instruction from the contract
- //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
- nb := ethutil.NumberToBytes(uint64(pc), 32)
- op, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
+ for {
+ // The base big int for all calculations. Use this for any results.
+ base := new(big.Int)
+ // XXX Should Instr return big int slice instead of string slice?
+ // Get the next instruction from the contract
+ //op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
+ nb := ethutil.NumberToBytes(uint64(pc), 32)
+ op, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
- if !cb(0) { break }
+ if !cb(0) {
+ break
+ }
- if Debug {
- //fmt.Printf("%-3d %-4d\n", pc, op)
- }
+ if Debug {
+ //fmt.Printf("%-3d %-4d\n", pc, op)
+ }
- switch op {
- case oADD:
- x, y := vm.stack.Popn()
- // (x + y) % 2 ** 256
- base.Add(x, y)
- base.Mod(base, Pow256)
- // Pop result back on the stack
- vm.stack.Push(base.String())
- case oSUB:
- x, y := vm.stack.Popn()
- // (x - y) % 2 ** 256
- base.Sub(x, y)
- base.Mod(base, Pow256)
- // Pop result back on the stack
- vm.stack.Push(base.String())
- case oMUL:
- x, y := vm.stack.Popn()
- // (x * y) % 2 ** 256
- base.Mul(x, y)
- base.Mod(base, Pow256)
- // Pop result back on the stack
- vm.stack.Push(base.String())
- case oDIV:
- x, y := vm.stack.Popn()
- // floor(x / y)
- base.Div(x, y)
- // Pop result back on the stack
- vm.stack.Push(base.String())
- case oSDIV:
- x, y := vm.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
- vm.stack.Push(z.String())
- case oMOD:
- x, y := vm.stack.Popn()
- base.Mod(x, y)
- vm.stack.Push(base.String())
- case oSMOD:
- x, y := vm.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
- vm.stack.Push(z.String())
- case oEXP:
- x, y := vm.stack.Popn()
- base.Exp(x, y, Pow256)
+ switch op {
+ case oADD:
+ x, y := vm.stack.Popn()
+ // (x + y) % 2 ** 256
+ base.Add(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ vm.stack.Push(base.String())
+ case oSUB:
+ x, y := vm.stack.Popn()
+ // (x - y) % 2 ** 256
+ base.Sub(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ vm.stack.Push(base.String())
+ case oMUL:
+ x, y := vm.stack.Popn()
+ // (x * y) % 2 ** 256
+ base.Mul(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ vm.stack.Push(base.String())
+ case oDIV:
+ x, y := vm.stack.Popn()
+ // floor(x / y)
+ base.Div(x, y)
+ // Pop result back on the stack
+ vm.stack.Push(base.String())
+ case oSDIV:
+ x, y := vm.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
+ vm.stack.Push(z.String())
+ case oMOD:
+ x, y := vm.stack.Popn()
+ base.Mod(x, y)
+ vm.stack.Push(base.String())
+ case oSMOD:
+ x, y := vm.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
+ vm.stack.Push(z.String())
+ case oEXP:
+ x, y := vm.stack.Popn()
+ base.Exp(x, y, Pow256)
- vm.stack.Push(base.String())
- case oNEG:
- base.Sub(Pow256, ethutil.Big(vm.stack.Pop()))
- vm.stack.Push(base.String())
- case oLT:
- x, y := vm.stack.Popn()
- // x < y
- if x.Cmp(y) < 0 {
- vm.stack.Push("1")
- } else {
- vm.stack.Push("0")
- }
- case oLE:
- x, y := vm.stack.Popn()
- // x <= y
- if x.Cmp(y) < 1 {
- vm.stack.Push("1")
- } else {
- vm.stack.Push("0")
- }
- case oGT:
- x, y := vm.stack.Popn()
- // x > y
- if x.Cmp(y) > 0 {
- vm.stack.Push("1")
- } else {
- vm.stack.Push("0")
- }
- case oGE:
- x, y := vm.stack.Popn()
- // x >= y
- if x.Cmp(y) > -1 {
- vm.stack.Push("1")
- } else {
- vm.stack.Push("0")
- }
- case oNOT:
- x, y := vm.stack.Popn()
- // x != y
- if x.Cmp(y) != 0 {
- vm.stack.Push("1")
- } else {
- vm.stack.Push("0")
- }
- case oMYADDRESS:
- vm.stack.Push(string(tx.Hash()))
- case oTXSENDER:
- vm.stack.Push(string(tx.Sender()))
- case oPUSH:
- // Get the next entry and pushes the value on the stack
- pc++
- vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
- case oPOP:
- // Pop current value of the stack
- vm.stack.Pop()
- case oLOAD:
- // Load instruction X on the stack
- i, _ := strconv.Atoi(vm.stack.Pop())
- vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
- case oSTOP:
- break out
- }
- pc++
- }
+ vm.stack.Push(base.String())
+ case oNEG:
+ base.Sub(Pow256, ethutil.Big(vm.stack.Pop()))
+ vm.stack.Push(base.String())
+ case oLT:
+ x, y := vm.stack.Popn()
+ // x < y
+ if x.Cmp(y) < 0 {
+ vm.stack.Push("1")
+ } else {
+ vm.stack.Push("0")
+ }
+ case oLE:
+ x, y := vm.stack.Popn()
+ // x <= y
+ if x.Cmp(y) < 1 {
+ vm.stack.Push("1")
+ } else {
+ vm.stack.Push("0")
+ }
+ case oGT:
+ x, y := vm.stack.Popn()
+ // x > y
+ if x.Cmp(y) > 0 {
+ vm.stack.Push("1")
+ } else {
+ vm.stack.Push("0")
+ }
+ case oGE:
+ x, y := vm.stack.Popn()
+ // x >= y
+ if x.Cmp(y) > -1 {
+ vm.stack.Push("1")
+ } else {
+ vm.stack.Push("0")
+ }
+ case oNOT:
+ x, y := vm.stack.Popn()
+ // x != y
+ if x.Cmp(y) != 0 {
+ vm.stack.Push("1")
+ } else {
+ vm.stack.Push("0")
+ }
+ case oMYADDRESS:
+ vm.stack.Push(string(tx.Hash()))
+ case oTXSENDER:
+ vm.stack.Push(string(tx.Sender()))
+ case oPUSH:
+ // Get the next entry and pushes the value on the stack
+ pc++
+ vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
+ case oPOP:
+ // Pop current value of the stack
+ vm.stack.Pop()
+ case oLOAD:
+ // Load instruction X on the stack
+ i, _ := strconv.Atoi(vm.stack.Pop())
+ vm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
+ case oSTOP:
+ break out
+ }
+ pc++
+ }
- vm.stack.Print()
+ vm.stack.Print()
}