WIP rewrite vm

This commit is contained in:
obscuren 2014-01-02 23:02:24 +01:00
parent 5b3d4fae6e
commit 9df4c74511
8 changed files with 150 additions and 36 deletions

View File

@ -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]

View File

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

View File

@ -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
*/
}

View File

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

View File

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

View File

@ -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"

68
vm.go
View File

@ -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:
}
}
}
*/

27
vm_test.go Normal file
View File

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