forked from cerc-io/plugeth
Updated stack based vm
This commit is contained in:
parent
6ab61f2c52
commit
2d3c3674fa
63
parsing.go
63
parsing.go
@ -11,49 +11,28 @@ import (
|
|||||||
// Op codes
|
// Op codes
|
||||||
var OpCodes = map[string]string{
|
var OpCodes = map[string]string{
|
||||||
"STOP": "0",
|
"STOP": "0",
|
||||||
"PUSH": "48", // 0x30
|
"ADD": "1",
|
||||||
"POP": "49", // 0x31
|
"MUL": "2",
|
||||||
"LOAD": "54", // 0x36
|
"SUB": "3",
|
||||||
|
"DIV": "4",
|
||||||
|
"SDIV": "5",
|
||||||
|
"MOD": "6",
|
||||||
|
"SMOD": "7",
|
||||||
|
"EXP": "8",
|
||||||
|
"NEG": "9",
|
||||||
|
"LT": "10",
|
||||||
|
"LE": "11",
|
||||||
|
"GT": "12",
|
||||||
|
"GE": "13",
|
||||||
|
"EQ": "14",
|
||||||
|
"NOT": "15",
|
||||||
|
"MYADDRESS": "16",
|
||||||
|
"TXSENDER": "17",
|
||||||
|
|
||||||
/* OLD VM OPCODES
|
|
||||||
"ADD": "16", // 0x10
|
"PUSH": "48",
|
||||||
"SUB": "17", // 0x11
|
"POP": "49",
|
||||||
"MUL": "18", // 0x12
|
"LOAD": "54",
|
||||||
"DIV": "19", // 0x13
|
|
||||||
"SDIV": "20", // 0x14
|
|
||||||
"MOD": "21", // 0x15
|
|
||||||
"SMOD": "22", // 0x16
|
|
||||||
"EXP": "23", // 0x17
|
|
||||||
"NEG": "24", // 0x18
|
|
||||||
"LT": "32", // 0x20
|
|
||||||
"LE": "33", // 0x21
|
|
||||||
"GT": "34", // 0x22
|
|
||||||
"GE": "35", // 0x23
|
|
||||||
"EQ": "36", // 0x24
|
|
||||||
"NOT": "37", // 0x25
|
|
||||||
"SHA256": "48", // 0x30
|
|
||||||
"RIPEMD160": "49", // 0x31
|
|
||||||
"ECMUL": "50", // 0x32
|
|
||||||
"ECADD": "51", // 0x33
|
|
||||||
"SIGN": "52", // 0x34
|
|
||||||
"RECOVER": "53", // 0x35
|
|
||||||
"COPY": "64", // 0x40
|
|
||||||
"ST": "65", // 0x41
|
|
||||||
"LD": "66", // 0x42
|
|
||||||
"SET": "67", // 0x43
|
|
||||||
"JMP": "80", // 0x50
|
|
||||||
"JMPI": "81", // 0x51
|
|
||||||
"IND": "82", // 0x52
|
|
||||||
"EXTRO": "96", // 0x60
|
|
||||||
"BALANCE": "97", // 0x61
|
|
||||||
"MKTX": "112", // 0x70
|
|
||||||
"DATA": "128", // 0x80
|
|
||||||
"DATAN": "129", // 0x81
|
|
||||||
"MYADDRESS": "144", // 0x90
|
|
||||||
"BLKHASH": "145", // 0x91
|
|
||||||
"COINBASE": "146", // 0x92
|
|
||||||
"SUICIDE": "255", // 0xff
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
320
vm.go
320
vm.go
@ -12,46 +12,28 @@ import (
|
|||||||
// Op codes
|
// Op codes
|
||||||
const (
|
const (
|
||||||
oSTOP int = 0x00
|
oSTOP int = 0x00
|
||||||
|
oADD int = 0x01
|
||||||
|
oMUL int = 0x02
|
||||||
|
oSUB int = 0x03
|
||||||
|
oDIV int = 0x04
|
||||||
|
oSDIV int = 0x05
|
||||||
|
oMOD int = 0x06
|
||||||
|
oSMOD int = 0x07
|
||||||
|
oEXP int = 0x08
|
||||||
|
oNEG int = 0x09
|
||||||
|
oLT int = 0x0a
|
||||||
|
oLE int = 0x0b
|
||||||
|
oGT int = 0x0c
|
||||||
|
oGE int = 0x0d
|
||||||
|
oEQ int = 0x0e
|
||||||
|
oNOT int = 0x0f
|
||||||
|
oMYADDRESS int = 0x10
|
||||||
|
oTXSENDER int = 0x11
|
||||||
|
|
||||||
|
|
||||||
oPUSH int = 0x30
|
oPUSH int = 0x30
|
||||||
oPOP int = 0x31
|
oPOP int = 0x31
|
||||||
oLOAD int = 0x36
|
oLOAD int = 0x36
|
||||||
/*
|
|
||||||
oADD int = 0x10
|
|
||||||
oSUB int = 0x11
|
|
||||||
oMUL int = 0x12
|
|
||||||
oDIV int = 0x13
|
|
||||||
oSDIV int = 0x14
|
|
||||||
oMOD int = 0x15
|
|
||||||
oSMOD int = 0x16
|
|
||||||
oEXP int = 0x17
|
|
||||||
oNEG int = 0x18
|
|
||||||
oLT int = 0x20
|
|
||||||
oLE int = 0x21
|
|
||||||
oGT int = 0x22
|
|
||||||
oGE int = 0x23
|
|
||||||
oEQ int = 0x24
|
|
||||||
oNOT int = 0x25
|
|
||||||
oSHA256 int = 0x30
|
|
||||||
oRIPEMD160 int = 0x31
|
|
||||||
oECMUL int = 0x32
|
|
||||||
oECADD int = 0x33
|
|
||||||
oSIGN int = 0x34
|
|
||||||
oRECOVER int = 0x35
|
|
||||||
oCOPY int = 0x40
|
|
||||||
oST int = 0x41
|
|
||||||
oLD int = 0x42
|
|
||||||
oSET int = 0x43
|
|
||||||
oJMP int = 0x50
|
|
||||||
oJMPI int = 0x51
|
|
||||||
oIND int = 0x52
|
|
||||||
oEXTRO int = 0x60
|
|
||||||
oBALANCE int = 0x61
|
|
||||||
oMKTX int = 0x70
|
|
||||||
oDATA int = 0x80
|
|
||||||
oDATAN int = 0x81
|
|
||||||
oMYADDRESS int = 0x90
|
|
||||||
oSUICIDE int = 0xff
|
|
||||||
*/
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpType int
|
type OpType int
|
||||||
@ -79,9 +61,21 @@ func (st *Stack) Pop() string {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (st *Stack) Popn() (*big.Int, *big.Int) {
|
||||||
|
s := len(st.data)
|
||||||
|
|
||||||
|
strs := st.data[s-2:]
|
||||||
|
st.data = st.data[:s-2]
|
||||||
|
|
||||||
|
return Big(strs[0]), Big(strs[1])
|
||||||
|
}
|
||||||
|
|
||||||
func (st *Stack) Push(d string) {
|
func (st *Stack) Push(d string) {
|
||||||
st.data = append(st.data, d)
|
st.data = append(st.data, d)
|
||||||
}
|
}
|
||||||
|
func (st *Stack) Print() {
|
||||||
|
fmt.Println(st.data)
|
||||||
|
}
|
||||||
|
|
||||||
type Vm struct {
|
type Vm struct {
|
||||||
// Stack
|
// Stack
|
||||||
@ -96,7 +90,7 @@ func NewVm() *Vm {
|
|||||||
|
|
||||||
func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
|
func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
|
||||||
// Instruction pointer
|
// Instruction pointer
|
||||||
iptr := 0
|
pc := 0
|
||||||
|
|
||||||
contract := block.GetContract(tx.Hash())
|
contract := block.GetContract(tx.Hash())
|
||||||
if contract == nil {
|
if contract == nil {
|
||||||
@ -104,164 +98,144 @@ func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pow256 := BigPow(2, 256)
|
||||||
|
|
||||||
fmt.Printf("# op arg\n")
|
fmt.Printf("# op arg\n")
|
||||||
out:
|
out:
|
||||||
for {
|
for {
|
||||||
// The base big int for all calculations. Use this for any results.
|
// The base big int for all calculations. Use this for any results.
|
||||||
base := new(big.Int)
|
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?
|
// XXX Should Instr return big int slice instead of string slice?
|
||||||
// Get the next instruction from the contract
|
// Get the next instruction from the contract
|
||||||
op, args, _ := Instr(contract.state.Get(string(Encode(uint32(iptr)))))
|
//op, _, _ := Instr(contract.state.Get(string(Encode(uint32(pc)))))
|
||||||
|
op, _, _ := Instr(contract.state.Get(string(NumberToBytes(uint64(pc), 32))))
|
||||||
|
|
||||||
|
if !cb(0) { break }
|
||||||
|
|
||||||
if Debug {
|
if Debug {
|
||||||
fmt.Printf("%-3d %-4d %v\n", iptr, op, args)
|
fmt.Printf("%-3d %-4d\n", pc, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
|
case oADD:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// (x + y) % 2 ** 256
|
||||||
|
base.Add(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oSUB:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// (x - y) % 2 ** 256
|
||||||
|
base.Sub(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oMUL:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// (x * y) % 2 ** 256
|
||||||
|
base.Mul(x, y)
|
||||||
|
base.Mod(base, Pow256)
|
||||||
|
// Pop result back on the stack
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oDIV:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// floor(x / y)
|
||||||
|
base.Div(x, y)
|
||||||
|
// Pop result back on the stack
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oSDIV:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// n > 2**255
|
||||||
|
if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) }
|
||||||
|
if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) }
|
||||||
|
z := new(big.Int)
|
||||||
|
z.Div(x, y)
|
||||||
|
if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) }
|
||||||
|
// Push result on to the stack
|
||||||
|
vm.stack.Push(z.String())
|
||||||
|
case oMOD:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
base.Mod(x, y)
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oSMOD:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// n > 2**255
|
||||||
|
if x.Cmp(Pow256) > 0 { x.Sub(Pow256, x) }
|
||||||
|
if y.Cmp(Pow256) > 0 { y.Sub(Pow256, y) }
|
||||||
|
z := new(big.Int)
|
||||||
|
z.Mod(x, y)
|
||||||
|
if z.Cmp(Pow256) > 0 { z.Sub(Pow256, z) }
|
||||||
|
// Push result on to the stack
|
||||||
|
vm.stack.Push(z.String())
|
||||||
|
case oEXP:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
base.Exp(x, y, Pow256)
|
||||||
|
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oNEG:
|
||||||
|
base.Sub(Pow256, Big(vm.stack.Pop()))
|
||||||
|
vm.stack.Push(base.String())
|
||||||
|
case oLT:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// x < y
|
||||||
|
if x.Cmp(y) < 0 {
|
||||||
|
vm.stack.Push("1")
|
||||||
|
} else {
|
||||||
|
vm.stack.Push("0")
|
||||||
|
}
|
||||||
|
case oLE:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// x <= y
|
||||||
|
if x.Cmp(y) < 1 {
|
||||||
|
vm.stack.Push("1")
|
||||||
|
} else {
|
||||||
|
vm.stack.Push("0")
|
||||||
|
}
|
||||||
|
case oGT:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// x > y
|
||||||
|
if x.Cmp(y) > 0 {
|
||||||
|
vm.stack.Push("1")
|
||||||
|
} else {
|
||||||
|
vm.stack.Push("0")
|
||||||
|
}
|
||||||
|
case oGE:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// x >= y
|
||||||
|
if x.Cmp(y) > -1 {
|
||||||
|
vm.stack.Push("1")
|
||||||
|
} else {
|
||||||
|
vm.stack.Push("0")
|
||||||
|
}
|
||||||
|
case oNOT:
|
||||||
|
x, y := vm.stack.Popn()
|
||||||
|
// x != y
|
||||||
|
if x.Cmp(y) != 0 {
|
||||||
|
vm.stack.Push("1")
|
||||||
|
} else {
|
||||||
|
vm.stack.Push("0")
|
||||||
|
}
|
||||||
|
case oMYADDRESS:
|
||||||
|
vm.stack.Push(string(tx.Hash()))
|
||||||
|
case oTXSENDER:
|
||||||
|
vm.stack.Push(tx.sender)
|
||||||
case oPUSH:
|
case oPUSH:
|
||||||
// Get the next entry and pushes the value on the stack
|
// Get the next entry and pushes the value on the stack
|
||||||
iptr++
|
pc++
|
||||||
vm.stack.Push(contract.state.Get(string(Encode(uint32(iptr)))))
|
vm.stack.Push(contract.state.Get(string(NumberToBytes(uint64(pc), 32))))
|
||||||
case oPOP:
|
case oPOP:
|
||||||
// Pop current value of the stack
|
// Pop current value of the stack
|
||||||
vm.stack.Pop()
|
vm.stack.Pop()
|
||||||
case oLOAD:
|
case oLOAD:
|
||||||
// Load instruction X on the stack
|
// Load instruction X on the stack
|
||||||
i, _ := strconv.Atoi(vm.stack.Pop())
|
i, _ := strconv.Atoi(vm.stack.Pop())
|
||||||
vm.stack.Push(contract.state.Get(string(Encode(uint32(i)))))
|
vm.stack.Push(contract.state.Get(string(NumberToBytes(uint64(i), 32))))
|
||||||
case oSTOP:
|
case oSTOP:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
iptr++
|
pc++
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
vm.stack.Print()
|
||||||
type Vm struct {
|
|
||||||
// Memory stack
|
|
||||||
stack map[string]string
|
|
||||||
memory map[string]map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVm() *Vm {
|
|
||||||
//stackSize := uint(256)
|
|
||||||
|
|
||||||
return &Vm{
|
|
||||||
stack: make(map[string]string),
|
|
||||||
memory: make(map[string]map[string]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vm *Vm) RunTransaction(tx *Transaction, cb TxCallback) {
|
|
||||||
if Debug {
|
|
||||||
fmt.Printf(`
|
|
||||||
# processing Tx (%v)
|
|
||||||
# fee = %f, ops = %d, sender = %s, value = %d
|
|
||||||
`, tx.addr, float32(tx.fee) / 1e8, len(tx.data), tx.sender, tx.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
vm.stack = make(map[string]string)
|
|
||||||
vm.stack["0"] = tx.sender
|
|
||||||
vm.stack["1"] = "100" //int(tx.value)
|
|
||||||
vm.stack["1"] = "1000" //int(tx.fee)
|
|
||||||
// Stack pointer
|
|
||||||
stPtr := 0
|
|
||||||
|
|
||||||
//vm.memory[tx.addr] = make([]int, 256)
|
|
||||||
vm.memory[tx.addr] = make(map[string]string)
|
|
||||||
|
|
||||||
// Define instruction 'accessors' for the instruction, which makes it more readable
|
|
||||||
// also called register values, shorthanded as Rx/y/z. Memory address are shorthanded as Mx/y/z.
|
|
||||||
// Instructions are shorthanded as Ix/y/z
|
|
||||||
x := 0; y := 1; z := 2; //a := 3; b := 4; c := 5
|
|
||||||
out:
|
|
||||||
for stPtr < len(tx.data) {
|
|
||||||
// The base big int for all calculations. Use this for any results.
|
|
||||||
base := new(big.Int)
|
|
||||||
// XXX Should Instr return big int slice instead of string slice?
|
|
||||||
op, args, _ := Instr(tx.data[stPtr])
|
|
||||||
|
|
||||||
if Debug {
|
|
||||||
fmt.Printf("%-3d %d %v\n", stPtr, op, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
opType := OpType(tNorm)
|
|
||||||
// Determine the op type (used for calculating fees by the block manager)
|
|
||||||
switch op {
|
|
||||||
case oEXTRO, oBALANCE:
|
|
||||||
opType = tExtro
|
|
||||||
case oSHA256, oRIPEMD160, oECMUL, oECADD: // TODO add rest
|
|
||||||
opType = tCrypto
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the callback yielded a negative result abort execution
|
|
||||||
if !cb(opType) { break out }
|
|
||||||
|
|
||||||
nptr := stPtr
|
|
||||||
switch op {
|
|
||||||
case oSTOP:
|
|
||||||
fmt.Println("exiting (oSTOP), idx =", nptr)
|
|
||||||
|
|
||||||
break out
|
|
||||||
case oADD:
|
|
||||||
// (Rx + Ry) % 2 ** 256
|
|
||||||
base.Add(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]]))
|
|
||||||
base.Mod(base, big.NewInt(int64(math.Pow(2, 256))))
|
|
||||||
// Set the result to Rz
|
|
||||||
vm.stack[args[ z ]] = base.String()
|
|
||||||
case oSUB:
|
|
||||||
// (Rx - Ry) % 2 ** 256
|
|
||||||
base.Sub(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]]))
|
|
||||||
base.Mod(base, big.NewInt(int64(math.Pow(2, 256))))
|
|
||||||
// Set the result to Rz
|
|
||||||
vm.stack[args[ z ]] = base.String()
|
|
||||||
case oMUL:
|
|
||||||
// (Rx * Ry) % 2 ** 256
|
|
||||||
base.Mul(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]]))
|
|
||||||
base.Mod(base, big.NewInt(int64(math.Pow(2, 256))))
|
|
||||||
// Set the result to Rz
|
|
||||||
vm.stack[args[ z ]] = base.String()
|
|
||||||
case oDIV:
|
|
||||||
// floor(Rx / Ry)
|
|
||||||
base.Div(Big(vm.stack[args[ x ]]), Big(vm.stack[args[ y ]]))
|
|
||||||
// Set the result to Rz
|
|
||||||
vm.stack[args[ z ]] = base.String()
|
|
||||||
case oSET:
|
|
||||||
// Set the (numeric) value at Iy to Rx
|
|
||||||
vm.stack[args[ x ]] = args[ y ]
|
|
||||||
case oLD:
|
|
||||||
// Load the value at Mx to Ry
|
|
||||||
vm.stack[args[ y ]] = vm.memory[tx.addr][vm.stack[args[ x ]]]
|
|
||||||
case oLT:
|
|
||||||
cmp := Big(vm.stack[args[ x ]]).Cmp( Big(vm.stack[args[ y ]]) )
|
|
||||||
// Set the result as "boolean" value to Rz
|
|
||||||
if cmp < 0 { // a < b
|
|
||||||
vm.stack[args[ z ]] = "1"
|
|
||||||
} else {
|
|
||||||
vm.stack[args[ z ]] = "0"
|
|
||||||
}
|
|
||||||
case oJMP:
|
|
||||||
// Set the instruction pointer to the value at Rx
|
|
||||||
ptr, _ := strconv.Atoi( vm.stack[args[ x ]] )
|
|
||||||
nptr = ptr
|
|
||||||
case oJMPI:
|
|
||||||
// Set the instruction pointer to the value at Ry if Rx yields true
|
|
||||||
if vm.stack[args[ x ]] != "0" {
|
|
||||||
ptr, _ := strconv.Atoi( vm.stack[args[ y ]] )
|
|
||||||
nptr = ptr
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
fmt.Println("Error op", op)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if stPtr == nptr {
|
|
||||||
stPtr++
|
|
||||||
} else {
|
|
||||||
stPtr = nptr
|
|
||||||
if Debug { fmt.Println("... JMP", nptr, "...") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
59
vm_test.go
59
vm_test.go
@ -7,23 +7,66 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
func TestVm(t *testing.T) {
|
func TestVm(t *testing.T) {
|
||||||
|
InitFees()
|
||||||
|
|
||||||
db, _ := NewMemDatabase()
|
db, _ := NewMemDatabase()
|
||||||
Db = db
|
Db = db
|
||||||
|
|
||||||
ctrct := NewTransaction("", 20, []string{
|
ctrct := NewTransaction("", 200000000, []string{
|
||||||
"PUSH",
|
"PUSH", "1a2f2e",
|
||||||
"1a2f2e",
|
"PUSH", "hallo",
|
||||||
"PUSH",
|
|
||||||
"hallo",
|
|
||||||
"POP", // POP hallo
|
"POP", // POP hallo
|
||||||
"PUSH",
|
"PUSH", "3",
|
||||||
"3",
|
|
||||||
"LOAD", // Load hallo back on the stack
|
"LOAD", // Load hallo back on the stack
|
||||||
|
|
||||||
|
"PUSH", "1",
|
||||||
|
"PUSH", "2",
|
||||||
|
"ADD",
|
||||||
|
|
||||||
|
"PUSH", "2",
|
||||||
|
"PUSH", "1",
|
||||||
|
"SUB",
|
||||||
|
|
||||||
|
"PUSH", "100000000000000000000000",
|
||||||
|
"PUSH", "10000000000000",
|
||||||
|
"SDIV",
|
||||||
|
|
||||||
|
"PUSH", "105",
|
||||||
|
"PUSH", "200",
|
||||||
|
"MOD",
|
||||||
|
|
||||||
|
"PUSH", "100000000000000000000000",
|
||||||
|
"PUSH", "10000000000000",
|
||||||
|
"SMOD",
|
||||||
|
|
||||||
|
"PUSH", "5",
|
||||||
|
"PUSH", "10",
|
||||||
|
"LT",
|
||||||
|
|
||||||
|
"PUSH", "5",
|
||||||
|
"PUSH", "5",
|
||||||
|
"LE",
|
||||||
|
|
||||||
|
"PUSH", "50",
|
||||||
|
"PUSH", "5",
|
||||||
|
"GT",
|
||||||
|
|
||||||
|
"PUSH", "5",
|
||||||
|
"PUSH", "5",
|
||||||
|
"GE",
|
||||||
|
|
||||||
|
"PUSH", "10",
|
||||||
|
"PUSH", "10",
|
||||||
|
"NOT",
|
||||||
|
|
||||||
|
"MYADDRESS",
|
||||||
|
"TXSENDER",
|
||||||
|
|
||||||
"STOP",
|
"STOP",
|
||||||
})
|
})
|
||||||
tx := NewTransaction("1e8a42ea8cce13", 100, []string{})
|
tx := NewTransaction("1e8a42ea8cce13", 100, []string{})
|
||||||
|
|
||||||
block := CreateBlock("", 0, "", "", 0, 0, "", []*Transaction{ctrct, tx})
|
block := CreateBlock("", 0, "", "c014ba53", 0, 0, "", []*Transaction{ctrct, tx})
|
||||||
db.Put(block.Hash(), block.MarshalRlp())
|
db.Put(block.Hash(), block.MarshalRlp())
|
||||||
|
|
||||||
bm := NewBlockManager()
|
bm := NewBlockManager()
|
||||||
|
Loading…
Reference in New Issue
Block a user