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
38ea6a6d
Commit
38ea6a6d
authored
Mar 20, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Closures and vm based on closures
Status: Work in progress
parent
82d0f65d
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
217 additions
and
5 deletions
+217
-5
closure.go
ethchain/closure.go
+68
-0
vm.go
ethchain/vm.go
+93
-5
vm_test.go
ethchain/vm_test.go
+56
-0
No files found.
ethchain/closure.go
0 → 100644
View file @
38ea6a6d
package
ethchain
// TODO Re write VM to use values instead of big integers?
import
(
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
type
Callee
interface
{
ReturnGas
(
*
big
.
Int
,
*
State
)
}
type
ClosureBody
interface
{
Callee
ethutil
.
RlpEncodable
GetMem
(
int64
)
*
ethutil
.
Value
}
// Basic inline closure object which implement the 'closure' interface
type
Closure
struct
{
callee
Callee
object
ClosureBody
state
*
State
gas
*
big
.
Int
val
*
big
.
Int
}
// Create a new closure for the given data items
func
NewClosure
(
callee
Callee
,
object
ClosureBody
,
state
*
State
,
gas
,
val
*
big
.
Int
)
*
Closure
{
return
&
Closure
{
callee
,
object
,
state
,
gas
,
val
}
}
// Retuns the x element in data slice
func
(
c
*
Closure
)
GetMem
(
x
int64
)
*
ethutil
.
Value
{
m
:=
c
.
object
.
GetMem
(
x
)
if
m
==
nil
{
return
ethutil
.
EmptyValue
()
}
return
m
}
func
(
c
*
Closure
)
Return
(
ret
[]
byte
)
[]
byte
{
// Return the remaining gas to the callee
// If no callee is present return it to
// the origin (i.e. contract or tx)
if
c
.
callee
!=
nil
{
c
.
callee
.
ReturnGas
(
c
.
gas
,
c
.
state
)
}
else
{
c
.
object
.
ReturnGas
(
c
.
gas
,
c
.
state
)
// TODO incase it's a POST contract we gotta serialise the contract again.
// But it's not yet defined
}
return
ret
}
// Implement the Callee interface
func
(
c
*
Closure
)
ReturnGas
(
gas
*
big
.
Int
,
state
*
State
)
{
// Return the gas to the closure
c
.
gas
.
Add
(
c
.
gas
,
gas
)
}
func
(
c
*
Closure
)
GetGas
()
*
big
.
Int
{
return
c
.
gas
}
ethchain/vm.go
View file @
38ea6a6d
...
@@ -32,13 +32,101 @@ type RuntimeVars struct {
...
@@ -32,13 +32,101 @@ type RuntimeVars struct {
txData
[]
string
txData
[]
string
}
}
func
(
vm
*
Vm
)
RunClosure
(
closure
*
Closure
,
state
*
State
,
vars
RuntimeVars
)
[]
byte
{
// If the amount of gas supplied is less equal to 0
if
closure
.
GetGas
()
.
Cmp
(
big
.
NewInt
(
0
))
<=
0
{
// TODO Do something
}
// Memory for the current closure
var
mem
[]
byte
// New stack (should this be shared?)
stack
:=
NewStack
()
// Instruction pointer
pc
:=
int64
(
0
)
// Current address
//addr := vars.address
step
:=
0
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"# op
\n
"
)
}
for
{
step
++
// Get the memory location of pc
val
:=
closure
.
GetMem
(
pc
)
// Get the opcode (it must be an opcode!)
op
:=
OpCode
(
val
.
Uint
())
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"%-3d %-4s"
,
pc
,
op
.
String
())
}
// TODO Get each instruction cost properly
fee
:=
new
(
big
.
Int
)
fee
.
Add
(
fee
,
big
.
NewInt
(
1000
))
if
closure
.
GetGas
()
.
Cmp
(
fee
)
<
0
{
return
closure
.
Return
(
nil
)
}
switch
op
{
case
oSTOP
:
return
closure
.
Return
(
nil
)
case
oPUSH
:
pc
++
val
:=
closure
.
GetMem
(
pc
)
.
BigInt
()
stack
.
Push
(
val
)
case
oMSTORE
:
// Pop value of the stack
val
:=
stack
.
Pop
()
// Set the bytes to the memory field
mem
=
append
(
mem
,
ethutil
.
BigToBytes
(
val
,
256
)
...
)
case
oCALL
:
// Pop return size and offset
retSize
,
retOffset
:=
stack
.
Popn
()
// Pop input size and offset
inSize
,
inOffset
:=
stack
.
Popn
()
// TODO remove me.
fmt
.
Sprintln
(
inSize
,
inOffset
)
// Pop gas and value of the stack.
gas
,
value
:=
stack
.
Popn
()
// Closure addr
addr
:=
stack
.
Pop
()
contract
:=
state
.
GetContract
(
addr
.
Bytes
())
closure
:=
NewClosure
(
closure
,
contract
,
state
,
gas
,
value
)
ret
:=
vm
.
RunClosure
(
closure
,
state
,
vars
)
// Ensure that memory is large enough to hold the returned data
totSize
:=
new
(
big
.
Int
)
.
Add
(
retOffset
,
retSize
)
lenSize
:=
big
.
NewInt
(
int64
(
len
(
mem
)))
// Resize the current memory slice so that the return value may fit
if
totSize
.
Cmp
(
lenSize
)
>
0
{
diff
:=
new
(
big
.
Int
)
.
Sub
(
totSize
,
lenSize
)
newSlice
:=
make
([]
byte
,
diff
.
Int64
()
+
1
)
mem
=
append
(
mem
,
newSlice
...
)
}
copy
(
mem
[
retOffset
.
Int64
()
:
retOffset
.
Int64
()
+
retSize
.
Int64
()
+
1
],
ret
)
case
oRETURN
:
size
,
offset
:=
stack
.
Popn
()
ret
:=
mem
[
offset
.
Int64
()
:
offset
.
Int64
()
+
size
.
Int64
()
+
1
]
return
closure
.
Return
(
ret
)
}
pc
++
}
}
// Old VM code
func
(
vm
*
Vm
)
Process
(
contract
*
Contract
,
state
*
State
,
vars
RuntimeVars
)
{
func
(
vm
*
Vm
)
Process
(
contract
*
Contract
,
state
*
State
,
vars
RuntimeVars
)
{
vm
.
mem
=
make
(
map
[
string
]
*
big
.
Int
)
vm
.
mem
=
make
(
map
[
string
]
*
big
.
Int
)
vm
.
stack
=
NewStack
()
vm
.
stack
=
NewStack
()
addr
:=
vars
.
address
// tx.Hash()[12:]
addr
:=
vars
.
address
// tx.Hash()[12:]
// Instruction pointer
// Instruction pointer
pc
:=
0
pc
:=
int64
(
0
)
if
contract
==
nil
{
if
contract
==
nil
{
fmt
.
Println
(
"Contract not found"
)
fmt
.
Println
(
"Contract not found"
)
...
@@ -344,7 +432,7 @@ out:
...
@@ -344,7 +432,7 @@ out:
contract
.
SetAddr
(
addr
,
y
)
contract
.
SetAddr
(
addr
,
y
)
//contract.State().Update(string(idx), string(y))
//contract.State().Update(string(idx), string(y))
case
oJMP
:
case
oJMP
:
x
:=
int
(
vm
.
stack
.
Pop
()
.
Uint64
()
)
x
:=
vm
.
stack
.
Pop
()
.
Int64
(
)
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
pc
=
x
pc
=
x
pc
--
pc
--
...
@@ -352,7 +440,7 @@ out:
...
@@ -352,7 +440,7 @@ out:
x
:=
vm
.
stack
.
Pop
()
x
:=
vm
.
stack
.
Pop
()
// Set pc to x if it's non zero
// Set pc to x if it's non zero
if
x
.
Cmp
(
ethutil
.
BigFalse
)
!=
0
{
if
x
.
Cmp
(
ethutil
.
BigFalse
)
!=
0
{
pc
=
int
(
x
.
Uint64
()
)
pc
=
x
.
Int64
(
)
pc
--
pc
--
}
}
case
oIND
:
case
oIND
:
...
@@ -400,9 +488,9 @@ out:
...
@@ -400,9 +488,9 @@ out:
func
makeInlineTx
(
addr
[]
byte
,
value
,
from
,
length
*
big
.
Int
,
contract
*
Contract
,
state
*
State
)
{
func
makeInlineTx
(
addr
[]
byte
,
value
,
from
,
length
*
big
.
Int
,
contract
*
Contract
,
state
*
State
)
{
ethutil
.
Config
.
Log
.
Debugf
(
" => creating inline tx %x %v %v %v"
,
addr
,
value
,
from
,
length
)
ethutil
.
Config
.
Log
.
Debugf
(
" => creating inline tx %x %v %v %v"
,
addr
,
value
,
from
,
length
)
j
:=
0
j
:=
int64
(
0
)
dataItems
:=
make
([]
string
,
int
(
length
.
Uint64
()))
dataItems
:=
make
([]
string
,
int
(
length
.
Uint64
()))
for
i
:=
from
.
Uint64
();
i
<
length
.
Ui
nt64
();
i
++
{
for
i
:=
from
.
Int64
();
i
<
length
.
I
nt64
();
i
++
{
dataItems
[
j
]
=
contract
.
GetMem
(
j
)
.
Str
()
dataItems
[
j
]
=
contract
.
GetMem
(
j
)
.
Str
()
j
++
j
++
}
}
...
...
ethchain/vm_test.go
View file @
38ea6a6d
...
@@ -8,6 +8,8 @@ import (
...
@@ -8,6 +8,8 @@ import (
"testing"
"testing"
)
)
/*
func TestRun(t *testing.T) {
func TestRun(t *testing.T) {
InitFees()
InitFees()
...
@@ -104,3 +106,57 @@ func TestRun2(t *testing.T) {
...
@@ -104,3 +106,57 @@ func TestRun2(t *testing.T) {
txData: tx.Data,
txData: tx.Data,
})
})
}
}
*/
// XXX Full stack test
func
TestRun3
(
t
*
testing
.
T
)
{
ethutil
.
ReadConfig
(
""
)
db
,
_
:=
ethdb
.
NewMemDatabase
()
state
:=
NewState
(
ethutil
.
NewTrie
(
db
,
""
))
script
:=
Compile
([]
string
{
"PUSH"
,
"300"
,
"MSTORE"
,
"PUSH"
,
"300"
,
"MSTORE"
,
"PUSH"
,
"62"
,
"PUSH"
,
"0"
,
"RETURN"
,
})
tx
:=
NewTransaction
(
ContractAddr
,
ethutil
.
Big
(
"100000000000000000000000000000000000000000000000000"
),
script
)
addr
:=
tx
.
Hash
()[
12
:
]
fmt
.
Printf
(
"addr contract %x
\n
"
,
addr
)
contract
:=
MakeContract
(
tx
,
state
)
state
.
UpdateContract
(
addr
,
contract
)
callerScript
:=
Compile
([]
string
{
"PUSH"
,
"62"
,
// REND
"PUSH"
,
"0"
,
// RSTART
"PUSH"
,
"22"
,
// MEND
"PUSH"
,
"15"
,
// MSTART
"PUSH"
,
"1000"
,
/// Gas
"PUSH"
,
"0"
,
/// value
"PUSH"
,
string
(
addr
),
// Sender
"CALL"
,
})
callerTx
:=
NewTransaction
(
ContractAddr
,
ethutil
.
Big
(
"100000000000000000000000000000000000000000000000000"
),
callerScript
)
callerAddr
:=
callerTx
.
Hash
()[
12
:
]
executer
:=
NewTransaction
(
ContractAddr
,
ethutil
.
Big
(
"10000"
),
nil
)
executer
.
Sign
([]
byte
(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
))
callerClosure
:=
NewClosure
(
executer
,
MakeContract
(
callerTx
,
state
),
state
,
big
.
NewInt
(
1000000000
),
new
(
big
.
Int
))
vm
:=
&
Vm
{}
vm
.
RunClosure
(
callerClosure
,
state
,
RuntimeVars
{
address
:
callerAddr
,
blockNumber
:
1
,
sender
:
ethutil
.
FromHex
(
"cd1722f3947def4cf144679da39c4c32bdc35681"
),
prevHash
:
ethutil
.
FromHex
(
"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
),
coinbase
:
ethutil
.
FromHex
(
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
),
time
:
1
,
diff
:
big
.
NewInt
(
256
),
txValue
:
big
.
NewInt
(
10000
),
txData
:
nil
,
})
}
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