From 8c4eca2490fc19a488ffb5fe1160a2ae695d018f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 16 Jan 2014 18:12:55 +0100 Subject: [PATCH] Moved the vm code the block manager and added more opcodes --- block_manager.go | 91 ++++++++++++--- vm.go | 284 ----------------------------------------------- vm_test.go | 76 ------------- 3 files changed, 77 insertions(+), 374 deletions(-) delete mode 100644 vm.go delete mode 100644 vm_test.go diff --git a/block_manager.go b/block_manager.go index 7b2d01f29b..4ddc3952b3 100644 --- a/block_manager.go +++ b/block_manager.go @@ -6,14 +6,14 @@ import ( "github.com/ethereum/ethutil-go" "log" "math/big" - "strconv" ) type BlockChain struct { + // Last block LastBlock *ethutil.Block - + // The famous, the fabulous Mister GENESIIIIIIS (block) genesisBlock *ethutil.Block - + // Last known total difficulty TD *big.Int } @@ -22,11 +22,10 @@ func NewBlockChain() *BlockChain { bc.genesisBlock = ethutil.NewBlock(ethutil.Encode(ethutil.Genesis)) // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = new(big.Int) - bc.TD.SetBytes(ethutil.Config.Db.LastKnownTD()) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) // TODO get last block from the database - //bc.LastBlock = bc.genesisBlock + bc.LastBlock = bc.genesisBlock return bc } @@ -46,6 +45,9 @@ type BlockManager struct { // Stack for processing contracts stack *Stack + + // Last known block number + LastBlockNumber *big.Int } func NewBlockManager() *BlockManager { @@ -54,6 +56,10 @@ func NewBlockManager() *BlockManager { stack: NewStack(), } + // Set the last known block number based on the blockchains last + // block + bm.LastBlockNumber = bm.BlockInfo(bm.bc.LastBlock).Number + return bm } @@ -99,6 +105,20 @@ func (bm *BlockManager) ProcessBlock(block *ethutil.Block) error { return nil } +func (bm *BlockManager) writeBlockInfo(block *ethutil.Block) { + bi := ethutil.BlockInfo{Number: bm.LastBlockNumber.Add(bm.LastBlockNumber, big.NewInt(1))} + + ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.MarshalRlp()) +} + +func (bm *BlockManager) BlockInfo(block *ethutil.Block) ethutil.BlockInfo { + bi := ethutil.BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.UnmarshalRlp(data) + + return bi +} + func (bm *BlockManager) CalculateTD(block *ethutil.Block) bool { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { @@ -204,10 +224,11 @@ func (bm *BlockManager) ProcessContract(tx *ethutil.Transaction, block *ethutil. lockChan <- true } -func (bm *BlockManager) ProcContract(tx *ethutil.Transaction, - block *ethutil.Block, cb TxCallback) { +// Contract evaluation is done here. +func (bm *BlockManager) ProcContract(tx *ethutil.Transaction, block *ethutil.Block, cb TxCallback) { // Instruction pointer pc := 0 + blockInfo := bm.BlockInfo(block) contract := block.GetContract(tx.Hash()) if contract == nil { @@ -238,6 +259,8 @@ out: } switch op { + case oSTOP: + break out case oADD: x, y := bm.stack.Popn() // (x + y) % 2 ** 256 @@ -378,7 +401,34 @@ out: case oBLK_TIMESTAMP: bm.stack.Push(big.NewInt(block.Time).String()) case oBLK_NUMBER: + bm.stack.Push(blockInfo.Number.String()) + case oBLK_DIFFICULTY: + bm.stack.Push(block.Difficulty.String()) + case oBASEFEE: + // e = 10^21 + e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) + d := new(big.Rat) + d.SetInt(block.Difficulty) + c := new(big.Rat) + c.SetFloat64(0.5) + // d = diff / 0.5 + d.Quo(d, c) + // base = floor(d) + base.Div(d.Num(), d.Denom()) + x := new(big.Int) + x.Div(e, base) + + // x = floor(10^21 / floor(diff^0.5)) + bm.stack.Push(x.String()) + case oSHA256: + case oRIPEMD160: + case oECMUL: + case oECADD: + case oECSIGN: + case oECRECOVER: + case oECVALID: + case oSHA3: case oPUSH: // Get the next entry and pushes the value on the stack pc++ @@ -386,12 +436,25 @@ out: 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 + case oDUP: + case oSWAP: + case oMLOAD: + case oMSTORE: + case oSLOAD: + case oSSTORE: + case oJMP: + case oJMPI: + case oIND: + 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/vm.go b/vm.go deleted file mode 100644 index 96a3dfa05a..0000000000 --- a/vm.go +++ /dev/null @@ -1,284 +0,0 @@ -package main - -import ( - "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 -) - -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) -} - -type Vm struct { - // Stack - stack *Stack -} - -func NewVm() *Vm { - return &Vm{ - stack: NewStack(), - } -} - -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 - } - - 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) - op, _, _ := ethutil.Instr(contract.State().Get(string(nb))) - - if !cb(0) { - break - } - - 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) - - 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() -} diff --git a/vm_test.go b/vm_test.go deleted file mode 100644 index cb70220e1c..0000000000 --- a/vm_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -/* -import ( - _"fmt" - "testing" -) - - -func TestVm(t *testing.T) { - InitFees() - - db, _ := NewMemDatabase() - Db = db - - ctrct := NewTransaction("", 200000000, []string{ - "PUSH", "1a2f2e", - "PUSH", "hallo", - "POP", // POP hallo - "PUSH", "3", - "LOAD", // Load hallo back on the stack - - "PUSH", "1", - "PUSH", "2", - "ADD", - - "PUSH", "2", - "PUSH", "1", - "SUB", - - "PUSH", "100000000000000000000000", - "PUSH", "10000000000000", - "SDIV", - - "PUSH", "105", - "PUSH", "200", - "MOD", - - "PUSH", "100000000000000000000000", - "PUSH", "10000000000000", - "SMOD", - - "PUSH", "5", - "PUSH", "10", - "LT", - - "PUSH", "5", - "PUSH", "5", - "LE", - - "PUSH", "50", - "PUSH", "5", - "GT", - - "PUSH", "5", - "PUSH", "5", - "GE", - - "PUSH", "10", - "PUSH", "10", - "NOT", - - "MYADDRESS", - "TXSENDER", - - "STOP", - }) - tx := NewTransaction("1e8a42ea8cce13", 100, []string{}) - - block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx}) - db.Put(block.Hash(), block.MarshalRlp()) - - bm := NewBlockManager() - bm.ProcessBlock( block ) -} -*/