WIP rewrite vm

pull/2/head
obscuren 11 years ago
parent 5b3d4fae6e
commit 9df4c74511
  1. 38
      block.go
  2. 6
      block_manager.go
  3. 3
      parsing.go
  4. 13
      parsing_test.go
  5. 23
      testing.go
  6. 8
      trie_test.go
  7. 68
      vm.go
  8. 27
      vm_test.go

@ -15,6 +15,7 @@ type Block struct {
uncles []*Block uncles []*Block
coinbase string coinbase string
// state xxx // state xxx
state *Trie
difficulty uint32 difficulty uint32
// Creation time // Creation time
time int64 time int64
@ -34,7 +35,7 @@ func NewBlock(raw []byte) *Block {
} }
// Creates a new block. This is currently for testing // 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{ block := &Block{
// Slice of transactions to include in this block // Slice of transactions to include in this block
transactions: transactions, transactions: transactions,
@ -49,12 +50,32 @@ func CreateBlock(/* TODO use raw data */transactions []*Transaction) *Block {
return 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() { func (block *Block) Update() {
} }
// Returns a hash of the block // Returns a hash of the block
func (block *Block) Hash() string { func (block *Block) Hash() []byte {
return Sha256Hex(block.MarshalRlp()) return Sha256Bin(block.MarshalRlp())
} }
func (block *Block) MarshalRlp() []byte { func (block *Block) MarshalRlp() []byte {
@ -73,7 +94,7 @@ func (block *Block) MarshalRlp() []byte {
"", "",
block.coinbase, block.coinbase,
// root state // root state
"", block.state.root,
// Sha of tx // Sha of tx
string(Sha256Bin([]byte(Encode(encTx)))), string(Sha256Bin([]byte(Encode(encTx)))),
block.difficulty, block.difficulty,
@ -99,7 +120,7 @@ func (block *Block) UnmarshalRlp(data []byte) {
block.number = uint32(number) block.number = uint32(number)
} }
if prevHash, ok := header[1].([]byte); ok { if prevHash, ok := header[1].([]uint8); ok {
block.prevHash = string(prevHash) block.prevHash = string(prevHash)
} }
@ -109,7 +130,12 @@ func (block *Block) UnmarshalRlp(data []byte) {
block.coinbase = string(coinbase) 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] // sha is header[5]

@ -33,7 +33,7 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
// Process each transaction/contract // Process each transaction/contract
for _, tx := range block.transactions { for _, tx := range block.transactions {
go bm.ProcessTransaction(tx, lockChan) go bm.ProcessTransaction(tx, block, lockChan)
} }
// Wait for all Tx to finish processing // Wait for all Tx to finish processing
@ -44,9 +44,9 @@ func (bm *BlockManager) ProcessBlock(block *Block) error {
return nil 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" { if tx.recipient == "\x00" {
bm.vm.RunTransaction(tx, func(opType OpType) bool { bm.vm.RunTransaction(tx, block, func(opType OpType) bool {
// TODO calculate fees // TODO calculate fees
return true // Continue return true // Continue

@ -11,6 +11,8 @@ import (
// Op codes // Op codes
var OpCodes = map[string]string{ var OpCodes = map[string]string{
"STOP": "0", "STOP": "0",
"PSH": "30", // 0x30
/*
"ADD": "16", // 0x10 "ADD": "16", // 0x10
"SUB": "17", // 0x11 "SUB": "17", // 0x11
"MUL": "18", // 0x12 "MUL": "18", // 0x12
@ -48,6 +50,7 @@ var OpCodes = map[string]string{
"BLKHASH": "145", // 0x91 "BLKHASH": "145", // 0x91
"COINBASE": "146", // 0x92 "COINBASE": "146", // 0x92
"SUICIDE": "255", // 0xff "SUICIDE": "255", // 0xff
*/
} }

@ -19,22 +19,13 @@ func TestCompile(t *testing.T) {
} }
func TestValidInstr(t *testing.T) { func TestValidInstr(t *testing.T) {
/*
op, args, err := Instr("68163") op, args, err := Instr("68163")
if err != nil { if err != nil {
t.Error("Error decoding instruction") 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) { func TestInvalidInstr(t *testing.T) {

@ -4,22 +4,17 @@ import (
"fmt" "fmt"
) )
// This will eventually go away
var Db *MemDatabase
func Testing() { func Testing() {
db, _ := NewMemDatabase()
Db = db
bm := NewBlockManager() bm := NewBlockManager()
tx := NewTransaction("\x00", 20, []string{ tx := NewTransaction("\x00", 20, []string{
"SET 10 6", "PSH 10",
"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",
}) })
txData := tx.MarshalRlp() txData := tx.MarshalRlp()
@ -28,9 +23,9 @@ func Testing() {
tx2 := NewTransaction("\x00", 20, []string{"SET 10 6", "LD 10 10"}) tx2 := NewTransaction("\x00", 20, []string{"SET 10 6", "LD 10 10"})
blck := CreateBlock([]*Transaction{tx2, tx}) blck := CreateTestBlock([]*Transaction{tx2, tx})
bm.ProcessBlock( blck ) bm.ProcessBlock( blck )
fmt.Println("GenesisBlock:", GenisisBlock, "hashed", GenisisBlock.Hash()) fmt.Println("GenesisBlock:", GenisisBlock, "hash", string(GenisisBlock.Hash()))
} }

@ -3,6 +3,7 @@ package main
import ( import (
"testing" "testing"
"encoding/hex" "encoding/hex"
_"fmt"
) )
func TestTriePut(t *testing.T) { func TestTriePut(t *testing.T) {
@ -41,6 +42,13 @@ func TestTrieUpdate(t *testing.T) {
trie.Update("doe", "reindeer") trie.Update("doe", "reindeer")
trie.Update("dog", "puppy") 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") trie.Update("dogglesworth", "cat")
root := hex.EncodeToString([]byte(trie.root)) root := hex.EncodeToString([]byte(trie.root))
req := "e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c" req := "e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c"

68
vm.go

@ -1,16 +1,18 @@
package main package main
import ( import (
"math" _"math"
"math/big" "math/big"
"fmt" "fmt"
"strconv" _"strconv"
_ "encoding/hex" _ "encoding/hex"
) )
// Op codes // Op codes
const ( const (
oSTOP int = 0x00 oSTOP int = 0x00
oPSH int = 0x30
/*
oADD int = 0x10 oADD int = 0x10
oSUB int = 0x11 oSUB int = 0x11
oMUL int = 0x12 oMUL int = 0x12
@ -46,6 +48,7 @@ const (
oDATAN int = 0x81 oDATAN int = 0x81
oMYADDRESS int = 0x90 oMYADDRESS int = 0x90
oSUICIDE int = 0xff oSUICIDE int = 0xff
*/
) )
type OpType int type OpType int
@ -57,6 +60,66 @@ const (
) )
type TxCallback func(opType OpType) bool 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 { type Vm struct {
// Memory stack // Memory stack
stack map[string]string stack map[string]string
@ -183,3 +246,4 @@ out:
} }
} }
} }
*/

@ -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)
}
Loading…
Cancel
Save