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
4b13f93a
Commit
4b13f93a
authored
May 20, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/poc5-rc7'
parents
6efdd216
c37b3cef
Changes
23
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
377 additions
and
278 deletions
+377
-278
README.md
README.md
+1
-1
block.go
ethchain/block.go
+71
-12
block_chain.go
ethchain/block_chain.go
+21
-4
block_chain_test.go
ethchain/block_chain_test.go
+14
-3
dagger.go
ethchain/dagger.go
+2
-2
genesis.go
ethchain/genesis.go
+12
-6
state.go
ethchain/state.go
+15
-34
state_manager.go
ethchain/state_manager.go
+51
-60
state_object.go
ethchain/state_object.go
+12
-9
state_object_test.go
ethchain/state_object_test.go
+25
-0
transaction.go
ethchain/transaction.go
+6
-8
transaction_pool.go
ethchain/transaction_pool.go
+6
-18
vm.go
ethchain/vm.go
+1
-2
vm_test.go
ethchain/vm_test.go
+1
-1
ethereum.go
ethereum.go
+2
-2
miner.go
ethminer/miner.go
+17
-30
pub.go
ethpub/pub.go
+2
-2
types.go
ethpub/types.go
+8
-0
common.go
ethutil/common.go
+13
-13
common_test.go
ethutil/common_test.go
+3
-3
config.go
ethutil/config.go
+15
-12
reactor.go
ethutil/reactor.go
+2
-1
peer.go
peer.go
+77
-55
No files found.
README.md
View file @
4b13f93a
...
...
@@ -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 5.0 RC
6
". For build instructions see the
[
Wiki
](
https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go
)
).
of Concept 5.0 RC
7
". 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/block.go
View file @
4b13f93a
...
...
@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"strconv"
"time"
)
...
...
@@ -40,6 +41,14 @@ type Block struct {
Difficulty
*
big
.
Int
// Creation time
Time
int64
// The block number
Number
*
big
.
Int
// Minimum Gas Price
MinGasPrice
*
big
.
Int
// Gas limit
GasLimit
*
big
.
Int
// Gas used
GasUsed
*
big
.
Int
// Extra data
Extra
string
// Block Nonce for verification
...
...
@@ -122,7 +131,7 @@ func (block *Block) Transactions() []*Transaction {
}
func
(
block
*
Block
)
PayFee
(
addr
[]
byte
,
fee
*
big
.
Int
)
bool
{
contract
:=
block
.
state
.
Get
Contra
ct
(
addr
)
contract
:=
block
.
state
.
Get
StateObje
ct
(
addr
)
// If we can't pay the fee return
if
contract
==
nil
||
contract
.
Amount
.
Cmp
(
fee
)
<
0
/* amount < fee */
{
fmt
.
Println
(
"Contract has insufficient funds"
,
contract
.
Amount
,
fee
)
...
...
@@ -206,7 +215,12 @@ func (block *Block) SetUncles(uncles []*Block) {
func
(
block
*
Block
)
SetTransactions
(
txs
[]
*
Transaction
)
{
block
.
transactions
=
txs
block
.
TxSha
=
ethutil
.
Sha3Bin
(
ethutil
.
Encode
(
block
.
rlpTxs
()))
trie
:=
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
""
)
for
i
,
tx
:=
range
txs
{
trie
.
Update
(
strconv
.
Itoa
(
i
),
string
(
tx
.
RlpEncode
()))
}
block
.
TxSha
=
trie
.
Root
.
([]
byte
)
}
func
(
block
*
Block
)
Value
()
*
ethutil
.
Value
{
...
...
@@ -233,9 +247,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
header
.
Get
(
3
)
.
Val
))
block
.
TxSha
=
header
.
Get
(
4
)
.
Bytes
()
block
.
Difficulty
=
header
.
Get
(
5
)
.
BigInt
()
block
.
Time
=
int64
(
header
.
Get
(
6
)
.
BigInt
()
.
Uint64
())
block
.
Extra
=
header
.
Get
(
7
)
.
Str
()
block
.
Nonce
=
header
.
Get
(
8
)
.
Bytes
()
block
.
Number
=
header
.
Get
(
6
)
.
BigInt
()
block
.
MinGasPrice
=
header
.
Get
(
7
)
.
BigInt
()
block
.
GasLimit
=
header
.
Get
(
8
)
.
BigInt
()
block
.
GasUsed
=
header
.
Get
(
9
)
.
BigInt
()
block
.
Time
=
int64
(
header
.
Get
(
10
)
.
BigInt
()
.
Uint64
())
block
.
Extra
=
header
.
Get
(
11
)
.
Str
()
block
.
Nonce
=
header
.
Get
(
12
)
.
Bytes
()
block
.
contractStates
=
make
(
map
[
string
]
*
ethutil
.
Trie
)
// Tx list might be empty if this is an uncle. Uncles only have their
...
...
@@ -270,21 +288,21 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
block
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
header
.
Get
(
3
)
.
Val
))
block
.
TxSha
=
header
.
Get
(
4
)
.
Bytes
()
block
.
Difficulty
=
header
.
Get
(
5
)
.
BigInt
()
block
.
Time
=
int64
(
header
.
Get
(
6
)
.
BigInt
()
.
Uint64
())
block
.
Extra
=
header
.
Get
(
7
)
.
Str
()
block
.
Nonce
=
header
.
Get
(
8
)
.
Bytes
()
block
.
Number
=
header
.
Get
(
6
)
.
BigInt
()
block
.
MinGasPrice
=
header
.
Get
(
7
)
.
BigInt
()
block
.
GasLimit
=
header
.
Get
(
8
)
.
BigInt
()
block
.
GasUsed
=
header
.
Get
(
9
)
.
BigInt
()
block
.
Time
=
int64
(
header
.
Get
(
10
)
.
BigInt
()
.
Uint64
())
block
.
Extra
=
header
.
Get
(
11
)
.
Str
()
block
.
Nonce
=
header
.
Get
(
12
)
.
Bytes
()
return
block
}
func
(
block
*
Block
)
String
()
string
{
return
fmt
.
Sprintf
(
"Block(%x):
\n
PrevHash:%x
\n
UncleSha:%x
\n
Coinbase:%x
\n
Root:%x
\n
TxSha:%x
\n
Diff:%v
\n
Time:%d
\n
Nonce:%x
\n
Txs:%d
\n
"
,
block
.
Hash
(),
block
.
PrevHash
,
block
.
UncleSha
,
block
.
Coinbase
,
block
.
state
.
trie
.
Root
,
block
.
TxSha
,
block
.
Difficulty
,
block
.
Time
,
block
.
Nonce
,
len
(
block
.
transactions
))
}
func
(
block
*
Block
)
GetRoot
()
interface
{}
{
return
block
.
state
.
trie
.
Root
}
//////////// UNEXPORTED /////////////////
func
(
block
*
Block
)
header
()
[]
interface
{}
{
return
[]
interface
{}{
// Sha of the previous block
...
...
@@ -299,6 +317,14 @@ func (block *Block) header() []interface{} {
block
.
TxSha
,
// Current block Difficulty
block
.
Difficulty
,
// The block number
block
.
Number
,
// Block minimum gas price
block
.
MinGasPrice
,
// Block upper gas bound
block
.
GasLimit
,
// Block gas used
block
.
GasUsed
,
// Time the block was found?
block
.
Time
,
// Extra data
...
...
@@ -307,3 +333,36 @@ func (block *Block) header() []interface{} {
block
.
Nonce
,
}
}
func
(
block
*
Block
)
String
()
string
{
return
fmt
.
Sprintf
(
`
BLOCK(%x):
PrevHash: %x
UncleSha: %x
Coinbase: %x
Root: %x
TxSha: %x
Difficulty: %v
Number: %v
MinGas: %v
MaxLimit: %v
GasUsed: %v
Time: %v
Extra: %v
Nonce: %x
`
,
block
.
Hash
(),
block
.
PrevHash
,
block
.
UncleSha
,
block
.
Coinbase
,
block
.
state
.
trie
.
Root
,
block
.
TxSha
,
block
.
Difficulty
,
block
.
Number
,
block
.
MinGasPrice
,
block
.
GasLimit
,
block
.
GasUsed
,
block
.
Time
,
block
.
Extra
,
block
.
Nonce
)
}
ethchain/block_chain.go
View file @
4b13f93a
...
...
@@ -70,6 +70,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
diff
.
Mul
(
diff
,
mul
)
diff
.
Add
(
diff
,
bc
.
CurrentBlock
.
Difficulty
)
block
.
Difficulty
=
diff
block
.
Number
=
new
(
big
.
Int
)
.
Add
(
bc
.
CurrentBlock
.
Number
,
ethutil
.
Big1
)
// max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024)
base
:=
new
(
big
.
Int
)
base2
:=
new
(
big
.
Int
)
parentGL
:=
bc
.
CurrentBlock
.
GasLimit
parentUsed
:=
bc
.
CurrentBlock
.
GasUsed
base
.
Mul
(
parentGL
,
big
.
NewInt
(
1024
-
1
))
base2
.
Mul
(
parentUsed
,
big
.
NewInt
(
6
))
base2
.
Div
(
base2
,
big
.
NewInt
(
5
))
base
.
Add
(
base
,
base2
)
base
.
Div
(
base
,
big
.
NewInt
(
1024
))
block
.
GasLimit
=
ethutil
.
BigMax
(
big
.
NewInt
(
10000
),
base
)
}
return
block
...
...
@@ -127,7 +143,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte
log
.
Println
(
"[CHAIN] We have found the common parent block, breaking"
)
break
}
log
.
Println
(
"Checking incoming blocks:"
)
chainDifficulty
.
Add
(
chainDifficulty
,
bc
.
CalculateBlockTD
(
block
))
}
...
...
@@ -182,6 +197,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error {
// XXX Why are we resetting? This is the block chain, it has nothing to do with states
//bc.Ethereum.StateManager().PrepareDefault(returnTo)
// Manually reset the last sync block
err
:=
ethutil
.
Config
.
Db
.
Delete
(
lastBlock
.
Hash
())
if
err
!=
nil
{
return
err
...
...
@@ -261,13 +277,14 @@ func AddTestNetFunds(block *Block) {
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"
,
// Vit
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4"
,
// Alex
"2ef47100e0787b915105fd5e3f4ff6752079d5cb"
,
// Maran
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826"
,
// Roman
}
{
//log.Println("2^200 Wei to", addr)
codedAddr
:=
ethutil
.
FromHex
(
addr
)
account
:=
block
.
state
.
GetAccount
(
codedAddr
)
account
.
Amount
=
ethutil
.
BigPow
(
2
,
200
)
block
.
state
.
UpdateStateObject
(
account
)
}
log
.
Printf
(
"%x
\n
"
,
block
.
RlpEncode
())
}
func
(
bc
*
BlockChain
)
setLastBlock
()
{
...
...
@@ -279,7 +296,7 @@ func (bc *BlockChain) setLastBlock() {
bc
.
LastBlockHash
=
block
.
Hash
()
bc
.
LastBlockNumber
=
info
.
Number
log
.
Print
f
(
"[CHAIN] Last known block height #%d
\n
"
,
bc
.
LastBlockNumber
)
ethutil
.
Config
.
Log
.
Info
f
(
"[CHAIN] Last known block height #%d
\n
"
,
bc
.
LastBlockNumber
)
}
else
{
AddTestNetFunds
(
bc
.
genesisBlock
)
...
...
@@ -294,7 +311,7 @@ func (bc *BlockChain) setLastBlock() {
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc
.
TD
=
ethutil
.
BigD
(
ethutil
.
Config
.
Db
.
LastKnownTD
())
log
.
Print
f
(
"Last block: %x
\n
"
,
bc
.
CurrentBlock
.
Hash
())
ethutil
.
Config
.
Log
.
Info
f
(
"Last block: %x
\n
"
,
bc
.
CurrentBlock
.
Hash
())
}
func
(
bc
*
BlockChain
)
SetTotalDifficulty
(
td
*
big
.
Int
)
{
...
...
ethchain/block_chain_test.go
View file @
4b13f93a
...
...
@@ -18,6 +18,18 @@ type TestManager struct {
Blocks
[]
*
Block
}
func
(
s
*
TestManager
)
IsListening
()
bool
{
return
false
}
func
(
s
*
TestManager
)
IsMining
()
bool
{
return
false
}
func
(
s
*
TestManager
)
PeerCount
()
int
{
return
0
}
func
(
s
*
TestManager
)
BlockChain
()
*
BlockChain
{
return
s
.
blockChain
}
...
...
@@ -38,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) {
}
func
NewTestManager
()
*
TestManager
{
ethutil
.
ReadConfig
(
".ethtest"
)
ethutil
.
ReadConfig
(
".ethtest"
,
ethutil
.
LogStd
)
db
,
err
:=
ethdb
.
NewMemDatabase
()
if
err
!=
nil
{
...
...
@@ -62,8 +74,7 @@ func NewTestManager() *TestManager {
func
(
tm
*
TestManager
)
AddFakeBlock
(
blk
[]
byte
)
error
{
block
:=
NewBlockFromBytes
(
blk
)
tm
.
Blocks
=
append
(
tm
.
Blocks
,
block
)
tm
.
StateManager
()
.
PrepareDefault
(
block
)
err
:=
tm
.
StateManager
()
.
ProcessBlock
(
block
,
false
)
err
:=
tm
.
StateManager
()
.
ProcessBlock
(
tm
.
StateManager
()
.
CurrentState
(),
block
,
false
)
return
err
}
func
(
tm
*
TestManager
)
CreateChain1
()
error
{
...
...
ethchain/dagger.go
View file @
4b13f93a
...
...
@@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
for
{
select
{
case
<-
reactChan
:
log
.
Print
ln
(
"[POW] Received reactor event; breaking out."
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[POW] Received reactor event; breaking out."
)
return
nil
default
:
i
++
if
i
%
1234567
==
0
{
elapsed
:=
time
.
Now
()
.
UnixNano
()
-
start
hashes
:=
((
float64
(
1e9
)
/
float64
(
elapsed
))
*
float64
(
i
))
/
1000
log
.
Print
ln
(
"[POW] Hashing @"
,
int64
(
hashes
),
"khash"
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[POW] Hashing @"
,
int64
(
hashes
),
"khash"
)
}
sha
:=
ethutil
.
Sha3Bin
(
big
.
NewInt
(
r
.
Int63
())
.
Bytes
())
...
...
ethchain/genesis.go
View file @
4b13f93a
...
...
@@ -15,7 +15,6 @@ var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{}))
var
GenesisHeader
=
[]
interface
{}{
// Previous hash (none)
//"",
ZeroHash256
,
// Sha of uncles
ethutil
.
Sha3Bin
(
ethutil
.
Encode
([]
interface
{}{})),
...
...
@@ -23,15 +22,22 @@ var GenesisHeader = []interface{}{
ZeroHash160
,
// Root state
""
,
// Sha of transactions
//EmptyShaList,
ethutil
.
Sha3Bin
(
ethutil
.
Encode
([]
interface
{}{})),
// tx sha
ZeroHash256
,
// Difficulty
ethutil
.
BigPow
(
2
,
22
),
// Number
ethutil
.
Big0
,
// Block minimum gas price
ethutil
.
Big0
,
// Block upper gas bound
big
.
NewInt
(
1000000
),
// Block gas used
ethutil
.
Big0
,
// Time
int64
(
0
)
,
ethutil
.
Big0
,
// Extra
""
,
nil
,
// Nonce
ethutil
.
Sha3Bin
(
big
.
NewInt
(
42
)
.
Bytes
()),
}
...
...
ethchain/state.go
View file @
4b13f93a
...
...
@@ -49,28 +49,6 @@ func (s *State) Purge() int {
return
s
.
trie
.
NewIterator
()
.
Purge
()
}
// XXX Deprecated
func
(
s
*
State
)
GetContract
(
addr
[]
byte
)
*
StateObject
{
data
:=
s
.
trie
.
Get
(
string
(
addr
))
if
data
==
""
{
return
nil
}
// build contract
contract
:=
NewStateObjectFromBytes
(
addr
,
[]
byte
(
data
))
// Check if there's a cached state for this contract
cachedState
:=
s
.
states
[
string
(
addr
)]
if
cachedState
!=
nil
{
contract
.
state
=
cachedState
}
else
{
// If it isn't cached, cache the state
s
.
states
[
string
(
addr
)]
=
contract
.
state
}
return
contract
}
func
(
s
*
State
)
GetStateObject
(
addr
[]
byte
)
*
StateObject
{
data
:=
s
.
trie
.
Get
(
string
(
addr
))
if
data
==
""
{
...
...
@@ -91,6 +69,21 @@ func (s *State) GetStateObject(addr []byte) *StateObject {
return
stateObject
}
// Updates any given state object
func
(
s
*
State
)
UpdateStateObject
(
object
*
StateObject
)
{
addr
:=
object
.
Address
()
if
object
.
state
!=
nil
{
s
.
states
[
string
(
addr
)]
=
object
.
state
}
ethutil
.
Config
.
Db
.
Put
(
ethutil
.
Sha3Bin
(
object
.
Script
()),
object
.
Script
())
s
.
trie
.
Update
(
string
(
addr
),
string
(
object
.
RlpEncode
()))
s
.
manifest
.
AddObjectChange
(
object
)
}
func
(
s
*
State
)
SetStateObject
(
stateObject
*
StateObject
)
{
s
.
states
[
string
(
stateObject
.
address
)]
=
stateObject
.
state
...
...
@@ -116,18 +109,6 @@ func (s *State) Copy() *State {
return
NewState
(
s
.
trie
.
Copy
())
}
// Updates any given state object
func
(
s
*
State
)
UpdateStateObject
(
object
*
StateObject
)
{
addr
:=
object
.
Address
()
if
object
.
state
!=
nil
{
s
.
states
[
string
(
addr
)]
=
object
.
state
}
s
.
trie
.
Update
(
string
(
addr
),
string
(
object
.
RlpEncode
()))
s
.
manifest
.
AddObjectChange
(
object
)
}
func
(
s
*
State
)
Put
(
key
,
object
[]
byte
)
{
s
.
trie
.
Update
(
string
(
key
),
string
(
object
))
}
...
...
ethchain/state_manager.go
View file @
4b13f93a
...
...
@@ -39,20 +39,13 @@ type StateManager struct {
// The ethereum manager interface
Ethereum
EthManager
// The managed states
// Processor state. Anything processed will be applied to this
// state
procState
*
State
// Comparative state it used for comparing and validating end
// results
compState
*
State
// Transiently state. The trans state isn't ever saved, validated and
// it could be used for setting account nonces without effecting
// the main states.
transState
*
State
// Manifest for keeping changes regarding state objects. See `notify`
// XXX Should we move the manifest to the State object. Benefit:
// * All states can keep their own local changes
//manifest *Manifest
// Mining state. The mining state is used purely and solely by the mining
// operation.
miningState
*
State
}
func
NewStateManager
(
ethereum
EthManager
)
*
StateManager
{
...
...
@@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager {
Pow
:
&
EasyPow
{},
Ethereum
:
ethereum
,
bc
:
ethereum
.
BlockChain
(),
//manifest: NewManifest(),
}
sm
.
procState
=
ethereum
.
BlockChain
()
.
CurrentBlock
.
State
()
sm
.
transState
=
sm
.
procState
.
Copy
()
sm
.
transState
=
ethereum
.
BlockChain
()
.
CurrentBlock
.
State
()
.
Copy
()
sm
.
miningState
=
ethereum
.
BlockChain
()
.
CurrentBlock
.
State
()
.
Copy
()
return
sm
}
func
(
sm
*
StateManager
)
Proc
State
()
*
State
{
return
sm
.
procState
func
(
sm
*
StateManager
)
Current
State
()
*
State
{
return
sm
.
Ethereum
.
BlockChain
()
.
CurrentBlock
.
State
()
}
func
(
sm
*
StateManager
)
TransState
()
*
State
{
return
sm
.
transState
}
func
(
sm
*
StateManager
)
MiningState
()
*
State
{
return
sm
.
miningState
}
func
(
sm
*
StateManager
)
NewMiningState
()
*
State
{
sm
.
miningState
=
sm
.
Ethereum
.
BlockChain
()
.
CurrentBlock
.
State
()
.
Copy
()
return
sm
.
miningState
}
func
(
sm
*
StateManager
)
BlockChain
()
*
BlockChain
{
return
sm
.
bc
}
func
(
sm
*
StateManager
)
MakeContract
(
tx
*
Transaction
)
*
StateObject
{
contract
:=
MakeContract
(
tx
,
s
m
.
procS
tate
)
func
(
sm
*
StateManager
)
MakeContract
(
state
*
State
,
tx
*
Transaction
)
*
StateObject
{
contract
:=
MakeContract
(
tx
,
state
)
if
contract
!=
nil
{
s
m
.
procState
.
states
[
string
(
tx
.
Hash
()[
12
:
]
)]
=
contract
.
state
s
tate
.
states
[
string
(
tx
.
CreationAddress
()
)]
=
contract
.
state
return
contract
}
...
...
@@ -95,7 +97,7 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject {
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func
(
sm
*
StateManager
)
ApplyTransactions
(
block
*
Block
,
txs
[]
*
Transaction
)
{
func
(
sm
*
StateManager
)
ApplyTransactions
(
state
*
State
,
block
*
Block
,
txs
[]
*
Transaction
)
{
// Process each transaction/contract
for
_
,
tx
:=
range
txs
{
// If there's no recipient, it's a contract
...
...
@@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
if
tx
.
IsContract
()
{
err
:=
sm
.
Ethereum
.
TxPool
()
.
ProcessTransaction
(
tx
,
block
,
false
)
if
err
==
nil
{
contract
:=
sm
.
MakeContract
(
tx
)
contract
:=
sm
.
MakeContract
(
state
,
tx
)
if
contract
!=
nil
{
sm
.
EvalScript
(
contract
.
Init
(),
contract
,
tx
,
block
)
sm
.
EvalScript
(
state
,
contract
.
Init
(),
contract
,
tx
,
block
)
}
else
{
ethutil
.
Config
.
Log
.
Infoln
(
"[STATE] Unable to create contract"
)
}
...
...
@@ -115,9 +117,10 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
}
}
else
{
err
:=
sm
.
Ethereum
.
TxPool
()
.
ProcessTransaction
(
tx
,
block
,
false
)
contract
:=
sm
.
procState
.
GetContract
(
tx
.
Recipient
)
contract
:=
state
.
GetStateObject
(
tx
.
Recipient
)
ethutil
.
Config
.
Log
.
Debugf
(
"contract recip %x
\n
"
,
tx
.
Recipient
)
if
err
==
nil
&&
len
(
contract
.
Script
())
>
0
{
sm
.
EvalScript
(
contract
.
Script
(),
contract
,
tx
,
block
)
sm
.
EvalScript
(
state
,
contract
.
Script
(),
contract
,
tx
,
block
)
}
else
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Infoln
(
"[STATE] process:"
,
err
)
}
...
...
@@ -125,20 +128,8 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
}
}
// The prepare function, prepares the state manager for the next
// "ProcessBlock" action.
func
(
sm
*
StateManager
)
Prepare
(
processor
*
State
,
comparative
*
State
)
{
sm
.
compState
=
comparative
sm
.
procState
=
processor
}
// Default prepare function
func
(
sm
*
StateManager
)
PrepareDefault
(
block
*
Block
)
{
sm
.
Prepare
(
sm
.
BlockChain
()
.
CurrentBlock
.
State
(),
block
.
State
())
}
// Block processing and validating with a given (temporarily) state
func
(
sm
*
StateManager
)
ProcessBlock
(
block
*
Block
,
dontReact
bool
)
error
{
func
(
sm
*
StateManager
)
ProcessBlock
(
state
*
State
,
block
*
Block
,
dontReact
bool
)
error
{
// Processing a blocks may never happen simultaneously
sm
.
mutex
.
Lock
()
defer
sm
.
mutex
.
Unlock
()
...
...
@@ -153,7 +144,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// we don't want to undo but since undo only happens on dirty
// nodes this won't happen because Commit would have been called
// before that.
defer
s
m
.
bc
.
CurrentBlock
.
Undo
()
defer
s
tate
.
Reset
()
// Check if we have the parent hash, if it isn't known we discard it
// Reasons might be catching up or simply an invalid block
...
...
@@ -162,7 +153,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
}
// Process the transactions on to current block
sm
.
ApplyTransactions
(
sm
.
bc
.
CurrentBlock
,
block
.
Transactions
())
sm
.
ApplyTransactions
(
s
tate
,
s
m
.
bc
.
CurrentBlock
,
block
.
Transactions
())
// Block validation
if
err
:=
sm
.
ValidateBlock
(
block
);
err
!=
nil
{
...
...
@@ -172,35 +163,35 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// I'm not sure, but I don't know if there should be thrown
// any errors at this time.
if
err
:=
sm
.
AccumelateRewards
(
block
);
err
!=
nil
{
if
err
:=
sm
.
AccumelateRewards
(
state
,
block
);
err
!=
nil
{
fmt
.
Println
(
"[SM] Error accumulating reward"
,
err
)
return
err
}
if
!
sm
.
compState
.
Cmp
(
sm
.
procState
)
{
return
fmt
.
Errorf
(
"Invalid merkle root. Expected %x, got %x"
,
sm
.
compState
.
trie
.
Root
,
sm
.
procState
.
trie
.
Root
)
//if !sm.compState.Cmp(state) {
if
!
block
.
State
()
.
Cmp
(
state
)
{
return
fmt
.
Errorf
(
"Invalid merkle root. Expected %x, got %x"
,
block
.
State
()
.
trie
.
Root
,
state
.
trie
.
Root
)
}
// Calculate the new total difficulty and sync back to the db
if
sm
.
CalculateTD
(
block
)
{
// Sync the current block's state to the database and cancelling out the deferred Undo
s
m
.
procS
tate
.
Sync
()
state
.
Sync
()
// Add the block to the chain
sm
.
bc
.
Add
(
block
)
sm
.
notifyChanges
(
state
)
ethutil
.
Config
.
Log
.
Infof
(
"[STATE] Added block #%d (%x)
\n
"
,
block
.
BlockInfo
()
.
Number
,
block
.
Hash
())
if
dontReact
==
false
{
sm
.
Ethereum
.
Reactor
()
.
Post
(
"newBlock"
,
block
)
sm
.
notifyChanges
()
sm
.
procState
.
manifest
.
Reset
()
state
.
manifest
.
Reset
()
}
sm
.
Ethereum
.
Broadcast
(
ethwire
.
MsgBlockTy
,
[]
interface
{}{
block
.
Value
()
.
Val
})
sm
.
Ethereum
.
TxPool
()
.
RemoveInvalid
(
s
m
.
procS
tate
)
sm
.
Ethereum
.
TxPool
()
.
RemoveInvalid
(
state
)
}
else
{
fmt
.
Println
(
"total diff failed"
)
}
...
...
@@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int {
return
UncleReward
}
func
(
sm
*
StateManager
)
AccumelateRewards
(
block
*
Block
)
error
{
func
(
sm
*
StateManager
)
AccumelateRewards
(
state
*
State
,
block
*
Block
)
error
{
// Get the account associated with the coinbase
account
:=
s
m
.
procS
tate
.
GetAccount
(
block
.
Coinbase
)
account
:=
state
.
GetAccount
(
block
.
Coinbase
)
// Reward amount of ether to the coinbase address
account
.
AddAmount
(
CalculateBlockReward
(
block
,
len
(
block
.
Uncles
)))
addr
:=
make
([]
byte
,
len
(
block
.
Coinbase
))
copy
(
addr
,
block
.
Coinbase
)
s
m
.
procS
tate
.
UpdateStateObject
(
account
)
state
.
UpdateStateObject
(
account
)
for
_
,
uncle
:=
range
block
.
Uncles
{
uncleAccount
:=
s
m
.
procS
tate
.
GetAccount
(
uncle
.
Coinbase
)
uncleAccount
:=
state
.
GetAccount
(
uncle
.
Coinbase
)
uncleAccount
.
AddAmount
(
CalculateUncleReward
(
uncle
))
s
m
.
procS
tate
.
UpdateStateObject
(
uncleAccount
)
state
.
UpdateStateObject
(
uncleAccount
)
}
return
nil
...
...
@@ -300,8 +291,8 @@ func (sm *StateManager) Stop() {
sm
.
bc
.
Stop
()
}
func
(
sm
*
StateManager
)
EvalScript
(
script
[]
byte
,
object
*
StateObject
,
tx
*
Transaction
,
block
*
Block
)
{
account
:=
s
m
.
procS
tate
.
GetAccount
(
tx
.
Sender
())
func
(
sm
*
StateManager
)
EvalScript
(
s
tate
*
State
,
s
cript
[]
byte
,
object
*
StateObject
,
tx
*
Transaction
,
block
*
Block
)
{
account
:=
state
.
GetAccount
(
tx
.
Sender
())
err
:=
account
.
ConvertGas
(
tx
.
Gas
,
tx
.
GasPrice
)
if
err
!=
nil
{
...
...
@@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
return
}
closure
:=
NewClosure
(
account
,
object
,
script
,
s
m
.
procS
tate
,
tx
.
Gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
s
m
.
procS
tate
,
sm
,
RuntimeVars
{
closure
:=
NewClosure
(
account
,
object
,
script
,
state
,
tx
.
Gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
state
,
sm
,
RuntimeVars
{
Origin
:
account
.
Address
(),
BlockNumber
:
block
.
BlockInfo
()
.
Number
,
PrevHash
:
block
.
PrevHash
,
...
...
@@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
closure
.
Call
(
vm
,
tx
.
Data
,
nil
)
// Update the account (refunds)
s
m
.
procS
tate
.
UpdateStateObject
(
account
)
s
m
.
procS
tate
.
UpdateStateObject
(
object
)
state
.
UpdateStateObject
(
account
)
state
.
UpdateStateObject
(
object
)
}
func
(
sm
*
StateManager
)
notifyChanges
()
{
for
addr
,
stateObject
:=
range
s
m
.
procS
tate
.
manifest
.
objectChanges
{
func
(
sm
*
StateManager
)
notifyChanges
(
state
*
State
)
{
for
addr
,
stateObject
:=
range
state
.
manifest
.
objectChanges
{
sm
.
Ethereum
.
Reactor
()
.
Post
(
"object:"
+
addr
,
stateObject
)
}
for
stateObjectAddr
,
mappedObjects
:=
range
s
m
.
procS
tate
.
manifest
.
storageChanges
{
for
stateObjectAddr
,
mappedObjects
:=
range
state
.
manifest
.
storageChanges
{
for
addr
,
value
:=
range
mappedObjects
{
sm
.
Ethereum
.
Reactor
()
.
Post
(
"storage:"
+
stateObjectAddr
+
":"
+
addr
,
&
StorageState
{[]
byte
(
stateObjectAddr
),
[]
byte
(
addr
),
value
})
}
...
...
ethchain/state_object.go
View file @
4b13f93a
...
...
@@ -11,6 +11,7 @@ type StateObject struct {
address
[]
byte
// Shared attributes
Amount
*
big
.
Int
ScriptHash
[]
byte
Nonce
uint64
// Contract related attributes
state
*
State
...
...
@@ -22,12 +23,10 @@ type StateObject struct {
func
MakeContract
(
tx
*
Transaction
,
state
*
State
)
*
StateObject
{
// Create contract if there's no recipient
if
tx
.
IsContract
()
{
// FIXME
addr
:=
tx
.
Hash
()[
12
:
]
addr
:=
tx
.
CreationAddress
()
value
:=
tx
.
Value
contract
:=
NewContract
(
addr
,
value
,
[]
byte
(
""
))
state
.
UpdateStateObject
(
contract
)
contract
:=
NewContract
(
addr
,
value
,
ZeroHash256
)
contract
.
script
=
tx
.
Data
contract
.
initScript
=
tx
.
Init
...
...
@@ -146,9 +145,10 @@ func (c *StateObject) RlpEncode() []byte {
if
c
.
state
!=
nil
{
root
=
c
.
state
.
trie
.
Root
}
else
{
root
=
nil
root
=
ZeroHash256
}
return
ethutil
.
Encode
([]
interface
{}{
c
.
Amount
,
c
.
Nonce
,
root
,
c
.
script
})
return
ethutil
.
Encode
([]
interface
{}{
c
.
Amount
,
c
.
Nonce
,
root
,
ethutil
.
Sha3Bin
(
c
.
script
)})
}
func
(
c
*
StateObject
)
RlpDecode
(
data
[]
byte
)
{
...
...
@@ -157,7 +157,10 @@ func (c *StateObject) RlpDecode(data []byte) {
c
.
Amount
=
decoder
.
Get
(
0
)
.
BigInt
()
c
.
Nonce
=
decoder
.
Get
(
1
)
.
Uint
()
c
.
state
=
NewState
(
ethutil
.
NewTrie
(
ethutil
.
Config
.
Db
,
decoder
.
Get
(
2
)
.
Interface
()))
c
.
script
=
decoder
.
Get
(
3
)
.
Bytes
()
c
.
ScriptHash
=
decoder
.
Get
(
3
)
.
Bytes
()
c
.
script
,
_
=
ethutil
.
Config
.
Db
.
Get
(
c
.
ScriptHash
)
}
// Storage change object. Used by the manifest for notifying changes to
...
...
ethchain/state_object_test.go
0 → 100644
View file @
4b13f93a
package
ethchain
import
(
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"testing"
)
func
TestSync
(
t
*
testing
.
T
)
{
ethutil
.
ReadConfig
(
""
,
ethutil
.
LogStd
)
db
,
_
:=
ethdb
.
NewMemDatabase
()
state
:=
NewState
(
ethutil
.
NewTrie
(
db
,
""
))
contract
:=
NewContract
([]
byte
(
"aa"
),
ethutil
.
Big1
,
ZeroHash256
)
contract
.
script
=
[]
byte
{
42
}
state
.
UpdateStateObject
(
contract
)
state
.
Sync
()
object
:=
state
.
GetStateObject
([]
byte
(
"aa"
))
fmt
.
Printf
(
"%x
\n
"
,
object
.
Script
())
}
ethchain/transaction.go
View file @
4b13f93a
...
...
@@ -60,7 +60,7 @@ func (tx *Transaction) IsContract() bool {
}
func
(
tx
*
Transaction
)
CreationAddress
()
[]
byte
{
return
tx
.
Hash
(
)[
12
:
]
return
ethutil
.
Sha3Bin
(
ethutil
.
NewValue
([]
interface
{}{
tx
.
Sender
(),
tx
.
Nonce
})
.
Encode
()
)[
12
:
]
}
func
(
tx
*
Transaction
)
Signature
(
key
[]
byte
)
[]
byte
{
...
...
@@ -109,10 +109,8 @@ func (tx *Transaction) Sign(privk []byte) error {
return
nil
}
// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ]
// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ]
func
(
tx
*
Transaction
)
RlpData
()
interface
{}
{
data
:=
[]
interface
{}{
tx
.
Nonce
,
tx
.
Value
,
tx
.
GasPrice
,
tx
.
Gas
,
tx
.
Recipient
,
tx
.
Data
}
data
:=
[]
interface
{}{
tx
.
Nonce
,
tx
.
GasPrice
,
tx
.
Gas
,
tx
.
Recipient
,
tx
.
Value
,
tx
.
Data
}
if
tx
.
contractCreation
{
data
=
append
(
data
,
tx
.
Init
)
...
...
@@ -135,10 +133,10 @@ func (tx *Transaction) RlpDecode(data []byte) {
func
(
tx
*
Transaction
)
RlpValueDecode
(
decoder
*
ethutil
.
Value
)
{
tx
.
Nonce
=
decoder
.
Get
(
0
)
.
Uint
()
tx
.
Valu
e
=
decoder
.
Get
(
1
)
.
BigInt
()
tx
.
Gas
Price
=
decoder
.
Get
(
2
)
.
BigInt
()
tx
.
Gas
=
decoder
.
Get
(
3
)
.
BigInt
()
tx
.
Recipient
=
decoder
.
Get
(
4
)
.
Bytes
()
tx
.
GasPric
e
=
decoder
.
Get
(
1
)
.
BigInt
()
tx
.
Gas
=
decoder
.
Get
(
2
)
.
BigInt
()
tx
.
Recipient
=
decoder
.
Get
(
3
)
.
Bytes
()
tx
.
Value
=
decoder
.
Get
(
4
)
.
BigInt
()
tx
.
Data
=
decoder
.
Get
(
5
)
.
Bytes
()
// If the list is of length 10 it's a contract creation tx
...
...
ethchain/transaction_pool.go
View file @
4b13f93a
...
...
@@ -131,9 +131,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
block
.
state
.
UpdateStateObject
(
sender
)
log
.
Print
f
(
"[TXPL] Processed Tx %x
\n
"
,
tx
.
Hash
())
ethutil
.
Config
.
Log
.
Info
f
(
"[TXPL] Processed Tx %x
\n
"
,
tx
.
Hash
())
pool
.
notifySubscribers
(
TxPost
,
tx
)
// Notify all subscribers
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:post"
,
tx
)
return
}
...
...
@@ -148,7 +149,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
}
// Get the sender
sender
:=
pool
.
Ethereum
.
StateManager
()
.
procState
.
GetAccount
(
tx
.
Sender
())
//sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender())
sender
:=
pool
.
Ethereum
.
StateManager
()
.
CurrentState
()
.
GetAccount
(
tx
.
Sender
())
totAmount
:=
new
(
big
.
Int
)
.
Add
(
tx
.
Value
,
new
(
big
.
Int
)
.
Mul
(
TxFee
,
TxFeeRat
))
// Make sure there's enough in the sender's account. Having insufficient
...
...
@@ -188,10 +190,7 @@ out:
pool
.
addTransaction
(
tx
)
// Notify the subscribers
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx"
,
tx
)
// Notify the subscribers
pool
.
notifySubscribers
(
TxPre
,
tx
)
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:pre"
,
tx
)
}
case
<-
pool
.
quit
:
break
out
...
...
@@ -252,14 +251,3 @@ func (pool *TxPool) Stop() {
log
.
Println
(
"[TXP] Stopped"
)
}
func
(
pool
*
TxPool
)
Subscribe
(
channel
chan
TxMsg
)
{
pool
.
subscribers
=
append
(
pool
.
subscribers
,
channel
)
}
func
(
pool
*
TxPool
)
notifySubscribers
(
ty
TxMsgTy
,
tx
*
Transaction
)
{
msg
:=
TxMsg
{
Type
:
ty
,
Tx
:
tx
}
for
_
,
subscriber
:=
range
pool
.
subscribers
{
subscriber
<-
msg
}
}
ethchain/vm.go
View file @
4b13f93a
...
...
@@ -95,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
if
ethutil
.
Config
.
Debug
{
ethutil
.
Config
.
Log
.
Debugf
(
"# op
\n
"
)
}
fmt
.
Println
(
closure
.
Script
)
for
{
// The base for all big integer arithmetic
...
...
@@ -472,7 +471,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
args
:=
mem
.
Get
(
inOffset
.
Int64
(),
inSize
.
Int64
())
// Fetch the contract which will serve as the closure body
contract
:=
vm
.
state
.
Get
Contra
ct
(
addr
.
Bytes
())
contract
:=
vm
.
state
.
Get
StateObje
ct
(
addr
.
Bytes
())
if
contract
!=
nil
{
// Prepay for the gas
...
...
ethchain/vm_test.go
View file @
4b13f93a
...
...
@@ -12,7 +12,7 @@ import (
)
func
TestRun4
(
t
*
testing
.
T
)
{
ethutil
.
ReadConfig
(
""
)
ethutil
.
ReadConfig
(
""
,
ethutil
.
LogStd
)
db
,
_
:=
ethdb
.
NewMemDatabase
()
state
:=
NewState
(
ethutil
.
NewTrie
(
db
,
""
))
...
...
ethereum.go
View file @
4b13f93a
...
...
@@ -222,7 +222,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error {
if
phost
==
chost
{
alreadyConnected
=
true
ethutil
.
Config
.
Log
.
Debugf
(
"[SERV] Peer %s already added.
\n
"
,
chost
)
//
ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost)
return
}
})
...
...
@@ -235,7 +235,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error {
s
.
peers
.
PushBack
(
peer
)
log
.
Printf
(
"[SERV] Adding peer %d / %d
\n
"
,
s
.
peers
.
Len
(),
s
.
MaxPeers
)
ethutil
.
Config
.
Log
.
Infof
(
"[SERV] Adding peer (%s) %d / %d
\n
"
,
addr
,
s
.
peers
.
Len
(),
s
.
MaxPeers
)
}
return
nil
...
...
ethminer/miner.go
View file @
4b13f93a
...
...
@@ -5,7 +5,6 @@ import (
"github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire"
"log"
)
type
Miner
struct
{
...
...
@@ -26,7 +25,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
quitChan
:=
make
(
chan
ethutil
.
React
,
1
)
// This is the channel that can exit the miner thread
ethereum
.
Reactor
()
.
Subscribe
(
"newBlock"
,
reactChan
)
ethereum
.
Reactor
()
.
Subscribe
(
"newTx"
,
reactChan
)
ethereum
.
Reactor
()
.
Subscribe
(
"newTx
:pre
"
,
reactChan
)
// We need the quit chan to be a Reactor event.
// The POW search method is actually blocking and if we don't
...
...
@@ -34,7 +33,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
// The miner overseer will never get the reactor events themselves
// Only after the miner will find the sha
ethereum
.
Reactor
()
.
Subscribe
(
"newBlock"
,
quitChan
)
ethereum
.
Reactor
()
.
Subscribe
(
"newTx"
,
quitChan
)
ethereum
.
Reactor
()
.
Subscribe
(
"newTx
:pre
"
,
quitChan
)
miner
:=
Miner
{
pow
:
&
ethchain
.
EasyPow
{},
...
...
@@ -53,18 +52,18 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
}
func
(
miner
*
Miner
)
Start
()
{
// Prepare inital block
miner
.
ethereum
.
StateManager
()
.
Prepare
(
miner
.
block
.
State
(),
miner
.
block
.
State
())
go
func
()
{
miner
.
listener
()
}
()
//
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
go
miner
.
listener
()
}
func
(
miner
*
Miner
)
listener
()
{
for
{
select
{
case
chanMessage
:=
<-
miner
.
reactChan
:
if
block
,
ok
:=
chanMessage
.
Resource
.
(
*
ethchain
.
Block
);
ok
{
log
.
Print
ln
(
"[MINER] Got new block via Reactor"
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[MINER] Got new block via Reactor"
)
if
bytes
.
Compare
(
miner
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
(),
block
.
Hash
())
==
0
{
// TODO: Perhaps continue mining to get some uncle rewards
log
.
Print
ln
(
"[MINER] New top block found resetting state"
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[MINER] New top block found resetting state"
)
// Filter out which Transactions we have that were not in this block
var
newtxs
[]
*
ethchain
.
Transaction
...
...
@@ -86,15 +85,15 @@ func (miner *Miner) listener() {
}
else
{
if
bytes
.
Compare
(
block
.
PrevHash
,
miner
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
PrevHash
)
==
0
{
log
.
Print
ln
(
"[MINER] Adding uncle block"
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[MINER] Adding uncle block"
)
miner
.
uncles
=
append
(
miner
.
uncles
,
block
)
miner
.
ethereum
.
StateManager
()
.
Prepare
(
miner
.
block
.
State
(),
miner
.
block
.
State
())
//
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
}
}
}
if
tx
,
ok
:=
chanMessage
.
Resource
.
(
*
ethchain
.
Transaction
);
ok
{
//log.
Print
ln("[MINER] Got new transaction from Reactor", tx)
//log.
Info
ln("[MINER] Got new transaction from Reactor", tx)
found
:=
false
for
_
,
ctx
:=
range
miner
.
txs
{
if
found
=
bytes
.
Compare
(
ctx
.
Hash
(),
tx
.
Hash
())
==
0
;
found
{
...
...
@@ -103,49 +102,37 @@ func (miner *Miner) listener() {
}
if
found
==
false
{
//log.
Print
ln("[MINER] We did not know about this transaction, adding")
//log.
Info
ln("[MINER] We did not know about this transaction, adding")
miner
.
txs
=
append
(
miner
.
txs
,
tx
)
miner
.
block
=
miner
.
ethereum
.
BlockChain
()
.
NewBlock
(
miner
.
coinbase
,
miner
.
txs
)
miner
.
block
.
SetTransactions
(
miner
.
txs
)
}
else
{
//log.
Print
ln("[MINER] We already had this transaction, ignoring")
//log.
Info
ln("[MINER] We already had this transaction, ignoring")
}
}
default
:
log
.
Print
ln
(
"[MINER] Mining on block. Includes"
,
len
(
miner
.
txs
),
"transactions"
)
ethutil
.
Config
.
Log
.
Info
ln
(
"[MINER] Mining on block. Includes"
,
len
(
miner
.
txs
),
"transactions"
)
// Apply uncles
if
len
(
miner
.
uncles
)
>
0
{
miner
.
block
.
SetUncles
(
miner
.
uncles
)
}
// FIXME @ maranh, first block doesn't need this. Everything after the first block does.
// Please check and fix
miner
.
ethereum
.
StateManager
()
.
Prepare
(
miner
.
block
.
State
(),
miner
.
block
.
State
())
// Apply all transactions to the block
miner
.
ethereum
.
StateManager
()
.
ApplyTransactions
(
miner
.
block
,
miner
.
block
.
Transactions
())
miner
.
ethereum
.
StateManager
()
.
AccumelateRewards
(
miner
.
block
)
miner
.
ethereum
.
StateManager
()
.
ApplyTransactions
(
miner
.
block
.
State
(),
miner
.
block
,
miner
.
block
.
Transactions
())
miner
.
ethereum
.
StateManager
()
.
AccumelateRewards
(
miner
.
block
.
State
(),
miner
.
block
)
// Search the nonce
//log.Println("[MINER] Initialision complete, starting mining")
miner
.
block
.
Nonce
=
miner
.
pow
.
Search
(
miner
.
block
,
miner
.
quitChan
)
if
miner
.
block
.
Nonce
!=
nil
{
miner
.
ethereum
.
StateManager
()
.
PrepareDefault
(
miner
.
block
)
err
:=
miner
.
ethereum
.
StateManager
()
.
ProcessBlock
(
miner
.
block
,
true
)
err
:=
miner
.
ethereum
.
StateManager
()
.
ProcessBlock
(
miner
.
ethereum
.
StateManager
()
.
CurrentState
(),
miner
.
block
,
true
)
if
err
!=
nil
{
log
.
Print
ln
(
err
)
ethutil
.
Config
.
Log
.
Info
ln
(
err
)
miner
.
txs
=
[]
*
ethchain
.
Transaction
{}
// Move this somewhere neat
miner
.
block
=
miner
.
ethereum
.
BlockChain
()
.
NewBlock
(
miner
.
coinbase
,
miner
.
txs
)
}
else
{
/*
// XXX @maranh This is already done in the state manager, why a 2nd time?
if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
}
*/
miner
.
ethereum
.
Broadcast
(
ethwire
.
MsgBlockTy
,
[]
interface
{}{
miner
.
block
.
Value
()
.
Val
})
log
.
Print
f
(
"[MINER] 🔨 Mined block %x
\n
"
,
miner
.
block
.
Hash
())
ethutil
.
Config
.
Log
.
Info
f
(
"[MINER] 🔨 Mined block %x
\n
"
,
miner
.
block
.
Hash
())
miner
.
txs
=
[]
*
ethchain
.
Transaction
{}
// Move this somewhere neat
miner
.
block
=
miner
.
ethereum
.
BlockChain
()
.
NewBlock
(
miner
.
coinbase
,
miner
.
txs
)
...
...
ethpub/pub.go
View file @
4b13f93a
...
...
@@ -45,7 +45,7 @@ func (lib *PEthereum) GetKey() *PKey {
}
func
(
lib
*
PEthereum
)
GetStateObject
(
address
string
)
*
PStateObject
{
stateObject
:=
lib
.
stateManager
.
ProcState
()
.
GetContra
ct
(
ethutil
.
FromHex
(
address
))
stateObject
:=
lib
.
stateManager
.
CurrentState
()
.
GetStateObje
ct
(
ethutil
.
FromHex
(
address
))
if
stateObject
!=
nil
{
return
NewPStateObject
(
stateObject
)
}
...
...
@@ -160,8 +160,8 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
}
acc
:=
lib
.
stateManager
.
TransState
()
.
GetStateObject
(
keyPair
.
Address
())
//acc := lib.stateManager.GetAddrState(keyPair.Address())
tx
.
Nonce
=
acc
.
Nonce
acc
.
Nonce
+=
1
lib
.
stateManager
.
TransState
()
.
SetStateObject
(
acc
)
tx
.
Sign
(
keyPair
.
PrivateKey
)
...
...
ethpub/types.go
View file @
4b13f93a
...
...
@@ -112,6 +112,14 @@ func (c *PStateObject) IsContract() bool {
return
false
}
func
(
c
*
PStateObject
)
Script
()
string
{
if
c
.
object
!=
nil
{
return
ethutil
.
Hex
(
c
.
object
.
Script
())
}
return
""
}
type
PStorageState
struct
{
StateAddress
string
Address
string
...
...
ethutil/common.go
View file @
4b13f93a
...
...
@@ -10,9 +10,9 @@ var (
Ether
=
BigPow
(
10
,
18
)
Finney
=
BigPow
(
10
,
15
)
Szabo
=
BigPow
(
10
,
12
)
Vita
=
BigPow
(
10
,
9
)
Turing
=
BigPow
(
10
,
6
)
Eins
=
BigPow
(
10
,
3
)
Shannon
=
BigPow
(
10
,
9
)
Babbage
=
BigPow
(
10
,
6
)
Ada
=
BigPow
(
10
,
3
)
Wei
=
big
.
NewInt
(
1
)
)
...
...
@@ -27,12 +27,12 @@ func CurrencyToString(num *big.Int) string {
return
fmt
.
Sprintf
(
"%v Finney"
,
new
(
big
.
Int
)
.
Div
(
num
,
Finney
))
case
num
.
Cmp
(
Szabo
)
>=
0
:
return
fmt
.
Sprintf
(
"%v Szabo"
,
new
(
big
.
Int
)
.
Div
(
num
,
Szabo
))
case
num
.
Cmp
(
Vita
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Vita"
,
new
(
big
.
Int
)
.
Div
(
num
,
Vita
))
case
num
.
Cmp
(
Turing
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Turing"
,
new
(
big
.
Int
)
.
Div
(
num
,
Turing
))
case
num
.
Cmp
(
Eins
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Eins"
,
new
(
big
.
Int
)
.
Div
(
num
,
Eins
))
case
num
.
Cmp
(
Shannon
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Shannon"
,
new
(
big
.
Int
)
.
Div
(
num
,
Shannon
))
case
num
.
Cmp
(
Babbage
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Babbage"
,
new
(
big
.
Int
)
.
Div
(
num
,
Babbage
))
case
num
.
Cmp
(
Ada
)
>=
0
:
return
fmt
.
Sprintf
(
"%v
Ada"
,
new
(
big
.
Int
)
.
Div
(
num
,
Ada
))
}
return
fmt
.
Sprintf
(
"%v Wei"
,
num
)
...
...
ethutil/common_test.go
View file @
4b13f93a
...
...
@@ -26,15 +26,15 @@ func TestCommon(t *testing.T) {
t
.
Error
(
"Got"
,
szabo
)
}
if
vito
!=
"10
Vita
"
{
if
vito
!=
"10
Shannon
"
{
t
.
Error
(
"Got"
,
vito
)
}
if
turing
!=
"10
Turing
"
{
if
turing
!=
"10
Babbage
"
{
t
.
Error
(
"Got"
,
turing
)
}
if
eins
!=
"10
Eins
"
{
if
eins
!=
"10
Ada
"
{
t
.
Error
(
"Got"
,
eins
)
}
...
...
ethutil/config.go
View file @
4b13f93a
...
...
@@ -9,14 +9,6 @@ import (
"runtime"
)
// Log types available
type
LogType
byte
const
(
LogTypeStdIn
=
1
LogTypeFile
=
2
)
// Config struct
type
config
struct
{
Db
Database
...
...
@@ -34,7 +26,7 @@ var Config *config
// Read config
//
// Initialize the global Config variable with default settings
func
ReadConfig
(
base
string
)
*
config
{
func
ReadConfig
(
base
string
,
logTypes
LoggerType
)
*
config
{
if
Config
==
nil
{
usr
,
_
:=
user
.
Current
()
path
:=
path
.
Join
(
usr
.
HomeDir
,
base
)
...
...
@@ -50,8 +42,8 @@ func ReadConfig(base string) *config {
}
}
Config
=
&
config
{
ExecPath
:
path
,
Debug
:
true
,
Ver
:
"0.5.0 RC
6
"
}
Config
.
Log
=
NewLogger
(
LogFile
|
LogStd
,
LogLevelDebug
)
Config
=
&
config
{
ExecPath
:
path
,
Debug
:
true
,
Ver
:
"0.5.0 RC
7
"
}
Config
.
Log
=
NewLogger
(
logTypes
,
LogLevelDebug
)
Config
.
SetClientString
(
"/Ethereum(G)"
)
}
...
...
@@ -138,7 +130,6 @@ func (log *Logger) Infoln(v ...interface{}) {
return
}
//fmt.Println(len(log.logSys))
for
_
,
logger
:=
range
log
.
logSys
{
logger
.
Println
(
v
...
)
}
...
...
@@ -153,3 +144,15 @@ func (log *Logger) Infof(format string, v ...interface{}) {
logger
.
Printf
(
format
,
v
...
)
}
}
func
(
log
*
Logger
)
Fatal
(
v
...
interface
{})
{
if
log
.
logLevel
>
LogLevelInfo
{
return
}
for
_
,
logger
:=
range
log
.
logSys
{
logger
.
Println
(
v
...
)
}
os
.
Exit
(
1
)
}
ethutil/reactor.go
View file @
4b13f93a
...
...
@@ -46,6 +46,7 @@ func (e *ReactorEvent) Remove(ch chan React) {
// Basic reactor resource
type
React
struct
{
Resource
interface
{}
Event
string
}
// The reactor basic engine. Acts as bridge
...
...
@@ -81,6 +82,6 @@ func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) {
func
(
reactor
*
ReactorEngine
)
Post
(
event
string
,
resource
interface
{})
{
ev
:=
reactor
.
patterns
[
event
]
if
ev
!=
nil
{
ev
.
Post
(
React
{
Resource
:
resource
})
ev
.
Post
(
React
{
Resource
:
resource
,
Event
:
event
})
}
}
peer.go
View file @
4b13f93a
...
...
@@ -18,7 +18,7 @@ const (
// The size of the output buffer for writing messages
outputBufferSize
=
50
// Current protocol version
ProtocolVersion
=
8
ProtocolVersion
=
10
)
type
DiscReason
byte
...
...
@@ -127,6 +127,7 @@ type Peer struct {
// Indicated whether the node is catching up or not
catchingUp
bool
diverted
bool
blocksRequested
int
Version
string
...
...
@@ -190,7 +191,6 @@ func (p *Peer) QueueMessage(msg *ethwire.Msg) {
if
atomic
.
LoadInt32
(
&
p
.
connected
)
!=
1
{
return
}
p
.
outputQueue
<-
msg
}
...
...
@@ -268,7 +268,6 @@ func (p *Peer) HandleInbound() {
for
atomic
.
LoadInt32
(
&
p
.
disconnect
)
==
0
{
// HMM?
time
.
Sleep
(
500
*
time
.
Millisecond
)
// Wait for a message from the peer
msgs
,
err
:=
ethwire
.
ReadMessages
(
p
.
conn
)
if
err
!=
nil
{
...
...
@@ -300,39 +299,44 @@ func (p *Peer) HandleInbound() {
var
err
error
// Make sure we are actually receiving anything
if
msg
.
Data
.
Len
()
-
1
>
1
&&
p
.
catchingUp
{
if
msg
.
Data
.
Len
()
-
1
>
1
&&
p
.
diverted
{
// We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find
// common ground to start syncing from
lastBlock
=
ethchain
.
NewBlockFromRlpValue
(
msg
.
Data
.
Get
(
msg
.
Data
.
Len
()
-
1
))
if
!
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
HasBlock
(
lastBlock
.
Hash
())
{
// If we can't find a common ancenstor we need to request more blocks.
// FIXME: At one point this won't scale anymore since we are not asking for an offset
// we just keep increasing the amount of blocks.
//fmt.Println("[PEER] No common ancestor found, requesting more blocks.")
p
.
blocksRequested
=
p
.
blocksRequested
*
2
p
.
catchingUp
=
false
p
.
SyncWithBlocks
()
}
ethutil
.
Config
.
Log
.
Infof
(
"[PEER] Last block: %x. Checking if we have it locally.
\n
"
,
lastBlock
.
Hash
())
for
i
:=
msg
.
Data
.
Len
()
-
1
;
i
>=
0
;
i
--
{
block
=
ethchain
.
NewBlockFromRlpValue
(
msg
.
Data
.
Get
(
i
))
// Do we have this block on our chain? If so we can continue
if
!
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
HasBlock
(
block
.
Hash
())
{
// We don't have this block, but we do have a block with the same prevHash, diversion time!
if
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
HasBlockWithPrevHash
(
block
.
PrevHash
)
{
if
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
FindCanonicalChainFromMsg
(
msg
,
block
.
PrevHash
)
{
return
p
.
diverted
=
false
if
!
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
FindCanonicalChainFromMsg
(
msg
,
block
.
PrevHash
)
{
p
.
SyncWithPeerToLastKnown
()
}
break
}
}
}
if
!
p
.
ethereum
.
StateManager
()
.
BlockChain
()
.
HasBlock
(
lastBlock
.
Hash
())
{
// If we can't find a common ancenstor we need to request more blocks.
// FIXME: At one point this won't scale anymore since we are not asking for an offset
// we just keep increasing the amount of blocks.
p
.
blocksRequested
=
p
.
blocksRequested
*
2
ethutil
.
Config
.
Log
.
Infof
(
"[PEER] No common ancestor found, requesting %d more blocks.
\n
"
,
p
.
blocksRequested
)
p
.
catchingUp
=
false
p
.
FindCommonParentBlock
()
break
}
}
for
i
:=
msg
.
Data
.
Len
()
-
1
;
i
>=
0
;
i
--
{
block
=
ethchain
.
NewBlockFromRlpValue
(
msg
.
Data
.
Get
(
i
))
p
.
ethereum
.
StateManager
()
.
PrepareDefault
(
block
)
err
=
p
.
ethereum
.
StateManager
()
.
ProcessBlock
(
block
,
false
)
//p.ethereum.StateManager().PrepareDefault(block)
state
:=
p
.
ethereum
.
StateManager
()
.
CurrentState
()
err
=
p
.
ethereum
.
StateManager
()
.
ProcessBlock
(
state
,
block
,
false
)
if
err
!=
nil
{
if
ethutil
.
Config
.
Debug
{
...
...
@@ -345,23 +349,28 @@ func (p *Peer) HandleInbound() {
}
}
if
msg
.
Data
.
Len
()
==
0
{
// Set catching up to false if
// the peer has nothing left to give
p
.
catchingUp
=
false
}
if
err
!=
nil
{
// If the parent is unknown try to catch up with this peer
if
ethchain
.
IsParentErr
(
err
)
{
ethutil
.
Config
.
Log
.
Infoln
(
"Attempting to catch up"
)
ethutil
.
Config
.
Log
.
Infoln
(
"Attempting to catch up
since we don't know the parent
"
)
p
.
catchingUp
=
false
p
.
CatchupWithPeer
(
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
())
}
else
if
ethchain
.
IsValidationErr
(
err
)
{
fmt
.
Println
(
err
)
fmt
.
Println
(
"Err:"
,
err
)
p
.
catchingUp
=
false
}
}
else
{
// XXX Do we want to catch up if there were errors?
// If we're catching up, try to catch up further.
if
p
.
catchingUp
&&
msg
.
Data
.
Len
()
>
1
{
if
ethutil
.
Config
.
Debug
&&
lastBlock
!=
nil
{
if
lastBlock
!=
nil
{
blockInfo
:=
lastBlock
.
BlockInfo
()
ethutil
.
Config
.
Log
.
Info
f
(
"Synced to block height #%d %x %x
\n
"
,
blockInfo
.
Number
,
lastBlock
.
Hash
(),
blockInfo
.
Hash
)
ethutil
.
Config
.
Log
.
Debug
f
(
"Synced to block height #%d %x %x
\n
"
,
blockInfo
.
Number
,
lastBlock
.
Hash
(),
blockInfo
.
Hash
)
}
p
.
catchingUp
=
false
...
...
@@ -371,11 +380,6 @@ func (p *Peer) HandleInbound() {
}
}
if
msg
.
Data
.
Len
()
==
0
{
// Set catching up to false if
// the peer has nothing left to give
p
.
catchingUp
=
false
}
case
ethwire
.
MsgTxTy
:
// If the message was a transaction queue the transaction
// in the TxPool where it will undergo validation and
...
...
@@ -443,7 +447,7 @@ func (p *Peer) HandleInbound() {
}
}
else
{
ethutil
.
Config
.
Log
.
Debugf
(
"[PEER] Could not find a similar block"
)
//
ethutil.Config.Log.Debugf("[PEER] Could not find a similar block")
// If no blocks are found we send back a reply with msg not in chain
// and the last hash from get chain
lastHash
:=
msg
.
Data
.
Get
(
l
-
1
)
...
...
@@ -451,8 +455,14 @@ func (p *Peer) HandleInbound() {
p
.
QueueMessage
(
ethwire
.
NewMessage
(
ethwire
.
MsgNotInChainTy
,
[]
interface
{}{
lastHash
.
Raw
()}))
}
case
ethwire
.
MsgNotInChainTy
:
ethutil
.
Config
.
Log
.
Debugf
(
"Not in chain %x
\n
"
,
msg
.
Data
)
// TODO
ethutil
.
Config
.
Log
.
Debugf
(
"Not in chain: %x
\n
"
,
msg
.
Data
.
Get
(
0
)
.
Bytes
())
if
p
.
diverted
==
true
{
// If were already looking for a common parent and we get here again we need to go deeper
p
.
blocksRequested
=
p
.
blocksRequested
*
2
}
p
.
diverted
=
true
p
.
catchingUp
=
false
p
.
FindCommonParentBlock
()
case
ethwire
.
MsgGetTxsTy
:
// Get the current transactions of the pool
txs
:=
p
.
ethereum
.
TxPool
()
.
CurrentTransactions
()
...
...
@@ -470,7 +480,6 @@ func (p *Peer) HandleInbound() {
}
}
}
p
.
Stop
()
}
...
...
@@ -580,14 +589,18 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
}
// Catch up with the connected peer
p
.
SyncWithBlocks
()
// Set the peer's caps
p
.
caps
=
Caps
(
c
.
Get
(
3
)
.
Byte
())
// Get a reference to the peers version
p
.
Version
=
c
.
Get
(
2
)
.
Str
()
// Catch up with the connected peer
if
!
p
.
ethereum
.
IsUpToDate
()
{
ethutil
.
Config
.
Log
.
Debugln
(
"Already syncing up with a peer; sleeping"
)
time
.
Sleep
(
10
*
time
.
Second
)
}
p
.
SyncWithPeerToLastKnown
()
ethutil
.
Config
.
Log
.
Debugln
(
"[PEER]"
,
p
)
}
...
...
@@ -608,12 +621,19 @@ func (p *Peer) String() string {
return
fmt
.
Sprintf
(
"[%s] (%s) %v %s [%s]"
,
strConnectType
,
strBoundType
,
p
.
conn
.
RemoteAddr
(),
p
.
Version
,
p
.
caps
)
}
func
(
p
*
Peer
)
SyncWithBlocks
()
{
if
!
p
.
catchingUp
{
func
(
p
*
Peer
)
SyncWithPeerToLastKnown
()
{
p
.
catchingUp
=
false
p
.
CatchupWithPeer
(
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
())
}
func
(
p
*
Peer
)
FindCommonParentBlock
()
{
if
p
.
catchingUp
{
return
}
p
.
catchingUp
=
true
// FIXME: THIS SHOULD NOT BE NEEDED
if
p
.
blocksRequested
==
0
{
p
.
blocksRequested
=
1
0
p
.
blocksRequested
=
2
0
}
blocks
:=
p
.
ethereum
.
BlockChain
()
.
GetChain
(
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
(),
p
.
blocksRequested
)
...
...
@@ -622,24 +642,26 @@ func (p *Peer) SyncWithBlocks() {
hashes
=
append
(
hashes
,
block
.
Hash
())
}
msgInfo
:=
append
(
hashes
,
uint64
(
50
))
msgInfo
:=
append
(
hashes
,
uint64
(
len
(
hashes
)))
ethutil
.
Config
.
Log
.
Infof
(
"Asking for block from %x (%d total) from %s
\n
"
,
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
(),
len
(
hashes
),
p
.
conn
.
RemoteAddr
()
.
String
())
msg
:=
ethwire
.
NewMessage
(
ethwire
.
MsgGetChainTy
,
msgInfo
)
p
.
QueueMessage
(
msg
)
}
}
func
(
p
*
Peer
)
CatchupWithPeer
(
blockHash
[]
byte
)
{
if
!
p
.
catchingUp
{
// Make sure nobody else is catching up when you want to do this
p
.
catchingUp
=
true
msg
:=
ethwire
.
NewMessage
(
ethwire
.
MsgGetChainTy
,
[]
interface
{}{
blockHash
,
uint64
(
50
)})
p
.
QueueMessage
(
msg
)
ethutil
.
Config
.
Log
.
Debugf
(
"Requesting blockchain %x...
\n
"
,
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
()[
:
4
]
)
ethutil
.
Config
.
Log
.
Debugf
(
"Requesting blockchain %x...
from peer %s
\n
"
,
p
.
ethereum
.
BlockChain
()
.
CurrentBlock
.
Hash
()[
:
4
],
p
.
conn
.
RemoteAddr
()
)
/*
msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{})
p.QueueMessage(msg)
ethutil
.
Config
.
Log
.
Debugln
(
"Requested transactions"
)
*/
}
}
...
...
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