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
|
||||
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]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
23
testing.go
23
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()))
|
||||
}
|
||||
|
@ -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
68
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:
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
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