Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
2d3c3674
Commit
2d3c3674
authored
Jan 03, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updated stack based vm
parent
6ab61f2c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
221 additions
and
225 deletions
+221
-225
parsing.go
parsing.go
+23
-44
vm.go
vm.go
+147
-173
vm_test.go
vm_test.go
+51
-8
No files found.
parsing.go
View file @
2d3c3674
...
...
@@ -10,50 +10,29 @@ import (
// Op codes
var
OpCodes
=
map
[
string
]
string
{
"STOP"
:
"0"
,
"PUSH"
:
"48"
,
// 0x30
"POP"
:
"49"
,
// 0x31
"LOAD"
:
"54"
,
// 0x36
/* OLD VM OPCODES
"ADD": "16", // 0x10
"SUB": "17", // 0x11
"MUL": "18", // 0x12
"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
*/
"STOP"
:
"0"
,
"ADD"
:
"1"
,
"MUL"
:
"2"
,
"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"
,
"PUSH"
:
"48"
,
"POP"
:
"49"
,
"LOAD"
:
"54"
,
}
...
...
vm.go
View file @
2d3c3674
...
...
@@ -12,46 +12,28 @@ import (
// Op codes
const
(
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
oPOP
int
=
0x31
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
...
...
@@ -79,9 +61,21 @@ func (st *Stack) Pop() string {
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
)
{
st
.
data
=
append
(
st
.
data
,
d
)
}
func
(
st
*
Stack
)
Print
()
{
fmt
.
Println
(
st
.
data
)
}
type
Vm
struct
{
// Stack
...
...
@@ -96,7 +90,7 @@ func NewVm() *Vm {
func
(
vm
*
Vm
)
ProcContract
(
tx
*
Transaction
,
block
*
Block
,
cb
TxCallback
)
{
// Instruction pointer
iptr
:=
0
pc
:=
0
contract
:=
block
.
GetContract
(
tx
.
Hash
())
if
contract
==
nil
{
...
...
@@ -104,164 +98,144 @@ func (vm *Vm) ProcContract(tx *Transaction, block *Block, cb TxCallback) {
return
}
Pow256
:=
BigPow
(
2
,
256
)
fmt
.
Printf
(
"# op arg
\n
"
)
out
:
for
{
// 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?
// 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
{
fmt
.
Printf
(
"%-3d %-4d
%v
\n
"
,
iptr
,
op
,
args
)
fmt
.
Printf
(
"%-3d %-4d
\n
"
,
pc
,
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
:
// Get the next entry and pushes the value on the stack
iptr
++
vm
.
stack
.
Push
(
contract
.
state
.
Get
(
string
(
Encode
(
uint32
(
iptr
)
))))
pc
++
vm
.
stack
.
Push
(
contract
.
state
.
Get
(
string
(
NumberToBytes
(
uint64
(
pc
),
32
))))
case
oPOP
:
// Pop current value of the stack
vm
.
stack
.
Pop
()
case
oLOAD
:
// Load instruction X on the stack
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
:
break
out
}
iptr
++
pc
++
}
}
/*
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, "...") }
}
}
vm
.
stack
.
Print
()
}
*/
vm_test.go
View file @
2d3c3674
...
...
@@ -7,23 +7,66 @@ import (
func
TestVm
(
t
*
testing
.
T
)
{
InitFees
()
db
,
_
:=
NewMemDatabase
()
Db
=
db
ctrct
:=
NewTransaction
(
""
,
20
,
[]
string
{
"PUSH"
,
"1a2f2e"
,
"PUSH"
,
"hallo"
,
ctrct
:=
NewTransaction
(
""
,
200000000
,
[]
string
{
"PUSH"
,
"1a2f2e"
,
"PUSH"
,
"hallo"
,
"POP"
,
// POP hallo
"PUSH"
,
"3"
,
"PUSH"
,
"3"
,
"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"
,
})
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
())
bm
:=
NewBlockManager
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment