diff --git a/block.go b/block.go index 9aa3c8bb56..146328471b 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 a60d4340d8..0ef5d11082 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 d5dcce04fa..765950a4c7 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 93fe434b9a..fa319e7bf9 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 5d0b818a90..07e8c362fa 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 6dbe040ee1..599a5f47cf 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 787e29295b..f38e7be06b 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 0000000000..d0bcda2cab --- /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) +} +