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
97786d03
Commit
97786d03
authored
Mar 24, 2014
by
Maran
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into miner
parents
274d5cc9
6a86c517
Changes
18
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
786 additions
and
511 deletions
+786
-511
README.md
README.md
+1
-1
address.go
ethchain/address.go
+25
-9
block.go
ethchain/block.go
+1
-1
block_manager_test.go
ethchain/block_manager_test.go
+4
-1
closure.go
ethchain/closure.go
+90
-0
contract.go
ethchain/contract.go
+37
-15
stack.go
ethchain/stack.go
+181
-115
state.go
ethchain/state.go
+39
-16
state_manager.go
ethchain/state_manager.go
+7
-8
transaction.go
ethchain/transaction.go
+15
-6
vm.go
ethchain/vm.go
+190
-271
vm_test.go
ethchain/vm_test.go
+69
-1
common.go
ethutil/common.go
+6
-0
config.go
ethutil/config.go
+13
-6
parsing.go
ethutil/parsing.go
+102
-59
rlp.go
ethutil/rlp.go
+4
-0
trie_test.go
ethutil/trie_test.go
+1
-0
peer.go
peer.go
+1
-2
No files found.
README.md
View file @
97786d03
...
...
@@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof
of Concept 3". For build instructions see the
[
Wiki
](
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go
)
).
of Concept 3
.5
". For build instructions see the
[
Wiki
](
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go
)
).
Ethereum Go is split up in several sub packages Please refer to each
individual package for more information.
...
...
ethchain/address.go
View file @
97786d03
...
...
@@ -6,23 +6,39 @@ import (
)
type
Account
struct
{
address
[]
byte
Amount
*
big
.
Int
Nonce
uint64
}
func
NewAccount
(
amount
*
big
.
Int
)
*
Account
{
return
&
Account
{
Amount
:
amount
,
Nonce
:
0
}
func
NewAccount
(
a
ddress
[]
byte
,
a
mount
*
big
.
Int
)
*
Account
{
return
&
Account
{
address
,
amount
,
0
}
}
func
NewAccountFromData
(
data
[]
byte
)
*
Account
{
a
ddress
:=
&
Account
{
}
a
ddress
.
RlpDecode
(
data
)
func
NewAccountFromData
(
address
,
data
[]
byte
)
*
Account
{
a
ccount
:=
&
Account
{
address
:
address
}
a
ccount
.
RlpDecode
(
data
)
return
a
ddress
return
a
ccount
}
func
(
a
*
Account
)
AddFee
(
fee
*
big
.
Int
)
{
a
.
Amount
.
Add
(
a
.
Amount
,
fee
)
a
.
AddFunds
(
fee
)
}
func
(
a
*
Account
)
AddFunds
(
funds
*
big
.
Int
)
{
a
.
Amount
.
Add
(
a
.
Amount
,
funds
)
}
func
(
a
*
Account
)
Address
()
[]
byte
{
return
a
.
address
}
// Implements Callee
func
(
a
*
Account
)
ReturnGas
(
value
*
big
.
Int
,
state
*
State
)
{
// Return the value back to the sender
a
.
AddFunds
(
value
)
state
.
UpdateAccount
(
a
.
address
,
a
)
}
func
(
a
*
Account
)
RlpEncode
()
[]
byte
{
...
...
ethchain/block.go
View file @
97786d03
...
...
@@ -142,7 +142,7 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
data
:=
block
.
state
.
trie
.
Get
(
string
(
block
.
Coinbase
))
// Get the ether (Coinbase) and add the fee (gief fee to miner)
ether
:=
NewAccountFromData
([]
byte
(
data
))
ether
:=
NewAccountFromData
(
block
.
Coinbase
,
[]
byte
(
data
))
base
=
new
(
big
.
Int
)
ether
.
Amount
=
base
.
Add
(
ether
.
Amount
,
fee
)
...
...
ethchain/block_manager_test.go
View file @
97786d03
package
ethchain
/*
import (
_ "fmt"
"github.com/ethereum/eth-go/ethdb"
...
...
@@ -14,9 +15,10 @@ func TestVm(t *testing.T) {
db, _ := ethdb.NewMemDatabase()
ethutil.Config.Db = db
bm
:=
New
Block
Manager
(
nil
)
bm := New
State
Manager(nil)
block := bm.bc.genesisBlock
bm.Prepare(block.State(), block.State())
script := Compile([]string{
"PUSH",
"1",
...
...
@@ -31,3 +33,4 @@ func TestVm(t *testing.T) {
tx2.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
bm.ApplyTransactions(block, []*Transaction{tx2})
}
*/
ethchain/closure.go
0 → 100644
View file @
97786d03
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
)
Address
()
[]
byte
}
type
ClosureBody
interface
{
Callee
ethutil
.
RlpEncodable
GetMem
(
*
big
.
Int
)
*
ethutil
.
Value
SetMem
(
*
big
.
Int
,
*
ethutil
.
Value
)
}
// Basic inline closure object which implement the 'closure' interface
type
Closure
struct
{
callee
Callee
object
ClosureBody
State
*
State
Gas
*
big
.
Int
Value
*
big
.
Int
Args
[]
byte
}
// 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
,
nil
}
}
// Retuns the x element in data slice
func
(
c
*
Closure
)
GetMem
(
x
*
big
.
Int
)
*
ethutil
.
Value
{
m
:=
c
.
object
.
GetMem
(
x
)
if
m
==
nil
{
return
ethutil
.
EmptyValue
()
}
return
m
}
func
(
c
*
Closure
)
SetMem
(
x
*
big
.
Int
,
val
*
ethutil
.
Value
)
{
c
.
object
.
SetMem
(
x
,
val
)
}
func
(
c
*
Closure
)
Address
()
[]
byte
{
return
c
.
object
.
Address
()
}
func
(
c
*
Closure
)
Call
(
vm
*
Vm
,
args
[]
byte
)
[]
byte
{
c
.
Args
=
args
return
vm
.
RunClosure
(
c
)
}
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
)
Object
()
ClosureBody
{
return
c
.
object
}
func
(
c
*
Closure
)
Callee
()
Callee
{
return
c
.
callee
}
ethchain/contract.go
View file @
97786d03
...
...
@@ -10,25 +10,21 @@ type Contract struct {
Nonce
uint64
//state *ethutil.Trie
state
*
State
address
[]
byte
}
func
NewContract
(
Amount
*
big
.
Int
,
root
[]
byte
)
*
Contract
{
contract
:=
&
Contract
{
Amount
:
Amount
,
Nonce
:
0
}
func
NewContract
(
address
[]
byte
,
Amount
*
big
.
Int
,
root
[]
byte
)
*
Contract
{
contract
:=
&
Contract
{
address
:
address
,
Amount
:
Amount
,
Nonce
:
0
}
contract
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
string
(
root
)))
return
contract
}
func
(
c
*
Contract
)
RlpEncode
()
[]
byte
{
return
ethutil
.
Encode
([]
interface
{}{
c
.
Amount
,
c
.
Nonce
,
c
.
state
.
trie
.
Root
})
}
func
NewContractFromBytes
(
address
,
data
[]
byte
)
*
Contract
{
contract
:=
&
Contract
{
address
:
address
}
contract
.
RlpDecode
(
data
)
func
(
c
*
Contract
)
RlpDecode
(
data
[]
byte
)
{
decoder
:=
ethutil
.
NewValueFromBytes
(
data
)
c
.
Amount
=
decoder
.
Get
(
0
)
.
BigInt
()
c
.
Nonce
=
decoder
.
Get
(
1
)
.
Uint
()
c
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
decoder
.
Get
(
2
)
.
Interface
()))
return
contract
}
func
(
c
*
Contract
)
Addr
(
addr
[]
byte
)
*
ethutil
.
Value
{
...
...
@@ -43,19 +39,45 @@ func (c *Contract) State() *State {
return
c
.
state
}
func
(
c
*
Contract
)
GetMem
(
num
i
nt
)
*
ethutil
.
Value
{
nb
:=
ethutil
.
BigToBytes
(
big
.
NewInt
(
int64
(
num
))
,
256
)
func
(
c
*
Contract
)
GetMem
(
num
*
big
.
I
nt
)
*
ethutil
.
Value
{
nb
:=
ethutil
.
BigToBytes
(
num
,
256
)
return
c
.
Addr
(
nb
)
}
func
(
c
*
Contract
)
SetMem
(
num
*
big
.
Int
,
val
*
ethutil
.
Value
)
{
addr
:=
ethutil
.
BigToBytes
(
num
,
256
)
c
.
state
.
trie
.
Update
(
string
(
addr
),
string
(
val
.
Encode
()))
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
func
(
c
*
Contract
)
ReturnGas
(
val
*
big
.
Int
,
state
*
State
)
{
c
.
Amount
.
Add
(
c
.
Amount
,
val
)
}
func
(
c
*
Contract
)
Address
()
[]
byte
{
return
c
.
address
}
func
(
c
*
Contract
)
RlpEncode
()
[]
byte
{
return
ethutil
.
Encode
([]
interface
{}{
c
.
Amount
,
c
.
Nonce
,
c
.
state
.
trie
.
Root
})
}
func
(
c
*
Contract
)
RlpDecode
(
data
[]
byte
)
{
decoder
:=
ethutil
.
NewValueFromBytes
(
data
)
c
.
Amount
=
decoder
.
Get
(
0
)
.
BigInt
()
c
.
Nonce
=
decoder
.
Get
(
1
)
.
Uint
()
c
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
decoder
.
Get
(
2
)
.
Interface
()))
}
func
MakeContract
(
tx
*
Transaction
,
state
*
State
)
*
Contract
{
// Create contract if there's no recipient
if
tx
.
IsContract
()
{
addr
:=
tx
.
Hash
()[
12
:
]
value
:=
tx
.
Value
contract
:=
NewContract
(
value
,
[]
byte
(
""
))
contract
:=
NewContract
(
addr
,
value
,
[]
byte
(
""
))
state
.
trie
.
Update
(
string
(
addr
),
string
(
contract
.
RlpEncode
()))
for
i
,
val
:=
range
tx
.
Data
{
if
len
(
val
)
>
0
{
...
...
ethchain/stack.go
View file @
97786d03
...
...
@@ -2,6 +2,7 @@ package ethchain
import
(
"fmt"
_
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
...
...
@@ -9,6 +10,7 @@ type OpCode int
// Op codes
const
(
// 0x0 range - arithmetic ops
oSTOP
=
0x00
oADD
=
0x01
oMUL
=
0x02
...
...
@@ -20,50 +22,65 @@ const (
oEXP
=
0x08
oNEG
=
0x09
oLT
=
0x0a
oLE
=
0x0b
oGT
=
0x0c
oGE
=
0x0d
oEQ
=
0x0e
oNOT
=
0x0f
oMYADDRESS
=
0x10
oTXSENDER
=
0x11
oTXVALUE
=
0x12
oTXDATAN
=
0x13
oTXDATA
=
0x14
oBLK_PREVHASH
=
0x15
oBLK_COINBASE
=
0x16
oBLK_TIMESTAMP
=
0x17
oBLK_NUMBER
=
0x18
oBLK_DIFFICULTY
=
0x19
oBLK_NONCE
=
0x1a
oBASEFEE
=
0x1b
oSHA256
=
0x20
oRIPEMD160
=
0x21
oECMUL
=
0x22
oECADD
=
0x23
oECSIGN
=
0x24
oECRECOVER
=
0x25
oECVALID
=
0x26
oSHA3
=
0x27
oPUSH
=
0x30
oPOP
=
0x31
oDUP
=
0x32
oSWAP
=
0x33
oMLOAD
=
0x34
oMSTORE
=
0x35
oSLOAD
=
0x36
oSSTORE
=
0x37
oJMP
=
0x38
oJMPI
=
0x39
oIND
=
0x3a
oEXTRO
=
0x3b
oBALANCE
=
0x3c
oMKTX
=
0x3d
oSUICIDE
=
0x3f
oGT
=
0x0b
oEQ
=
0x0c
oNOT
=
0x0d
// 0x10 range - bit ops
oAND
=
0x10
oOR
=
0x11
oXOR
=
0x12
oBYTE
=
0x13
// 0x20 range - crypto
oSHA3
=
0x20
// 0x30 range - closure state
oADDRESS
=
0x30
oBALANCE
=
0x31
oORIGIN
=
0x32
oCALLER
=
0x33
oCALLVALUE
=
0x34
oCALLDATA
=
0x35
oCALLDATASIZE
=
0x36
oGASPRICE
=
0x37
// 0x40 range - block operations
oPREVHASH
=
0x40
oCOINBASE
=
0x41
oTIMESTAMP
=
0x42
oNUMBER
=
0x43
oDIFFICULTY
=
0x44
oGASLIMIT
=
0x45
// 0x50 range - 'storage' and execution
oPUSH
=
0x50
oPOP
=
0x51
oDUP
=
0x52
oSWAP
=
0x53
oMLOAD
=
0x54
oMSTORE
=
0x55
oMSTORE8
=
0x56
oSLOAD
=
0x57
oSSTORE
=
0x58
oJUMP
=
0x59
oJUMPI
=
0x5a
oPC
=
0x5b
oMSIZE
=
0x5c
// 0x60 range - closures
oCREATE
=
0x60
oCALL
=
0x61
oRETURN
=
0x62
// 0x70 range - other
oLOG
=
0x70
// XXX Unofficial
oSUICIDE
=
0x7f
)
// Since the opcodes aren't all in order we can't use a regular slice
var
opCodeToString
=
map
[
OpCode
]
string
{
// 0x0 range - arithmetic ops
oSTOP
:
"STOP"
,
oADD
:
"ADD"
,
oMUL
:
"MUL"
,
...
...
@@ -75,44 +92,59 @@ var opCodeToString = map[OpCode]string{
oEXP
:
"EXP"
,
oNEG
:
"NEG"
,
oLT
:
"LT"
,
oLE
:
"LE"
,
oGT
:
"GT"
,
oGE
:
"GE"
,
oEQ
:
"EQ"
,
oNOT
:
"NOT"
,
oMYADDRESS
:
"MYADDRESS"
,
oTXSENDER
:
"TXSENDER"
,
oTXVALUE
:
"TXVALUE"
,
oTXDATAN
:
"TXDATAN"
,
oTXDATA
:
"TXDATA"
,
oBLK_PREVHASH
:
"BLK_PREVHASH"
,
oBLK_COINBASE
:
"BLK_COINBASE"
,
oBLK_TIMESTAMP
:
"BLK_TIMESTAMP"
,
oBLK_NUMBER
:
"BLK_NUMBER"
,
oBLK_DIFFICULTY
:
"BLK_DIFFICULTY"
,
oBASEFEE
:
"BASEFEE"
,
oSHA256
:
"SHA256"
,
oRIPEMD160
:
"RIPEMD160"
,
oECMUL
:
"ECMUL"
,
oECADD
:
"ECADD"
,
oECSIGN
:
"ECSIGN"
,
oECRECOVER
:
"ECRECOVER"
,
oECVALID
:
"ECVALID"
,
// 0x10 range - bit ops
oAND
:
"AND"
,
oOR
:
"OR"
,
oXOR
:
"XOR"
,
oBYTE
:
"BYTE"
,
// 0x20 range - crypto
oSHA3
:
"SHA3"
,
// 0x30 range - closure state
oADDRESS
:
"ADDRESS"
,
oBALANCE
:
"BALANCE"
,
oORIGIN
:
"ORIGIN"
,
oCALLER
:
"CALLER"
,
oCALLVALUE
:
"CALLVALUE"
,
oCALLDATA
:
"CALLDATA"
,
oCALLDATASIZE
:
"CALLDATASIZE"
,
oGASPRICE
:
"TXGASPRICE"
,
// 0x40 range - block operations
oPREVHASH
:
"PREVHASH"
,
oCOINBASE
:
"COINBASE"
,
oTIMESTAMP
:
"TIMESTAMP"
,
oNUMBER
:
"NUMBER"
,
oDIFFICULTY
:
"DIFFICULTY"
,
oGASLIMIT
:
"GASLIMIT"
,
// 0x50 range - 'storage' and execution
oPUSH
:
"PUSH"
,
oPOP
:
"POP"
,
oDUP
:
"DUP"
,
oSWAP
:
"SWAP"
,
oMLOAD
:
"MLOAD"
,
oMSTORE
:
"MSTORE"
,
oMSTORE8
:
"MSTORE8"
,
oSLOAD
:
"SLOAD"
,
oSSTORE
:
"SSTORE"
,
oJMP
:
"JMP"
,
oJMPI
:
"JMPI"
,
oIND
:
"IND"
,
oEXTRO
:
"EXTRO"
,
oBALANCE
:
"BALANCE"
,
oMKTX
:
"MKTX"
,
oJUMP
:
"JUMP"
,
oJUMPI
:
"JUMPI"
,
oPC
:
"PC"
,
oMSIZE
:
"MSIZE"
,
// 0x60 range - closures
oCREATE
:
"CREATE"
,
oCALL
:
"CALL"
,
oRETURN
:
"RETURN"
,
// 0x70 range - other
oLOG
:
"LOG"
,
oSUICIDE
:
"SUICIDE"
,
}
...
...
@@ -141,35 +173,27 @@ func NewStack() *Stack {
}
func
(
st
*
Stack
)
Pop
()
*
big
.
Int
{
s
:=
len
(
st
.
data
)
str
:=
st
.
data
[
s
-
1
]
st
.
data
=
st
.
data
[
:
s
-
1
]
str
:=
st
.
data
[
0
]
st
.
data
=
st
.
data
[
1
:
]
return
str
}
func
(
st
*
Stack
)
Popn
()
(
*
big
.
Int
,
*
big
.
Int
)
{
s
:=
len
(
st
.
data
)
ints
:=
st
.
data
[
s
-
2
:
]
st
.
data
=
st
.
data
[
:
s
-
2
]
ints
:=
st
.
data
[
:
2
]
st
.
data
=
st
.
data
[
2
:
]
return
ints
[
0
],
ints
[
1
]
}
func
(
st
*
Stack
)
Peek
()
*
big
.
Int
{
s
:=
len
(
st
.
data
)
str
:=
st
.
data
[
s
-
1
]
str
:=
st
.
data
[
0
]
return
str
}
func
(
st
*
Stack
)
Peekn
()
(
*
big
.
Int
,
*
big
.
Int
)
{
s
:=
len
(
st
.
data
)
ints
:=
st
.
data
[
s
-
2
:
]
ints
:=
st
.
data
[
:
2
]
return
ints
[
0
],
ints
[
1
]
}
...
...
@@ -188,3 +212,45 @@ func (st *Stack) Print() {
}
fmt
.
Println
(
"#############"
)
}
type
Memory
struct
{
store
[]
byte
}
func
(
m
*
Memory
)
Set
(
offset
,
size
int64
,
value
[]
byte
)
{
totSize
:=
offset
+
size
lenSize
:=
int64
(
len
(
m
.
store
)
-
1
)
if
totSize
>
lenSize
{
// Calculate the diff between the sizes
diff
:=
totSize
-
lenSize
if
diff
>
0
{
// Create a new empty slice and append it
newSlice
:=
make
([]
byte
,
diff
-
1
)
// Resize slice
m
.
store
=
append
(
m
.
store
,
newSlice
...
)
}
}
copy
(
m
.
store
[
offset
:
offset
+
size
],
value
)
}
func
(
m
*
Memory
)
Get
(
offset
,
size
int64
)
[]
byte
{
return
m
.
store
[
offset
:
offset
+
size
]
}
func
(
m
*
Memory
)
Len
()
int
{
return
len
(
m
.
store
)
}
func
(
m
*
Memory
)
Print
()
{
fmt
.
Println
(
"### MEM ###"
)
if
len
(
m
.
store
)
>
0
{
addr
:=
0
for
i
:=
0
;
i
+
32
<
len
(
m
.
store
);
i
+=
32
{
fmt
.
Printf
(
"%03d %v
\n
"
,
addr
,
m
.
store
[
i
:
i
+
32
])
addr
++
}
}
else
{
fmt
.
Println
(
"-- empty --"
)
}
fmt
.
Println
(
"###########"
)
}
ethchain/state.go
View file @
97786d03
...
...
@@ -63,8 +63,7 @@ func (s *State) GetContract(addr []byte) *Contract {
}
// build contract
contract
:=
&
Contract
{}
contract
.
RlpDecode
([]
byte
(
data
))
contract
:=
NewContractFromBytes
(
addr
,
[]
byte
(
data
))
// Check if there's a cached state for this contract
cachedState
:=
s
.
states
[
string
(
addr
)]
...
...
@@ -78,27 +77,19 @@ func (s *State) GetContract(addr []byte) *Contract {
return
contract
}
func
(
s
*
State
)
UpdateContract
(
addr
[]
byte
,
contract
*
Contract
)
{
s
.
trie
.
Update
(
string
(
addr
),
string
(
contract
.
RlpEncode
()))
}
func
Compile
(
code
[]
string
)
(
script
[]
string
)
{
script
=
make
([]
string
,
len
(
code
))
for
i
,
val
:=
range
code
{
instr
,
_
:=
ethutil
.
CompileInstr
(
val
)
script
[
i
]
=
string
(
instr
)
}
func
(
s
*
State
)
UpdateContract
(
contract
*
Contract
)
{
addr
:=
contract
.
Address
()
return
s
.
states
[
string
(
addr
)]
=
contract
.
state
s
.
trie
.
Update
(
string
(
addr
),
string
(
contract
.
RlpEncode
()))
}
func
(
s
*
State
)
GetAccount
(
addr
[]
byte
)
(
account
*
Account
)
{
data
:=
s
.
trie
.
Get
(
string
(
addr
))
if
data
==
""
{
account
=
NewAccount
(
big
.
NewInt
(
0
))
account
=
NewAccount
(
addr
,
big
.
NewInt
(
0
))
}
else
{
account
=
NewAccountFromData
([]
byte
(
data
))
account
=
NewAccountFromData
(
addr
,
[]
byte
(
data
))
}
return
...
...
@@ -153,3 +144,35 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) {
return
val
,
typ
}
func
(
s
*
State
)
Put
(
key
,
object
[]
byte
)
{
s
.
trie
.
Update
(
string
(
key
),
string
(
object
))
}
func
(
s
*
State
)
Root
()
interface
{}
{
return
s
.
trie
.
Root
}
// Script compilation functions
// Compiles strings to machine code
func
Compile
(
code
[]
string
)
(
script
[]
string
)
{
script
=
make
([]
string
,
len
(
code
))
for
i
,
val
:=
range
code
{
instr
,
_
:=
ethutil
.
CompileInstr
(
val
)
script
[
i
]
=
string
(
instr
)
}
return
}
func
CompileToValues
(
code
[]
string
)
(
script
[]
*
ethutil
.
Value
)
{
script
=
make
([]
*
ethutil
.
Value
,
len
(
code
))
for
i
,
val
:=
range
code
{
instr
,
_
:=
ethutil
.
CompileInstr
(
val
)
script
[
i
]
=
ethutil
.
NewValue
(
instr
)
}
return
}
ethchain/state_manager.go
View file @
97786d03
...
...
@@ -308,18 +308,17 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
}
}()
*/
vm
:=
&
Vm
{}
//vm.Process(contract, block.state, RuntimeVars{
vm
.
Process
(
contract
,
sm
.
procState
,
RuntimeVars
{
address
:
tx
.
Hash
()[
12
:
],
caller
:=
sm
.
procState
.
GetAccount
(
tx
.
Sender
())
closure
:=
NewClosure
(
caller
,
contract
,
sm
.
procState
,
tx
.
Gas
,
tx
.
Value
)
vm
:=
NewVm
(
sm
.
procState
,
RuntimeVars
{
origin
:
caller
.
Address
(),
blockNumber
:
block
.
BlockInfo
()
.
Number
,
sender
:
tx
.
Sender
(),
prevHash
:
block
.
PrevHash
,
coinbase
:
block
.
Coinbase
,
time
:
block
.
Time
,
diff
:
block
.
Difficulty
,
txValue
:
tx
.
Value
,
txData
:
tx
.
Data
,
// XXX Tx data? Could be just an argument to the closure instead
txData
:
nil
,
})
closure
.
Call
(
vm
,
nil
)
}
ethchain/transaction.go
View file @
97786d03
...
...
@@ -13,22 +13,31 @@ type Transaction struct {
Nonce
uint64
Recipient
[]
byte
Value
*
big
.
Int
Gas
*
big
.
Int
Gasprice
*
big
.
Int
Data
[]
string
Memory
[]
int
v
byte
r
,
s
[]
byte
}
func
NewTransaction
(
to
[]
byte
,
value
*
big
.
Int
,
data
[]
string
)
*
Transaction
{
tx
:=
Transaction
{
Recipient
:
to
,
Value
:
value
}
tx
.
Nonce
=
0
// Serialize the data
tx
.
Data
=
data
tx
:=
Transaction
{
Recipient
:
to
,
Value
:
value
,
Nonce
:
0
,
Data
:
data
}
return
&
tx
}
func
NewContractCreationTx
(
value
,
gasprice
*
big
.
Int
,
data
[]
string
)
*
Transaction
{
return
&
Transaction
{
Value
:
value
,
Gasprice
:
gasprice
,
Data
:
data
}
}
func
NewContractMessageTx
(
to
[]
byte
,
value
,
gasprice
,
gas
*
big
.
Int
,
data
[]
string
)
*
Transaction
{
return
&
Transaction
{
Recipient
:
to
,
Value
:
value
,
Gasprice
:
gasprice
,
Gas
:
gas
,
Data
:
data
}
}
func
NewTx
(
to
[]
byte
,
value
*
big
.
Int
,
data
[]
string
)
*
Transaction
{
return
&
Transaction
{
Recipient
:
to
,
Value
:
value
,
Gasprice
:
big
.
NewInt
(
0
),
Gas
:
big
.
NewInt
(
0
),
Nonce
:
0
,
Data
:
data
}
}
// XXX Deprecated
func
NewTransactionFromData
(
data
[]
byte
)
*
Transaction
{
return
NewTransactionFromBytes
(
data
)
...
...
ethchain/vm.go
View file @
97786d03
package
ethchain
import
(
"bytes"
"fmt"
_
"bytes"
_
"fmt"
"github.com/ethereum/eth-go/ethutil"
"github.com/obscuren/secp256k1-go"
_
"github.com/obscuren/secp256k1-go"
"log"
"math"
_
"math"
"math/big"
)
...
...
@@ -18,122 +18,102 @@ type Vm struct {
mem
map
[
string
]
*
big
.
Int
vars
RuntimeVars
state
*
State
}
type
RuntimeVars
struct
{
address
[]
byte
origin
[]
byte
blockNumber
uint64
sender
[]
byte
prevHash
[]
byte
coinbase
[]
byte
time
int64
diff
*
big
.
Int
txValue
*
big
.
Int
txData
[]
string
}
func
(
vm
*
Vm
)
Process
(
contract
*
Contract
,
state
*
State
,
vars
RuntimeVars
)
{
vm
.
mem
=
make
(
map
[
string
]
*
big
.
Int
)
vm
.
stack
=
NewStack
()
func
NewVm
(
state
*
State
,
vars
RuntimeVars
)
*
Vm
{
return
&
Vm
{
vars
:
vars
,
state
:
state
}
}
addr
:=
vars
.
address
// tx.Hash()[12:]
// Instruction pointer
pc
:=
0
var
Pow256
=
ethutil
.
BigPow
(
2
,
256
)
if
contract
==
nil
{
fmt
.
Println
(
"Contract not found"
)
return
func
(
vm
*
Vm
)
RunClosure
(
closure
*
Closure
)
[]
byte
{
// If the amount of gas supplied is less equal to 0
if
closure
.
Gas
.
Cmp
(
big
.
NewInt
(
0
))
<=
0
{
// TODO Do something
}
Pow256
:=
ethutil
.
BigPow
(
2
,
256
)
// Memory for the current closure
mem
:=
&
Memory
{}
// New stack (should this be shared?)
stack
:=
NewStack
()
// Instruction pointer
pc
:=
big
.
NewInt
(
0
)
// Current step count
step
:=
0
// The base for all big integer arithmetic
base
:=
new
(
big
.
Int
)
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"# op
\n
"
)
}
stepcount
:=
0
totalFee
:=
new
(
big
.
Int
)
out
:
for
{
stepcount
++
// The base big int for all calculations. Use this for any results.
base
:=
new
(
big
.
Int
)
val
:=
contract
.
GetMem
(
pc
)
//fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb)
step
++
// Get the memory location of pc
val
:=
closure
.
GetMem
(
pc
)
// Get the opcode (it must be an opcode!)
op
:=
OpCode
(
val
.
Uint
())
var
fee
*
big
.
Int
=
new
(
big
.
Int
)
var
fee2
*
big
.
Int
=
new
(
big
.
Int
)
if
stepcount
>
16
{
fee
.
Add
(
fee
,
StepFee
)
}
// Calculate the fees
switch
op
{
case
oSSTORE
:
y
,
x
:=
vm
.
stack
.
Peekn
()
val
:=
contract
.
Addr
(
ethutil
.
BigToBytes
(
x
,
256
))
if
val
.
IsEmpty
()
&&
len
(
y
.
Bytes
())
>
0
{
fee2
.
Add
(
DataFee
,
StoreFee
)
}
else
{
fee2
.
Sub
(
DataFee
,
StoreFee
)
}
case
oSLOAD
:
fee
.
Add
(
fee
,
StoreFee
)
case
oEXTRO
,
oBALANCE
:
fee
.
Add
(
fee
,
ExtroFee
)
case
oSHA256
,
oRIPEMD160
,
oECMUL
,
oECADD
,
oECSIGN
,
oECRECOVER
,
oECVALID
:
fee
.
Add
(
fee
,
CryptoFee
)
case
oMKTX
:
fee
.
Add
(
fee
,
ContractFee
)
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"%-3d %-4s"
,
pc
,
op
.
String
())
}
tf
:=
new
(
big
.
Int
)
.
Add
(
fee
,
fee2
)
if
contract
.
Amount
.
Cmp
(
tf
)
<
0
{
fmt
.
Println
(
"Insufficient fees to continue running the contract"
,
tf
,
contract
.
Amount
)
break
}
// Add the fee to the total fee. It's subtracted when we're done looping
totalFee
.
Add
(
totalFee
,
tf
)
// TODO Get each instruction cost properly
fee
:=
new
(
big
.
Int
)
fee
.
Add
(
fee
,
big
.
NewInt
(
1000
))
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"%-3d %-4s"
,
pc
,
op
.
String
()
)
if
closure
.
Gas
.
Cmp
(
fee
)
<
0
{
return
closure
.
Return
(
nil
)
}
switch
op
{
case
oSTOP
:
fmt
.
Println
(
""
)
break
out
case
oLOG
:
stack
.
Print
()
mem
.
Print
()
case
oSTOP
:
// Stop the closure
return
closure
.
Return
(
nil
)
// 0x20 range
case
oADD
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// (x + y) % 2 ** 256
base
.
Add
(
x
,
y
)
base
.
Mod
(
base
,
Pow256
)
// Pop result back on the stack
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oSUB
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// (x - y) % 2 ** 256
base
.
Sub
(
x
,
y
)
base
.
Mod
(
base
,
Pow256
)
// Pop result back on the stack
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oMUL
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// (x * y) % 2 ** 256
base
.
Mul
(
x
,
y
)
base
.
Mod
(
base
,
Pow256
)
// Pop result back on the stack
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oDIV
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// floor(x / y)
base
.
Div
(
x
,
y
)
// Pop result back on the stack
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oSDIV
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// n > 2**255
if
x
.
Cmp
(
Pow256
)
>
0
{
x
.
Sub
(
Pow256
,
x
)
...
...
@@ -147,13 +127,13 @@ out:
z
.
Sub
(
Pow256
,
z
)
}
// Push result on to the stack
vm
.
stack
.
Push
(
z
)
stack
.
Push
(
z
)
case
oMOD
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
base
.
Mod
(
x
,
y
)
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oSMOD
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// n > 2**255
if
x
.
Cmp
(
Pow256
)
>
0
{
x
.
Sub
(
Pow256
,
x
)
...
...
@@ -167,213 +147,154 @@ out:
z
.
Sub
(
Pow256
,
z
)
}
// Push result on to the stack
vm
.
stack
.
Push
(
z
)
stack
.
Push
(
z
)
case
oEXP
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
base
.
Exp
(
x
,
y
,
Pow256
)
vm
.
stack
.
Push
(
base
)
stack
.
Push
(
base
)
case
oNEG
:
base
.
Sub
(
Pow256
,
vm
.
stack
.
Pop
())
vm
.
stack
.
Push
(
base
)
base
.
Sub
(
Pow256
,
stack
.
Pop
())
stack
.
Push
(
base
)
case
oLT
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// x < y
if
x
.
Cmp
(
y
)
<
0
{
vm
.
stack
.
Push
(
ethutil
.
BigTrue
)
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
}
case
oLE
:
x
,
y
:=
vm
.
stack
.
Popn
()
// x <= y
if
x
.
Cmp
(
y
)
<
1
{
vm
.
stack
.
Push
(
ethutil
.
BigTrue
)
stack
.
Push
(
ethutil
.
BigTrue
)
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
stack
.
Push
(
ethutil
.
BigFalse
)
}
case
oGT
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// x > y
if
x
.
Cmp
(
y
)
>
0
{
vm
.
stack
.
Push
(
ethutil
.
BigTrue
)
stack
.
Push
(
ethutil
.
BigTrue
)
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
}
case
oGE
:
x
,
y
:=
vm
.
stack
.
Popn
()
// x >= y
if
x
.
Cmp
(
y
)
>
-
1
{
vm
.
stack
.
Push
(
ethutil
.
BigTrue
)
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
stack
.
Push
(
ethutil
.
BigFalse
)
}
case
oNOT
:
x
,
y
:=
vm
.
stack
.
Popn
()
x
,
y
:=
stack
.
Popn
()
// x != y
if
x
.
Cmp
(
y
)
!=
0
{
vm
.
stack
.
Push
(
ethutil
.
BigTrue
)
stack
.
Push
(
ethutil
.
BigTrue
)
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
stack
.
Push
(
ethutil
.
BigFalse
)
}
case
oMYADDRESS
:
vm
.
stack
.
Push
(
ethutil
.
BigD
(
addr
))
case
oTXSENDER
:
vm
.
stack
.
Push
(
ethutil
.
BigD
(
vars
.
sender
))
case
oTXVALUE
:
vm
.
stack
.
Push
(
vars
.
txValue
)
case
oTXDATAN
:
vm
.
stack
.
Push
(
big
.
NewInt
(
int64
(
len
(
vars
.
txData
))))
case
oTXDATA
:
v
:=
vm
.
stack
.
Pop
()
// v >= len(data)
if
v
.
Cmp
(
big
.
NewInt
(
int64
(
len
(
vars
.
txData
))))
>=
0
{
vm
.
stack
.
Push
(
ethutil
.
Big
(
"0"
))
}
else
{
vm
.
stack
.
Push
(
ethutil
.
Big
(
vars
.
txData
[
v
.
Uint64
()]))
}
case
oBLK_PREVHASH
:
vm
.
stack
.
Push
(
ethutil
.
BigD
(
vars
.
prevHash
))
case
oBLK_COINBASE
:
vm
.
stack
.
Push
(
ethutil
.
BigD
(
vars
.
coinbase
))
case
oBLK_TIMESTAMP
:
vm
.
stack
.
Push
(
big
.
NewInt
(
vars
.
time
))
case
oBLK_NUMBER
:
vm
.
stack
.
Push
(
big
.
NewInt
(
int64
(
vars
.
blockNumber
)))
case
oBLK_DIFFICULTY
:
vm
.
stack
.
Push
(
vars
.
diff
)
case
oBASEFEE
:
// e = 10^21
e
:=
big
.
NewInt
(
0
)
.
Exp
(
big
.
NewInt
(
10
),
big
.
NewInt
(
21
),
big
.
NewInt
(
0
))
d
:=
new
(
big
.
Rat
)
d
.
SetInt
(
vars
.
diff
)
c
:=
new
(
big
.
Rat
)
c
.
SetFloat64
(
0.5
)
// d = diff / 0.5
d
.
Quo
(
d
,
c
)
// base = floor(d)
base
.
Div
(
d
.
Num
(),
d
.
Denom
())
x
:=
new
(
big
.
Int
)
x
.
Div
(
e
,
base
)
// 0x10 range
case
oAND
:
case
oOR
:
case
oXOR
:
case
oBYTE
:
// x = floor(10^21 / floor(diff^0.5))
vm
.
stack
.
Push
(
x
)
case
oSHA256
,
oSHA3
,
oRIPEMD160
:
// This is probably save
// ceil(pop / 32)
length
:=
int
(
math
.
Ceil
(
float64
(
vm
.
stack
.
Pop
()
.
Uint64
())
/
32.0
))
// New buffer which will contain the concatenated popped items
data
:=
new
(
bytes
.
Buffer
)
for
i
:=
0
;
i
<
length
;
i
++
{
// Encode the number to bytes and have it 32bytes long
num
:=
ethutil
.
NumberToBytes
(
vm
.
stack
.
Pop
()
.
Bytes
(),
256
)
data
.
WriteString
(
string
(
num
))
}
// 0x20 range
case
oSHA3
:
if
op
==
oSHA256
{
vm
.
stack
.
Push
(
base
.
SetBytes
(
ethutil
.
Sha256Bin
(
data
.
Bytes
())))
}
else
if
op
==
oSHA3
{
vm
.
stack
.
Push
(
base
.
SetBytes
(
ethutil
.
Sha3Bin
(
data
.
Bytes
())))
}
else
{
vm
.
stack
.
Push
(
base
.
SetBytes
(
ethutil
.
Ripemd160
(
data
.
Bytes
())))
}
case
oECMUL
:
y
:=
vm
.
stack
.
Pop
()
x
:=
vm
.
stack
.
Pop
()
//n := vm.stack.Pop()
// 0x30 range
case
oADDRESS
:
stack
.
Push
(
ethutil
.
BigD
(
closure
.
Object
()
.
Address
()))
case
oBALANCE
:
stack
.
Push
(
closure
.
Value
)
case
oORIGIN
:
stack
.
Push
(
ethutil
.
BigD
(
vm
.
vars
.
origin
))
case
oCALLER
:
stack
.
Push
(
ethutil
.
BigD
(
closure
.
Callee
()
.
Address
()))
case
oCALLVALUE
:
// FIXME: Original value of the call, not the current value
stack
.
Push
(
closure
.
Value
)
case
oCALLDATA
:
offset
:=
stack
.
Pop
()
mem
.
Set
(
offset
.
Int64
(),
int64
(
len
(
closure
.
Args
)),
closure
.
Args
)
case
oCALLDATASIZE
:
stack
.
Push
(
big
.
NewInt
(
int64
(
len
(
closure
.
Args
))))
case
oGASPRICE
:
// TODO
//if ethutil.Big(x).Cmp(ethutil.Big(y)) {
data
:=
new
(
bytes
.
Buffer
)
data
.
WriteString
(
x
.
String
())
data
.
WriteString
(
y
.
String
())
if
secp256k1
.
VerifyPubkeyValidity
(
data
.
Bytes
())
==
1
{
// 0x40 range
case
oPREVHASH
:
stack
.
Push
(
ethutil
.
BigD
(
vm
.
vars
.
prevHash
))
case
oCOINBASE
:
stack
.
Push
(
ethutil
.
BigD
(
vm
.
vars
.
coinbase
))
case
oTIMESTAMP
:
stack
.
Push
(
big
.
NewInt
(
vm
.
vars
.
time
))
case
oNUMBER
:
stack
.
Push
(
big
.
NewInt
(
int64
(
vm
.
vars
.
blockNumber
)))
case
oDIFFICULTY
:
stack
.
Push
(
vm
.
vars
.
diff
)
case
oGASLIMIT
:
// TODO
}
else
{
// Invalid, push infinity
vm
.
stack
.
Push
(
ethutil
.
Big
(
"0"
))
vm
.
stack
.
Push
(
ethutil
.
Big
(
"0"
))
}
//} else {
// // Invalid, push infinity
// vm.stack.Push("0")
// vm.stack.Push("0")
//}
case
oECADD
:
case
oECSIGN
:
case
oECRECOVER
:
case
oECVALID
:
case
oPUSH
:
pc
++
vm
.
stack
.
Push
(
contract
.
GetMem
(
pc
)
.
BigInt
())
// 0x50 range
case
oPUSH
:
// Push PC+1 on to the stack
pc
.
Add
(
pc
,
ethutil
.
Big1
)
val
:=
closure
.
GetMem
(
pc
)
.
BigInt
()
stack
.
Push
(
val
)
case
oPOP
:
// Pop current value of the stack
vm
.
stack
.
Pop
()
stack
.
Pop
()
case
oDUP
:
// Dup top stack
x
:=
vm
.
stack
.
Pop
()
vm
.
stack
.
Push
(
x
)
vm
.
stack
.
Push
(
x
)
stack
.
Push
(
stack
.
Peek
())
case
oSWAP
:
// Swap two top most values
x
,
y
:=
vm
.
stack
.
Popn
()
vm
.
stack
.
Push
(
y
)
vm
.
stack
.
Push
(
x
)
x
,
y
:=
stack
.
Popn
()
stack
.
Push
(
y
)
stack
.
Push
(
x
)
case
oMLOAD
:
x
:=
vm
.
stack
.
Pop
()
vm
.
stack
.
Push
(
vm
.
mem
[
x
.
String
()])
case
oMSTORE
:
x
,
y
:=
vm
.
stack
.
Popn
()
vm
.
mem
[
x
.
String
()]
=
y
offset
:=
stack
.
Pop
()
stack
.
Push
(
ethutil
.
BigD
(
mem
.
Get
(
offset
.
Int64
(),
32
)))
case
oMSTORE
:
// Store the value at stack top-1 in to memory at location stack top
// Pop value of the stack
val
,
mStart
:=
stack
.
Popn
()
mem
.
Set
(
mStart
.
Int64
(),
32
,
ethutil
.
BigToBytes
(
val
,
256
))
case
oMSTORE8
:
val
,
mStart
:=
stack
.
Popn
()
base
.
And
(
val
,
new
(
big
.
Int
)
.
SetInt64
(
0xff
))
mem
.
Set
(
mStart
.
Int64
(),
32
,
ethutil
.
BigToBytes
(
base
,
256
))
case
oSLOAD
:
// Load the value in storage and push it on the stack
x
:=
vm
.
stack
.
Pop
()
// decode the object as a big integer
decoder
:=
contract
.
Addr
(
x
.
Bytes
())
if
!
decoder
.
IsNil
()
{
vm
.
stack
.
Push
(
decoder
.
BigInt
())
}
else
{
vm
.
stack
.
Push
(
ethutil
.
BigFalse
)
}
loc
:=
stack
.
Pop
()
val
:=
closure
.
GetMem
(
loc
)
stack
.
Push
(
val
.
BigInt
())
case
oSSTORE
:
// Store Y at index X
y
,
x
:=
vm
.
stack
.
Popn
()
addr
:=
ethutil
.
BigToBytes
(
x
,
256
)
fmt
.
Printf
(
" => %x (%v) @ %v"
,
y
.
Bytes
(),
y
,
ethutil
.
BigD
(
addr
))
contract
.
SetAddr
(
addr
,
y
)
//contract.State().Update(string(idx), string(y))
case
oJMP
:
x
:=
int
(
vm
.
stack
.
Pop
()
.
Uint64
())
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
pc
=
x
pc
--
case
oJMPI
:
x
:=
vm
.
stack
.
Pop
()
// Set pc to x if it's non zero
if
x
.
Cmp
(
ethutil
.
BigFalse
)
!=
0
{
pc
=
int
(
x
.
Uint64
())
pc
--
val
,
loc
:=
stack
.
Popn
()
closure
.
SetMem
(
loc
,
ethutil
.
NewValue
(
val
))
case
oJUMP
:
pc
=
stack
.
Pop
()
case
oJUMPI
:
pos
,
cond
:=
stack
.
Popn
()
if
cond
.
Cmp
(
big
.
NewInt
(
0
))
>
0
{
pc
=
pos
}
case
oIND
:
vm
.
stack
.
Push
(
big
.
NewInt
(
int64
(
pc
)))
case
oEXTRO
:
memAddr
:=
vm
.
stack
.
Pop
()
contractAddr
:=
vm
.
stack
.
Pop
()
.
Bytes
()
case
oPC
:
stack
.
Push
(
pc
)
case
oMSIZE
:
stack
.
Push
(
big
.
NewInt
(
int64
(
mem
.
Len
())))
// 0x60 range
case
oCALL
:
// Pop return size and offset
retSize
,
retOffset
:=
stack
.
Popn
()
// Pop input size and offset
inSize
,
inOffset
:=
stack
.
Popn
()
// Get the arguments from the memory
args
:=
mem
.
Get
(
inOffset
.
Int64
(),
inSize
.
Int64
())
// Pop gas and value of the stack.
gas
,
value
:=
stack
.
Popn
()
// Closure addr
addr
:=
stack
.
Pop
()
// Fetch the contract which will serve as the closure body
contract
:=
vm
.
state
.
GetContract
(
addr
.
Bytes
())
// Create a new callable closure
closure
:=
NewClosure
(
closure
,
contract
,
vm
.
state
,
gas
,
value
)
// Executer the closure and get the return value (if any)
ret
:=
closure
.
Call
(
vm
,
args
)
// Push the contract's memory on to the stack
vm
.
stack
.
Push
(
contractMemory
(
state
,
contractAddr
,
memAddr
))
case
oBALANCE
:
// Pushes the balance of the popped value on to the stack
account
:=
state
.
GetAccount
(
vm
.
stack
.
Pop
()
.
Bytes
())
vm
.
stack
.
Push
(
account
.
Amount
)
case
oMKTX
:
addr
,
value
:=
vm
.
stack
.
Popn
()
from
,
length
:=
vm
.
stack
.
Popn
()
mem
.
Set
(
retOffset
.
Int64
(),
retSize
.
Int64
(),
ret
)
case
oRETURN
:
size
,
offset
:=
stack
.
Popn
()
ret
:=
mem
.
Get
(
offset
.
Int64
(),
size
.
Int64
())
makeInlineTx
(
addr
.
Bytes
(),
value
,
from
,
length
,
contract
,
state
)
return
closure
.
Return
(
ret
)
case
oSUICIDE
:
recAddr
:=
vm
.
stack
.
Pop
()
.
Bytes
()
/*
recAddr := stack.Pop().Bytes()
// Purge all memory
deletedMemory := contract.state.Purge()
// Add refunds to the pop'ed address
...
...
@@ -387,30 +308,28 @@ out:
ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr)
break out
*/
default
:
fmt
.
Printf
(
"Invalid OPCODE: %x
\n
"
,
op
)
}
ethutil
.
Config
.
Log
.
Debugln
(
""
)
//vm.stack.Print()
pc
++
ethutil
.
Config
.
Log
.
Debugln
(
"Invalid opcode"
,
op
)
}
state
.
UpdateContract
(
addr
,
contract
)
pc
.
Add
(
pc
,
ethutil
.
Big1
)
}
}
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
)
j
:=
0
j
:=
int64
(
0
)
dataItems
:=
make
([]
string
,
int
(
length
.
Uint64
()))
for
i
:=
from
.
Uint64
();
i
<
length
.
Ui
nt64
();
i
++
{
dataItems
[
j
]
=
contract
.
GetMem
(
j
)
.
Str
()
for
i
:=
from
.
Int64
();
i
<
length
.
I
nt64
();
i
++
{
dataItems
[
j
]
=
contract
.
GetMem
(
big
.
NewInt
(
j
)
)
.
Str
()
j
++
}
tx
:=
NewTransaction
(
addr
,
value
,
dataItems
)
if
tx
.
IsContract
()
{
contract
:=
MakeContract
(
tx
,
state
)
state
.
UpdateContract
(
tx
.
Hash
()[
12
:
],
contract
)
state
.
UpdateContract
(
contract
)
}
else
{
account
:=
state
.
GetAccount
(
tx
.
Recipient
)
account
.
Amount
.
Add
(
account
.
Amount
,
tx
.
Value
)
...
...
ethchain/vm_test.go
View file @
97786d03
package
ethchain
import
(
"
fmt
"
"
bytes
"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"testing"
)
/*
func TestRun(t *testing.T) {
InitFees()
...
...
@@ -104,3 +106,69 @@ func TestRun2(t *testing.T) {
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"
,
"PUSH"
,
"0"
,
"MSTORE"
,
"PUSH"
,
"32"
,
"CALLDATA"
,
"PUSH"
,
"64"
,
"PUSH"
,
"0"
,
"RETURN"
,
})
tx
:=
NewTransaction
(
ContractAddr
,
ethutil
.
Big
(
"100000000000000000000000000000000000000000000000000"
),
script
)
addr
:=
tx
.
Hash
()[
12
:
]
contract
:=
MakeContract
(
tx
,
state
)
state
.
UpdateContract
(
contract
)
callerScript
:=
ethutil
.
Compile
(
"PUSH"
,
1337
,
// Argument
"PUSH"
,
65
,
// argument mem offset
"MSTORE"
,
"PUSH"
,
64
,
// ret size
"PUSH"
,
0
,
// ret offset
"PUSH"
,
32
,
// arg size
"PUSH"
,
65
,
// arg offset
"PUSH"
,
1000
,
/// Gas
"PUSH"
,
0
,
/// value
"PUSH"
,
addr
,
// Sender
"CALL"
,
"PUSH"
,
64
,
"PUSH"
,
0
,
"RETURN"
,
)
callerTx
:=
NewTransaction
(
ContractAddr
,
ethutil
.
Big
(
"100000000000000000000000000000000000000000000000000"
),
callerScript
)
// Contract addr as test address
account
:=
NewAccount
(
ContractAddr
,
big
.
NewInt
(
10000000
))
callerClosure
:=
NewClosure
(
account
,
MakeContract
(
callerTx
,
state
),
state
,
big
.
NewInt
(
1000000000
),
new
(
big
.
Int
))
vm
:=
NewVm
(
state
,
RuntimeVars
{
origin
:
account
.
Address
(),
blockNumber
:
1
,
prevHash
:
ethutil
.
FromHex
(
"5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
),
coinbase
:
ethutil
.
FromHex
(
"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba"
),
time
:
1
,
diff
:
big
.
NewInt
(
256
),
// XXX Tx data? Could be just an argument to the closure instead
txData
:
nil
,
})
ret
:=
callerClosure
.
Call
(
vm
,
nil
)
exp
:=
[]
byte
{
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
44
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
5
,
57
}
if
bytes
.
Compare
(
ret
,
exp
)
!=
0
{
t
.
Errorf
(
"expected return value to be %v, got %v"
,
exp
,
ret
)
}
}
ethutil/common.go
View file @
97786d03
...
...
@@ -33,3 +33,9 @@ func CurrencyToString(num *big.Int) string {
return
fmt
.
Sprintf
(
"%v Wei"
,
num
)
}
var
(
Big1
=
big
.
NewInt
(
1
)
Big0
=
big
.
NewInt
(
0
)
Big256
=
big
.
NewInt
(
0xff
)
)
ethutil/config.go
View file @
97786d03
...
...
@@ -6,6 +6,7 @@ import (
"os"
"os/user"
"path"
"runtime"
)
type
LogType
byte
...
...
@@ -23,6 +24,7 @@ type config struct {
ExecPath
string
Debug
bool
Ver
string
ClientString
string
Pubkey
[]
byte
Seed
bool
}
...
...
@@ -48,11 +50,16 @@ func ReadConfig(base string) *config {
Config
=
&
config
{
ExecPath
:
path
,
Debug
:
true
,
Ver
:
"0.3.1"
}
Config
.
Log
=
NewLogger
(
LogFile
|
LogStd
,
LogLevelDebug
)
Config
.
SetClientString
(
"/Ethereum(G)"
)
}
return
Config
}
func
(
c
*
config
)
SetClientString
(
str
string
)
{
Config
.
ClientString
=
fmt
.
Sprintf
(
"%s nv%s/%s"
,
str
,
c
.
Ver
,
runtime
.
GOOS
)
}
type
LoggerType
byte
const
(
...
...
ethutil/parsing.go
View file @
97786d03
...
...
@@ -7,6 +7,7 @@ import (
// Op codes
var
OpCodes
=
map
[
string
]
byte
{
// 0x0 range - arithmetic ops
"STOP"
:
0x00
,
"ADD"
:
0x01
,
"MUL"
:
0x02
,
...
...
@@ -18,46 +19,60 @@ var OpCodes = map[string]byte{
"EXP"
:
0x08
,
"NEG"
:
0x09
,
"LT"
:
0x0a
,
"LE"
:
0x0b
,
"GT"
:
0x0c
,
"GE"
:
0x0d
,
"EQ"
:
0x0e
,
"NOT"
:
0x0f
,
"MYADDRESS"
:
0x10
,
"TXSENDER"
:
0x11
,
"TXVALUE"
:
0x12
,
"TXDATAN"
:
0x13
,
"TXDATA"
:
0x14
,
"BLK_PREVHASH"
:
0x15
,
"BLK_COINBASE"
:
0x16
,
"BLK_TIMESTAMP"
:
0x17
,
"BLK_NUMBER"
:
0x18
,
"BLK_DIFFICULTY"
:
0x19
,
"BLK_NONCE"
:
0x1a
,
"BASEFEE"
:
0x1b
,
"SHA256"
:
0x20
,
"RIPEMD160"
:
0x21
,
"ECMUL"
:
0x22
,
"ECADD"
:
0x23
,
"ECSIGN"
:
0x24
,
"ECRECOVER"
:
0x25
,
"ECVALID"
:
0x26
,
"SHA3"
:
0x27
,
"PUSH"
:
0x30
,
"POP"
:
0x31
,
"DUP"
:
0x32
,
"SWAP"
:
0x33
,
"MLOAD"
:
0x34
,
"MSTORE"
:
0x35
,
"SLOAD"
:
0x36
,
"SSTORE"
:
0x37
,
"JMP"
:
0x38
,
"JMPI"
:
0x39
,
"IND"
:
0x3a
,
"EXTRO"
:
0x3b
,
"BALANCE"
:
0x3c
,
"MKTX"
:
0x3d
,
"SUICIDE"
:
0x3f
,
"GT"
:
0x0b
,
"EQ"
:
0x0c
,
"NOT"
:
0x0d
,
// 0x10 range - bit ops
"AND"
:
0x10
,
"OR"
:
0x11
,
"XOR"
:
0x12
,
"BYTE"
:
0x13
,
// 0x20 range - crypto
"SHA3"
:
0x20
,
// 0x30 range - closure state
"ADDRESS"
:
0x30
,
"BALANCE"
:
0x31
,
"ORIGIN"
:
0x32
,
"CALLER"
:
0x33
,
"CALLVALUE"
:
0x34
,
"CALLDATA"
:
0x35
,
"CALLDATASIZE"
:
0x36
,
"GASPRICE"
:
0x38
,
// 0x40 range - block operations
"PREVHASH"
:
0x40
,
"COINBASE"
:
0x41
,
"TIMESTAMP"
:
0x42
,
"NUMBER"
:
0x43
,
"DIFFICULTY"
:
0x44
,
"GASLIMIT"
:
0x45
,
// 0x50 range - 'storage' and execution
"PUSH"
:
0x50
,
"POP"
:
0x51
,
"DUP"
:
0x52
,
"SWAP"
:
0x53
,
"MLOAD"
:
0x54
,
"MSTORE"
:
0x55
,
"MSTORE8"
:
0x56
,
"SLOAD"
:
0x57
,
"SSTORE"
:
0x58
,
"JUMP"
:
0x59
,
"JUMPI"
:
0x5a
,
"PC"
:
0x5b
,
"MSIZE"
:
0x5c
,
// 0x60 range - closures
"CREATE"
:
0x60
,
"CALL"
:
0x61
,
"RETURN"
:
0x62
,
// 0x70 range - other
"LOG"
:
0x70
,
"SUICIDE"
:
0x7f
,
}
func
IsOpCode
(
s
string
)
bool
{
...
...
@@ -69,16 +84,30 @@ func IsOpCode(s string) bool {
return
false
}
func
CompileInstr
(
s
string
)
([]
byte
,
error
)
{
isOp
:=
IsOpCode
(
s
)
func
CompileInstr
(
s
interface
{})
([]
byte
,
error
)
{
switch
s
.
(
type
)
{
case
string
:
str
:=
s
.
(
string
)
isOp
:=
IsOpCode
(
str
)
if
isOp
{
return
[]
byte
{
OpCodes
[
s
]},
nil
return
[]
byte
{
OpCodes
[
str
]},
nil
}
num
:=
new
(
big
.
Int
)
num
.
SetString
(
s
,
0
)
_
,
success
:=
num
.
SetString
(
str
,
0
)
// Assume regular bytes during compilation
if
!
success
{
num
.
SetBytes
([]
byte
(
str
))
}
return
num
.
Bytes
(),
nil
case
int
:
return
big
.
NewInt
(
int64
(
s
.
(
int
)))
.
Bytes
(),
nil
case
[]
byte
:
return
BigD
(
s
.
([]
byte
))
.
Bytes
(),
nil
}
return
nil
,
nil
}
func
Instr
(
instr
string
)
(
int
,
[]
string
,
error
)
{
...
...
@@ -99,3 +128,17 @@ func Instr(instr string) (int, []string, error) {
return
op
,
args
[
1
:
7
],
nil
}
// Script compilation functions
// Compiles strings to machine code
func
Compile
(
instructions
...
interface
{})
(
script
[]
string
)
{
script
=
make
([]
string
,
len
(
instructions
))
for
i
,
val
:=
range
instructions
{
instr
,
_
:=
CompileInstr
(
val
)
script
[
i
]
=
string
(
instr
)
}
return
}
ethutil/rlp.go
View file @
97786d03
...
...
@@ -9,6 +9,10 @@ import (
"math/big"
)
type
RlpEncodable
interface
{
RlpEncode
()
[]
byte
}
type
RlpEncoder
struct
{
rlpData
[]
byte
}
...
...
ethutil/trie_test.go
View file @
97786d03
package
ethutil
import
(
"fmt"
"reflect"
"testing"
)
...
...
peer.go
View file @
97786d03
...
...
@@ -7,7 +7,6 @@ import (
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"net"
"runtime"
"strconv"
"strings"
"sync/atomic"
...
...
@@ -160,7 +159,7 @@ func NewOutboundPeer(addr string, ethereum *Ethereum, caps Caps) *Peer {
connected
:
0
,
disconnect
:
0
,
caps
:
caps
,
Version
:
fmt
.
Sprintf
(
"/Ethereum(G) v%s/%s"
,
ethutil
.
Config
.
Ver
,
runtime
.
GOOS
)
,
Version
:
ethutil
.
Config
.
ClientString
,
}
// Set up the connection in another goroutine so we don't block the main thread
...
...
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