aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorobscuren <obscuren@obscura.com>2014-01-03 06:02:24 +0800
committerobscuren <obscuren@obscura.com>2014-01-03 06:02:24 +0800
commit9df4c745119b3ed10a7ad17887e8dd9cac249af7 (patch)
tree8ae82afaf78a225d685a146a4cc67a77d3ca773d
parent5b3d4fae6e03e5471a10c653fc0b016cc5e5dcfa (diff)
downloadgo-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar.gz
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar.bz2
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar.lz
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar.xz
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.tar.zst
go-tangerine-9df4c745119b3ed10a7ad17887e8dd9cac249af7.zip
WIP rewrite vm
-rw-r--r--block.go38
-rw-r--r--block_manager.go6
-rw-r--r--parsing.go3
-rw-r--r--parsing_test.go13
-rw-r--r--testing.go23
-rw-r--r--trie_test.go8
-rw-r--r--vm.go68
-rw-r--r--vm_test.go27
8 files changed, 150 insertions, 36 deletions
diff --git a/block.go b/block.go
index 9aa3c8bb5..146328471 100644
--- a/block.go
+++ b/block.go
@@ -15,6 +15,7 @@ type Block struct {
uncles []*Block
coinbase string
// state xxx
+ state *Trie
difficulty uint32
// Creation time
time int64
@@ -34,7 +35,7 @@ func NewBlock(raw []byte) *Block {
}
// Creates a new block. This is currently for testing
-func CreateBlock(/* TODO use raw data */transactions []*Transaction) *Block {
+func CreateTestBlock(/* TODO use raw data */transactions []*Transaction) *Block {
block := &Block{
// Slice of transactions to include in this block
transactions: transactions,
@@ -49,12 +50,32 @@ func CreateBlock(/* TODO use raw data */transactions []*Transaction) *Block {
return block
}
+func CreateBlock(root string, num int, prevHash string, base string, difficulty int, nonce int, extra string, txes []*Transaction) *Block {
+ block := &Block{
+ // Slice of transactions to include in this block
+ transactions: txes,
+ number: uint32(num),
+ prevHash: prevHash,
+ coinbase: base,
+ difficulty: uint32(difficulty),
+ nonce: uint32(nonce),
+ time: time.Now().Unix(),
+ extra: extra,
+ }
+ block.state = NewTrie(Db, root)
+ for _, tx := range txes {
+ block.state.Update(tx.recipient, string(tx.MarshalRlp()))
+ }
+
+ return block
+}
+
func (block *Block) Update() {
}
// Returns a hash of the block
-func (block *Block) Hash() string {
- return Sha256Hex(block.MarshalRlp())
+func (block *Block) Hash() []byte {
+ return Sha256Bin(block.MarshalRlp())
}
func (block *Block) MarshalRlp() []byte {
@@ -73,7 +94,7 @@ func (block *Block) MarshalRlp() []byte {
"",
block.coinbase,
// root state
- "",
+ block.state.root,
// Sha of tx
string(Sha256Bin([]byte(Encode(encTx)))),
block.difficulty,
@@ -99,7 +120,7 @@ func (block *Block) UnmarshalRlp(data []byte) {
block.number = uint32(number)
}
- if prevHash, ok := header[1].([]byte); ok {
+ if prevHash, ok := header[1].([]uint8); ok {
block.prevHash = string(prevHash)
}
@@ -109,7 +130,12 @@ func (block *Block) UnmarshalRlp(data []byte) {
block.coinbase = string(coinbase)
}
- // state is header[header[4]
+ if state, ok := header[4].([]uint8); ok {
+ // XXX The database is currently a global variable defined in testing.go
+ // This will eventually go away and the database will grabbed from the public server
+ // interface
+ block.state = NewTrie(Db, string(state))
+ }
// sha is header[5]
diff --git a/block_manager.go b/block_manager.go
index a60d4340d..0ef5d1108 100644
--- a/block_manager.go
+++ b/block_manager.go
@@ -33,7 +33,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
// Process each transaction/contract
for _, tx := range block.transactions {
- go bm.ProcessTransaction(tx, lockChan)
+ go bm.ProcessTransaction(tx, block, lockChan)
}
// Wait for all Tx to finish processing
@@ -44,9 +44,9 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
return nil
}
-func (bm *BlockManager) ProcessTransaction(tx *Transaction, lockChan chan bool) {
+func (bm *BlockManager) ProcessTransaction(tx *Transaction, block *Block, lockChan chan bool) {
if tx.recipient == "\x00" {
- bm.vm.RunTransaction(tx, func(opType OpType) bool {
+ bm.vm.RunTransaction(tx, block, func(opType OpType) bool {
// TODO calculate fees
return true // Continue
diff --git a/parsing.go b/parsing.go
index d5dcce04f..765950a4c 100644
--- a/parsing.go
+++ b/parsing.go
@@ -11,6 +11,8 @@ import (
// Op codes
var OpCodes = map[string]string{
"STOP": "0",
+ "PSH": "30", // 0x30
+ /*
"ADD": "16", // 0x10
"SUB": "17", // 0x11
"MUL": "18", // 0x12
@@ -48,6 +50,7 @@ var OpCodes = map[string]string{
"BLKHASH": "145", // 0x91
"COINBASE": "146", // 0x92
"SUICIDE": "255", // 0xff
+ */
}
diff --git a/parsing_test.go b/parsing_test.go
index 93fe434b9..fa319e7bf 100644
--- a/parsing_test.go
+++ b/parsing_test.go
@@ -19,22 +19,13 @@ func TestCompile(t *testing.T) {
}
func TestValidInstr(t *testing.T) {
+ /*
op, args, err := Instr("68163")
if err != nil {
t.Error("Error decoding instruction")
}
+ */
- if op != oSET {
- t.Error("Expected op to be 43, got:", op)
- }
-
- if args[0] != "10" {
- t.Error("Expect args[0] to be 10, got:", args[0])
- }
-
- if args[1] != "1" {
- t.Error("Expected args[1] to be 1, got:", args[1])
- }
}
func TestInvalidInstr(t *testing.T) {
diff --git a/testing.go b/testing.go
index 5d0b818a9..07e8c362f 100644
--- a/testing.go
+++ b/testing.go
@@ -4,22 +4,17 @@ import (
"fmt"
)
+// This will eventually go away
+var Db *MemDatabase
+
func Testing() {
+ db, _ := NewMemDatabase()
+ Db = db
+
bm := NewBlockManager()
tx := NewTransaction("\x00", 20, []string{
- "SET 10 6",
- "LD 10 10",
- "LT 10 1 20",
- "SET 255 7",
- "JMPI 20 255",
- "STOP",
- "SET 30 200",
- "LD 30 31",
- "SET 255 22",
- "JMPI 31 255",
- "SET 255 15",
- "JMP 255",
+ "PSH 10",
})
txData := tx.MarshalRlp()
@@ -28,9 +23,9 @@ func Testing() {
tx2 := NewTransaction("\x00", 20, []string{"SET 10 6", "LD 10 10"})
- blck := CreateBlock([]*Transaction{tx2, tx})
+ blck := CreateTestBlock([]*Transaction{tx2, tx})
bm.ProcessBlock( blck )
- fmt.Println("GenesisBlock:", GenisisBlock, "hashed", GenisisBlock.Hash())
+ fmt.Println("GenesisBlock:", GenisisBlock, "hash", string(GenisisBlock.Hash()))
}
diff --git a/trie_test.go b/trie_test.go
index 6dbe040ee..599a5f47c 100644
--- a/trie_test.go
+++ b/trie_test.go
@@ -3,6 +3,7 @@ package main
import (
"testing"
"encoding/hex"
+ _"fmt"
)
func TestTriePut(t *testing.T) {
@@ -41,6 +42,13 @@ func TestTrieUpdate(t *testing.T) {
trie.Update("doe", "reindeer")
trie.Update("dog", "puppy")
+ /*
+ data, _ := db.Get([]byte(trie.root))
+ data, _ = db.Get([]byte(DecodeNode(data)[1]))
+ data, _ = db.Get([]byte(DecodeNode(data)[7]))
+ PrintSlice(DecodeNode(data))
+ */
+
trie.Update("dogglesworth", "cat")
root := hex.EncodeToString([]byte(trie.root))
req := "e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c"
diff --git a/vm.go b/vm.go
index 787e29295..f38e7be06 100644
--- a/vm.go
+++ b/vm.go
@@ -1,16 +1,18 @@
package main
import (
- "math"
+ _"math"
"math/big"
"fmt"
- "strconv"
+ _"strconv"
_ "encoding/hex"
)
// Op codes
const (
oSTOP int = 0x00
+ oPSH int = 0x30
+ /*
oADD int = 0x10
oSUB int = 0x11
oMUL int = 0x12
@@ -46,6 +48,7 @@ const (
oDATAN int = 0x81
oMYADDRESS int = 0x90
oSUICIDE int = 0xff
+ */
)
type OpType int
@@ -57,6 +60,66 @@ const (
)
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]
+ st.data = st.data[:s-1]
+
+ return str
+}
+
+func (st *Stack) Push(d string) {
+ st.data = append(st.data, d)
+}
+
+type Vm struct {
+ // Stack
+ stack *Stack
+}
+
+func NewVm() *Vm {
+ return &Vm{
+ stack: NewStack(),
+ }
+}
+
+func (vm *Vm) RunTransaction(tx *Transaction, block *Block, cb TxCallback) {
+ // Instruction pointer
+ iptr := 0
+
+ // Index pointer for the memory
+ memIndex := 0
+
+ fmt.Printf("# op arg\n")
+ for iptr < len(tx.data) {
+ memIndex++
+ // The base big int for all calculations. Use this for any results.
+ base := new(big.Int)
+ base.SetString("0",0) // so it doesn't whine about it
+ // XXX Should Instr return big int slice instead of string slice?
+ op, args, _ := Instr(tx.data[iptr])
+
+ if Debug {
+ fmt.Printf("%-3d %-4d %v\n", iptr, op, args)
+ }
+
+ switch op {
+ case oPSH:
+ }
+ // Increment instruction pointer
+ iptr++
+ }
+}
+
+/*
type Vm struct {
// Memory stack
stack map[string]string
@@ -183,3 +246,4 @@ out:
}
}
}
+*/
diff --git a/vm_test.go b/vm_test.go
new file mode 100644
index 000000000..d0bcda2ca
--- /dev/null
+++ b/vm_test.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+ _"encoding/hex"
+)
+
+
+func TestVm(t *testing.T) {
+ db, _ := NewMemDatabase()
+ Db = db
+
+ tx := NewTransaction("\x00", 20, []string{
+ "PSH 10",
+ })
+
+ block := CreateBlock("", 0, "", "", 0, 0, "", []*Transaction{tx})
+ db.Put(block.Hash(), block.MarshalRlp())
+
+ bm := NewBlockManager()
+ bm.ProcessBlock( block )
+ tx1 := &Transaction{}
+ tx1.UnmarshalRlp([]byte(block.state.Get(tx.recipient)))
+ fmt.Println(tx1)
+}
+