From 489576b6f04585b33c8aedd8aa6e5a8d54e1a960 Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Sun, 19 Jan 2014 00:35:32 +0100
Subject: More opcodes

---
 block_manager.go | 133 +++++++++++++++++++++++++++++++++----------------------
 stack.go         |  11 +++--
 2 files changed, 85 insertions(+), 59 deletions(-)

diff --git a/block_manager.go b/block_manager.go
index 0831111e3..44b5461dc 100644
--- a/block_manager.go
+++ b/block_manager.go
@@ -9,6 +9,7 @@ import (
 	"log"
 	"math"
 	"math/big"
+	"strconv"
 )
 
 type BlockChain struct {
@@ -52,14 +53,14 @@ type BlockManager struct {
 	// Stack for processing contracts
 	stack *Stack
 	// non-persistent key/value memory storage
-	mem map[string]string
+	mem map[string]*big.Int
 }
 
 func NewBlockManager() *BlockManager {
 	bm := &BlockManager{
 		bc:    NewBlockChain(),
 		stack: NewStack(),
-		mem:   make(map[string]string),
+		mem:   make(map[string]*big.Int),
 	}
 
 	// Set the last known block number based on the blockchains last
@@ -276,27 +277,27 @@ out:
 			base.Add(x, y)
 			base.Mod(base, Pow256)
 			// Pop result back on the stack
-			bm.stack.Push(base.String())
+			bm.stack.Push(base)
 		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())
+			bm.stack.Push(base)
 		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())
+			bm.stack.Push(base)
 		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())
+			bm.stack.Push(base)
 		case oSDIV:
 			x, y := bm.stack.Popn()
 			// n > 2**255
@@ -312,11 +313,11 @@ out:
 				z.Sub(Pow256, z)
 			}
 			// Push result on to the stack
-			bm.stack.Push(z.String())
+			bm.stack.Push(z)
 		case oMOD:
 			x, y := bm.stack.Popn()
 			base.Mod(x, y)
-			bm.stack.Push(base.String())
+			bm.stack.Push(base)
 		case oSMOD:
 			x, y := bm.stack.Popn()
 			// n > 2**255
@@ -332,87 +333,85 @@ out:
 				z.Sub(Pow256, z)
 			}
 			// Push result on to the stack
-			bm.stack.Push(z.String())
+			bm.stack.Push(z)
 		case oEXP:
 			x, y := bm.stack.Popn()
 			base.Exp(x, y, Pow256)
 
-			bm.stack.Push(base.String())
+			bm.stack.Push(base)
 		case oNEG:
-			base.Sub(Pow256, ethutil.Big(bm.stack.Pop()))
-			bm.stack.Push(base.String())
+			base.Sub(Pow256, bm.stack.Pop())
+			bm.stack.Push(base)
 		case oLT:
 			x, y := bm.stack.Popn()
 			// x < y
 			if x.Cmp(y) < 0 {
-				bm.stack.Push("1")
+				bm.stack.Push(ethutil.BigTrue)
 			} else {
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.BigFalse)
 			}
 		case oLE:
 			x, y := bm.stack.Popn()
 			// x <= y
 			if x.Cmp(y) < 1 {
-				bm.stack.Push("1")
+				bm.stack.Push(ethutil.BigTrue)
 			} else {
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.BigFalse)
 			}
 		case oGT:
 			x, y := bm.stack.Popn()
 			// x > y
 			if x.Cmp(y) > 0 {
-				bm.stack.Push("1")
+				bm.stack.Push(ethutil.BigTrue)
 			} else {
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.BigFalse)
 			}
 		case oGE:
 			x, y := bm.stack.Popn()
 			// x >= y
 			if x.Cmp(y) > -1 {
-				bm.stack.Push("1")
+				bm.stack.Push(ethutil.BigTrue)
 			} else {
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.BigFalse)
 			}
 		case oNOT:
 			x, y := bm.stack.Popn()
 			// x != y
 			if x.Cmp(y) != 0 {
-				bm.stack.Push("1")
+				bm.stack.Push(ethutil.BigTrue)
 			} else {
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.BigFalse)
 			}
 
 		// 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()))
+			bm.stack.Push(ethutil.BigD(tx.Hash()))
 		case oTXSENDER:
-			bm.stack.Push(string(tx.Sender()))
+			bm.stack.Push(ethutil.BigD(tx.Sender()))
 		case oTXVALUE:
-			bm.stack.Push(tx.Value.String())
+			bm.stack.Push(tx.Value)
 		case oTXDATAN:
-			bm.stack.Push(big.NewInt(int64(len(tx.Data))).String())
+			bm.stack.Push(big.NewInt(int64(len(tx.Data))))
 		case oTXDATA:
-			v := ethutil.Big(bm.stack.Pop())
+			v := 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())
+				bm.stack.Push(ethutil.Big("0"))
 			} else {
-				bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()]).String())
+				bm.stack.Push(ethutil.Big(tx.Data[v.Uint64()]))
 			}
 		case oBLK_PREVHASH:
-			bm.stack.Push(string(block.PrevHash))
+			bm.stack.Push(ethutil.Big(block.PrevHash))
 		case oBLK_COINBASE:
-			bm.stack.Push(block.Coinbase)
+			bm.stack.Push(ethutil.Big(block.Coinbase))
 		case oBLK_TIMESTAMP:
-			bm.stack.Push(big.NewInt(block.Time).String())
+			bm.stack.Push(big.NewInt(block.Time))
 		case oBLK_NUMBER:
-			bm.stack.Push(blockInfo.Number.String())
+			bm.stack.Push(blockInfo.Number)
 		case oBLK_DIFFICULTY:
-			bm.stack.Push(block.Difficulty.String())
+			bm.stack.Push(block.Difficulty)
 		case oBASEFEE:
 			// e = 10^21
 			e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0))
@@ -429,23 +428,23 @@ out:
 			x.Div(e, base)
 
 			// x = floor(10^21 / floor(diff^0.5))
-			bm.stack.Push(x.String())
+			bm.stack.Push(x)
 		case oSHA256, oRIPEMD160:
 			// This is probably save
 			// ceil(pop / 32)
-			length := int(math.Ceil(float64(ethutil.Big(bm.stack.Pop()).Uint64()) / 32.0))
+			length := int(math.Ceil(float64(bm.stack.Pop().Uint64()) / 32.0))
 			// New buffer which will contain the concatenated popped items
 			data := new(bytes.Buffer)
 			for i := 0; i < length; i++ {
 				// Encode the number to bytes and have it 32bytes long
-				num := ethutil.NumberToBytes(ethutil.Big(bm.stack.Pop()).Bytes(), 256)
+				num := ethutil.NumberToBytes(bm.stack.Pop().Bytes(), 256)
 				data.WriteString(string(num))
 			}
 
 			if op == oSHA256 {
-				bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes())).String())
+				bm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes())))
 			} else {
-				bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes())).String())
+				bm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes())))
 			}
 		case oECMUL:
 			y := bm.stack.Pop()
@@ -454,14 +453,14 @@ out:
 
 			//if ethutil.Big(x).Cmp(ethutil.Big(y)) {
 			data := new(bytes.Buffer)
-			data.WriteString(x)
-			data.WriteString(y)
+			data.WriteString(x.String())
+			data.WriteString(y.String())
 			if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 {
 				// TODO
 			} else {
 				// Invalid, push infinity
-				bm.stack.Push("0")
-				bm.stack.Push("0")
+				bm.stack.Push(ethutil.Big("0"))
+				bm.stack.Push(ethutil.Big("0"))
 			}
 			//} else {
 			//	// Invalid, push infinity
@@ -475,31 +474,59 @@ out:
 		case oECVALID:
 		case oSHA3:
 		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))))
+			bm.stack.Push(bm.mem[strconv.Itoa(pc)])
 		case oPOP:
 			// Pop current value of the stack
 			bm.stack.Pop()
 		case oDUP:
+			// Dup top stack
+			x := bm.stack.Pop()
+			bm.stack.Push(x)
+			bm.stack.Push(x)
 		case oSWAP:
+			// Swap two top most values
+			x, y := bm.stack.Popn()
+			bm.stack.Push(y)
+			bm.stack.Push(x)
 		case oMLOAD:
+			x := bm.stack.Pop()
+			bm.stack.Push(bm.mem[x.String()])
 		case oMSTORE:
+			x, y := bm.stack.Popn()
+			bm.mem[x.String()] = y
 		case oSLOAD:
+			// Load the value in storage and push it on the stack
+			x := bm.stack.Pop()
+			// decode the object as a big integer
+			decoder := ethutil.NewRlpDecoder([]byte(contract.State().Get(x.String())))
+			if !decoder.IsNil() {
+				bm.stack.Push(decoder.AsBigInt())
+			} else {
+				bm.stack.Push(ethutil.BigFalse)
+			}
 		case oSSTORE:
+			// Store Y at index X
+			x, y := bm.stack.Popn()
+			contract.State().Update(x.String(), string(ethutil.Encode(y)))
 		case oJMP:
+			x := int(bm.stack.Pop().Uint64())
+			// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
+			pc = x
+			pc--
 		case oJMPI:
+			x := bm.stack.Pop()
+			// Set pc to x if it's non zero
+			if x.Cmp(ethutil.BigFalse) != 0 {
+				pc = int(x.Uint64())
+				pc--
+			}
 		case oIND:
+			bm.stack.Push(big.NewInt(int64(pc)))
 		case oEXTRO:
 		case oBALANCE:
 		case oMKTX:
 		case oSUICIDE:
-			/*
-				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))))
-			*/
 		}
 		pc++
 	}
diff --git a/stack.go b/stack.go
index cee98555b..9d595d85b 100644
--- a/stack.go
+++ b/stack.go
@@ -2,7 +2,6 @@ package main
 
 import (
 	"fmt"
-	"github.com/ethereum/ethutil-go"
 	"math/big"
 )
 
@@ -135,14 +134,14 @@ type TxCallback func(opType OpType) bool
 
 // Simple push/pop stack mechanism
 type Stack struct {
-	data []string
+	data []*big.Int
 }
 
 func NewStack() *Stack {
 	return &Stack{}
 }
 
-func (st *Stack) Pop() string {
+func (st *Stack) Pop() *big.Int {
 	s := len(st.data)
 
 	str := st.data[s-1]
@@ -154,13 +153,13 @@ func (st *Stack) Pop() string {
 func (st *Stack) Popn() (*big.Int, *big.Int) {
 	s := len(st.data)
 
-	strs := st.data[s-2:]
+	ints := st.data[s-2:]
 	st.data = st.data[:s-2]
 
-	return ethutil.Big(strs[0]), ethutil.Big(strs[1])
+	return ints[0], ints[1]
 }
 
-func (st *Stack) Push(d string) {
+func (st *Stack) Push(d *big.Int) {
 	st.data = append(st.data, d)
 }
 func (st *Stack) Print() {
-- 
cgit v1.2.3