aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-01-16 22:20:41 +0800
committerobscuren <geffobscura@gmail.com>2014-01-16 22:20:41 +0800
commit83396cd836f6d963573295b9304be87bf45f5ad6 (patch)
tree3fbf521946b2820cd715a848f14691efc3004331
parenta80a3eeb238443d4b49deda360015ab315bd14a4 (diff)
downloadgo-tangerine-83396cd836f6d963573295b9304be87bf45f5ad6.tar.gz
go-tangerine-83396cd836f6d963573295b9304be87bf45f5ad6.tar.zst
go-tangerine-83396cd836f6d963573295b9304be87bf45f5ad6.zip
Moved stack to its own file. Moved contract processing to block manager
-rw-r--r--block_manager.go207
-rw-r--r--stack.go164
2 files changed, 366 insertions, 5 deletions
diff --git a/block_manager.go b/block_manager.go
index 7e16cdb3a..7b2d01f29 100644
--- a/block_manager.go
+++ b/block_manager.go
@@ -6,6 +6,7 @@ import (
"github.com/ethereum/ethutil-go"
"log"
"math/big"
+ "strconv"
)
type BlockChain struct {
@@ -40,16 +41,17 @@ func (bc *BlockChain) GenesisBlock() *ethutil.Block {
}
type BlockManager struct {
- // Ethereum virtual machine for processing contracts
- vm *Vm
// The block chain :)
bc *BlockChain
+
+ // Stack for processing contracts
+ stack *Stack
}
func NewBlockManager() *BlockManager {
bm := &BlockManager{
- vm: NewVm(),
- bc: NewBlockChain(),
+ bc: NewBlockChain(),
+ stack: NewStack(),
}
return bm
@@ -189,7 +191,7 @@ func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.
}()
// Process contract
- bm.vm.ProcContract(tx, block, func(opType OpType) bool {
+ bm.ProcContract(tx, block, func(opType OpType) bool {
// TODO turn on once big ints are in place
//if !block.PayFee(tx.Hash(), StepFee.Uint64()) {
// return false
@@ -201,3 +203,198 @@ func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil.
// Broadcast we're done
lockChan <- true
}
+
+func (bm *BlockManager) 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
+ }
+
+ Pow256 := ethutil.BigPow(2, 256)
+
+ //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)
+ o, _, _ := ethutil.Instr(contract.State().Get(string(nb)))
+ op := OpCode(o)
+
+ if !cb(0) {
+ break
+ }
+
+ if Debug {
+ //fmt.Printf("%-3d %-4s\n", pc, op.String())
+ }
+
+ switch op {
+ case oADD:
+ x, y := bm.stack.Popn()
+ // (x + y) % 2 ** 256
+ base.Add(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base.String())
+ case oSUB:
+ x, y := bm.stack.Popn()
+ // (x - y) % 2 ** 256
+ base.Sub(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base.String())
+ case oMUL:
+ x, y := bm.stack.Popn()
+ // (x * y) % 2 ** 256
+ base.Mul(x, y)
+ base.Mod(base, Pow256)
+ // Pop result back on the stack
+ bm.stack.Push(base.String())
+ case oDIV:
+ x, y := bm.stack.Popn()
+ // floor(x / y)
+ base.Div(x, y)
+ // Pop result back on the stack
+ bm.stack.Push(base.String())
+ case oSDIV:
+ x, y := bm.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
+ bm.stack.Push(z.String())
+ case oMOD:
+ x, y := bm.stack.Popn()
+ base.Mod(x, y)
+ bm.stack.Push(base.String())
+ case oSMOD:
+ x, y := bm.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
+ bm.stack.Push(z.String())
+ case oEXP:
+ x, y := bm.stack.Popn()
+ base.Exp(x, y, Pow256)
+
+ bm.stack.Push(base.String())
+ case oNEG:
+ base.Sub(Pow256, ethutil.Big(bm.stack.Pop()))
+ bm.stack.Push(base.String())
+ case oLT:
+ x, y := bm.stack.Popn()
+ // x < y
+ if x.Cmp(y) < 0 {
+ bm.stack.Push("1")
+ } else {
+ bm.stack.Push("0")
+ }
+ case oLE:
+ x, y := bm.stack.Popn()
+ // x <= y
+ if x.Cmp(y) < 1 {
+ bm.stack.Push("1")
+ } else {
+ bm.stack.Push("0")
+ }
+ case oGT:
+ x, y := bm.stack.Popn()
+ // x > y
+ if x.Cmp(y) > 0 {
+ bm.stack.Push("1")
+ } else {
+ bm.stack.Push("0")
+ }
+ case oGE:
+ x, y := bm.stack.Popn()
+ // x >= y
+ if x.Cmp(y) > -1 {
+ bm.stack.Push("1")
+ } else {
+ bm.stack.Push("0")
+ }
+ case oNOT:
+ x, y := bm.stack.Popn()
+ // x != y
+ if x.Cmp(y) != 0 {
+ bm.stack.Push("1")
+ } else {
+ bm.stack.Push("0")
+ }
+
+ // Please note that the following code contains some
+ // ugly string casting. This will have to change to big
+ // ints. TODO :)
+ case oMYADDRESS:
+ bm.stack.Push(string(tx.Hash()))
+ case oTXSENDER:
+ bm.stack.Push(string(tx.Sender()))
+ case oTXVALUE:
+ bm.stack.Push(tx.Value.String())
+ case oTXDATAN:
+ bm.stack.Push(big.NewInt(int64(len(tx.Data))).String())
+ case oTXDATA:
+ v := ethutil.Big(bm.stack.Pop())
+ // v >= len(data)
+ if v.Cmp(big.NewInt(int64(len(tx.Data)))) >= 0 {
+ //I know this will change. It makes no
+ //sense. Read comment above
+ bm.stack.Push(ethutil.Big("0").String())
+ } else {
+ bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()]).String())
+ }
+ case oBLK_PREVHASH:
+ bm.stack.Push(string(block.PrevHash))
+ case oBLK_COINBASE:
+ bm.stack.Push(block.Coinbase)
+ case oBLK_TIMESTAMP:
+ bm.stack.Push(big.NewInt(block.Time).String())
+ case oBLK_NUMBER:
+
+ case oPUSH:
+ // Get the next entry and pushes the value on the stack
+ pc++
+ bm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(pc), 32))))
+ case oPOP:
+ // Pop current value of the stack
+ bm.stack.Pop()
+ case oLOAD:
+ // Load instruction X on the stack
+ i, _ := strconv.Atoi(bm.stack.Pop())
+ bm.stack.Push(contract.State().Get(string(ethutil.NumberToBytes(uint64(i), 32))))
+ case oSTOP:
+ break out
+ }
+ pc++
+ }
+
+ bm.stack.Print()
+}
diff --git a/stack.go b/stack.go
new file mode 100644
index 000000000..2b2f075cf
--- /dev/null
+++ b/stack.go
@@ -0,0 +1,164 @@
+package main
+
+import (
+ "fmt"
+ "github.com/ethereum/ethutil-go"
+ "math/big"
+)
+
+type OpCode byte
+
+// Op codes
+const (
+ oSTOP OpCode = 0x00
+ oADD OpCode = 0x01
+ oMUL OpCode = 0x02
+ oSUB OpCode = 0x03
+ oDIV OpCode = 0x04
+ oSDIV OpCode = 0x05
+ oMOD OpCode = 0x06
+ oSMOD OpCode = 0x07
+ oEXP OpCode = 0x08
+ oNEG OpCode = 0x09
+ oLT OpCode = 0x0a
+ oLE OpCode = 0x0b
+ oGT OpCode = 0x0c
+ oGE OpCode = 0x0d
+ oEQ OpCode = 0x0e
+ oNOT OpCode = 0x0f
+ oMYADDRESS OpCode = 0x10
+ oTXSENDER OpCode = 0x11
+ oTXVALUE OpCode = 0x12
+ oTXFEE OpCode = 0x13
+ oTXDATAN OpCode = 0x14
+ oTXDATA OpCode = 0x15
+ oBLK_PREVHASH OpCode = 0x16
+ oBLK_COINBASE OpCode = 0x17
+ oBLK_TIMESTAMP OpCode = 0x18
+ oBLK_NUMBER OpCode = 0x19
+ oBLK_DIFFICULTY OpCode = 0x1a
+ oSHA256 OpCode = 0x20
+ oRIPEMD160 OpCode = 0x21
+ oECMUL OpCode = 0x22
+ oECADD OpCode = 0x23
+ oECSIGN OpCode = 0x24
+ oECRECOVER OpCode = 0x25
+ oECVALID OpCode = 0x26
+ oPUSH OpCode = 0x30
+ oPOP OpCode = 0x31
+ oDUP OpCode = 0x32
+ oDUPN OpCode = 0x33
+ oSWAP OpCode = 0x34
+ oSWAPN OpCode = 0x35
+ oLOAD OpCode = 0x36
+ oSTORE OpCode = 0x37
+ oJMP OpCode = 0x40
+ oJMPI OpCode = 0x41
+ oIND OpCode = 0x42
+ oEXTRO OpCode = 0x50
+ oBALANCE OpCode = 0x51
+ oMKTX OpCode = 0x60
+ oSUICIDE OpCode = 0xff
+)
+
+// Since the opcodes aren't all in order we can't use a regular slice
+var opCodeToString = map[OpCode]string{
+ oSTOP: "STOP",
+ oADD: "ADD",
+ oMUL: "MUL",
+ oSUB: "SUB",
+ oDIV: "DIV",
+ oSDIV: "SDIV",
+ oMOD: "MOD",
+ oSMOD: "SMOD",
+ oEXP: "EXP",
+ oNEG: "NEG",
+ oLT: "LT",
+ oLE: "LE",
+ oGT: "GT",
+ oGE: "GE",
+ oEQ: "EQ",
+ oNOT: "NOT",
+ oMYADDRESS: "MYADDRESS",
+ oTXSENDER: "TXSENDER",
+ oTXVALUE: "TXVALUE",
+ oTXFEE: "TXFEE",
+ oTXDATAN: "TXDATAN",
+ oTXDATA: "TXDATA",
+ oBLK_PREVHASH: "BLK_PREVHASH",
+ oBLK_COINBASE: "BLK_COINBASE",
+ oBLK_TIMESTAMP: "BLK_TIMESTAMP",
+ oBLK_NUMBER: "BLK_NUMBER",
+ oBLK_DIFFICULTY: "BLK_DIFFIFULTY",
+ oSHA256: "SHA256",
+ oRIPEMD160: "RIPEMD160",
+ oECMUL: "ECMUL",
+ oECADD: "ECADD",
+ oECSIGN: "ECSIGN",
+ oECRECOVER: "ECRECOVER",
+ oECVALID: "ECVALID",
+ oPUSH: "PUSH",
+ oPOP: "POP",
+ oDUP: "DUP",
+ oDUPN: "DUPN",
+ oSWAP: "SWAP",
+ oSWAPN: "SWAPN",
+ oLOAD: "LOAD",
+ oSTORE: "STORE",
+ oJMP: "JMP",
+ oJMPI: "JMPI",
+ oIND: "IND",
+ oEXTRO: "EXTRO",
+ oBALANCE: "BALANCE",
+ oMKTX: "MKTX",
+ oSUICIDE: "SUICIDE",
+}
+
+func (o OpCode) String() string {
+ return opCodeToString[o]
+}
+
+type OpType int
+
+const (
+ tNorm = iota
+ tData
+ tExtro
+ tCrypto
+)
+
+type TxCallback func(opType OpType) bool
+
+// Simple push/pop stack mechanism
+type Stack struct {
+ data []string
+}
+
+func NewStack() *Stack {
+ return &Stack{}
+}
+
+func (st *Stack) Pop() string {
+ s := len(st.data)
+
+ str := st.data[s-1]
+ st.data = st.data[:s-1]
+
+ return str
+}
+
+func (st *Stack) Popn() (*big.Int, *big.Int) {
+ s := len(st.data)
+
+ strs := st.data[s-2:]
+ st.data = st.data[:s-2]
+
+ return ethutil.Big(strs[0]), ethutil.Big(strs[1])
+}
+
+func (st *Stack) Push(d string) {
+ st.data = append(st.data, d)
+}
+func (st *Stack) Print() {
+ fmt.Println(st.data)
+}