aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-01-17 01:12:55 +0800
committerobscuren <geffobscura@gmail.com>2014-01-17 01:12:55 +0800
commit8c4eca2490fc19a488ffb5fe1160a2ae695d018f (patch)
tree2d912c02d1a8d1e403a88e92efd678180055f738
parent33004d704e4a77368e5b2b415cfee3f05a3b469f (diff)
downloadgo-tangerine-8c4eca2490fc19a488ffb5fe1160a2ae695d018f.tar.gz
go-tangerine-8c4eca2490fc19a488ffb5fe1160a2ae695d018f.tar.zst
go-tangerine-8c4eca2490fc19a488ffb5fe1160a2ae695d018f.zip
Moved the vm code the block manager and added more opcodes
-rw-r--r--block_manager.go93
-rw-r--r--vm.go284
-rw-r--r--vm_test.go76
3 files changed, 78 insertions, 375 deletions
diff --git a/block_manager.go b/block_manager.go
index 7b2d01f29..4ddc3952b 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 96a3dfa05..000000000
--- 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 cb70220e1..000000000
--- 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 )
-}
-*/