forked from cerc-io/plugeth
WIP rewrite vm
This commit is contained in:
parent
5b3d4fae6e
commit
9df4c74511
38
block.go
38
block.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) {
|
||||||
|
23
testing.go
23
testing.go
@ -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
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:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
27
vm_test.go
Normal file
27
vm_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user