More opcodes

This commit is contained in:
obscuren 2014-01-19 00:35:32 +01:00
parent ee61cfcfa7
commit 489576b6f0
2 changed files with 85 additions and 59 deletions

@ -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++
}

@ -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() {