From 489576b6f04585b33c8aedd8aa6e5a8d54e1a960 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 19 Jan 2014 00:35:32 +0100 Subject: [PATCH] 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() {