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
70867904
Commit
70867904
authored
May 27, 2015
by
obscuren
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/0.9.25'
parents
ceea1a70
2c532a72
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
361 additions
and
242 deletions
+361
-242
admin.go
cmd/geth/admin.go
+52
-18
js.go
cmd/geth/js.go
+1
-1
js_test.go
cmd/geth/js_test.go
+3
-1
main.go
cmd/geth/main.go
+8
-7
flags.go
cmd/utils/flags.go
+5
-1
solidity.go
common/compiler/solidity.go
+2
-0
block_processor.go
core/block_processor.go
+5
-2
chain_manager.go
core/chain_manager.go
+1
-1
transaction_pool.go
core/transaction_pool.go
+5
-0
transaction_pool_test.go
core/transaction_pool_test.go
+14
-0
backend.go
eth/backend.go
+5
-7
downloader.go
eth/downloader/downloader.go
+1
-1
sync.go
eth/sync.go
+0
-1
jsre.go
jsre/jsre.go
+86
-149
jsre_test.go
jsre/jsre_test.go
+6
-6
database.go
p2p/discover/database.go
+14
-3
database_test.go
p2p/discover/database_test.go
+11
-0
table.go
p2p/discover/table.go
+101
-30
server.go
p2p/server.go
+38
-11
jeth.go
rpc/jeth.go
+3
-3
No files found.
cmd/geth/admin.go
View file @
70867904
...
...
@@ -88,6 +88,7 @@ func (js *jsre) adminBindings() {
debug
.
Set
(
"getBlockRlp"
,
js
.
getBlockRlp
)
debug
.
Set
(
"setHead"
,
js
.
setHead
)
debug
.
Set
(
"processBlock"
,
js
.
debugBlock
)
debug
.
Set
(
"seedhash"
,
js
.
seedHash
)
// undocumented temporary
debug
.
Set
(
"waitForBlocks"
,
js
.
waitForBlocks
)
}
...
...
@@ -118,6 +119,27 @@ func (js *jsre) getBlock(call otto.FunctionCall) (*types.Block, error) {
return
block
,
nil
}
func
(
js
*
jsre
)
seedHash
(
call
otto
.
FunctionCall
)
otto
.
Value
{
if
len
(
call
.
ArgumentList
)
>
0
{
if
call
.
Argument
(
0
)
.
IsNumber
()
{
num
,
_
:=
call
.
Argument
(
0
)
.
ToInteger
()
hash
,
err
:=
ethash
.
GetSeedHash
(
uint64
(
num
))
if
err
!=
nil
{
fmt
.
Println
(
err
)
return
otto
.
UndefinedValue
()
}
v
,
_
:=
call
.
Otto
.
ToValue
(
fmt
.
Sprintf
(
"0x%x"
,
hash
))
return
v
}
else
{
fmt
.
Println
(
"arg not a number"
)
}
}
else
{
fmt
.
Println
(
"requires number argument"
)
}
return
otto
.
UndefinedValue
()
}
func
(
js
*
jsre
)
pendingTransactions
(
call
otto
.
FunctionCall
)
otto
.
Value
{
txs
:=
js
.
ethereum
.
TxPool
()
.
GetTransactions
()
...
...
@@ -144,7 +166,8 @@ func (js *jsre) pendingTransactions(call otto.FunctionCall) otto.Value {
}
}
return
js
.
re
.
ToVal
(
ltxs
)
v
,
_
:=
call
.
Otto
.
ToValue
(
ltxs
)
return
v
}
func
(
js
*
jsre
)
resend
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -175,7 +198,8 @@ func (js *jsre) resend(call otto.FunctionCall) otto.Value {
}
js
.
ethereum
.
TxPool
()
.
RemoveTransactions
(
types
.
Transactions
{
tx
.
tx
})
return
js
.
re
.
ToVal
(
ret
)
v
,
_
:=
call
.
Otto
.
ToValue
(
ret
)
return
v
}
fmt
.
Println
(
"first argument must be a transaction"
)
...
...
@@ -198,12 +222,13 @@ func (js *jsre) sign(call otto.FunctionCall) otto.Value {
fmt
.
Println
(
err
)
return
otto
.
UndefinedValue
()
}
v
,
err
:=
js
.
xeth
.
Sign
(
signer
,
data
,
false
)
signed
,
err
:=
js
.
xeth
.
Sign
(
signer
,
data
,
false
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
return
otto
.
UndefinedValue
()
}
return
js
.
re
.
ToVal
(
v
)
v
,
_
:=
call
.
Otto
.
ToValue
(
signed
)
return
v
}
func
(
js
*
jsre
)
debugBlock
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -217,10 +242,11 @@ func (js *jsre) debugBlock(call otto.FunctionCall) otto.Value {
vm
.
Debug
=
true
_
,
err
=
js
.
ethereum
.
BlockProcessor
()
.
RetryProcess
(
block
)
if
err
!=
nil
{
glog
.
Info
ln
(
err
)
fmt
.
Print
ln
(
err
)
}
vm
.
Debug
=
old
fmt
.
Println
(
"ok"
)
return
otto
.
UndefinedValue
()
}
...
...
@@ -237,8 +263,8 @@ func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
func
(
js
*
jsre
)
downloadProgress
(
call
otto
.
FunctionCall
)
otto
.
Value
{
current
,
max
:=
js
.
ethereum
.
Downloader
()
.
Stats
()
return
js
.
re
.
ToVal
(
fmt
.
Sprintf
(
"%d/%d"
,
current
,
max
))
v
,
_
:=
call
.
Otto
.
ToValue
(
fmt
.
Sprintf
(
"%d/%d"
,
current
,
max
))
return
v
}
func
(
js
*
jsre
)
getBlockRlp
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -248,7 +274,8 @@ func (js *jsre) getBlockRlp(call otto.FunctionCall) otto.Value {
return
otto
.
UndefinedValue
()
}
encoded
,
_
:=
rlp
.
EncodeToBytes
(
block
)
return
js
.
re
.
ToVal
(
fmt
.
Sprintf
(
"%x"
,
encoded
))
v
,
_
:=
call
.
Otto
.
ToValue
(
fmt
.
Sprintf
(
"%x"
,
encoded
))
return
v
}
func
(
js
*
jsre
)
setExtra
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -278,8 +305,9 @@ func (js *jsre) setGasPrice(call otto.FunctionCall) otto.Value {
return
otto
.
UndefinedValue
()
}
func
(
js
*
jsre
)
hashrate
(
otto
.
FunctionCall
)
otto
.
Value
{
return
js
.
re
.
ToVal
(
js
.
ethereum
.
Miner
()
.
HashRate
())
func
(
js
*
jsre
)
hashrate
(
call
otto
.
FunctionCall
)
otto
.
Value
{
v
,
_
:=
call
.
Otto
.
ToValue
(
js
.
ethereum
.
Miner
()
.
HashRate
())
return
v
}
func
(
js
*
jsre
)
makeDAG
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -495,15 +523,18 @@ func (js *jsre) newAccount(call otto.FunctionCall) otto.Value {
fmt
.
Printf
(
"Could not create the account: %v"
,
err
)
return
otto
.
UndefinedValue
()
}
return
js
.
re
.
ToVal
(
acct
.
Address
.
Hex
())
v
,
_
:=
call
.
Otto
.
ToValue
(
acct
.
Address
.
Hex
())
return
v
}
func
(
js
*
jsre
)
nodeInfo
(
call
otto
.
FunctionCall
)
otto
.
Value
{
return
js
.
re
.
ToVal
(
js
.
ethereum
.
NodeInfo
())
v
,
_
:=
call
.
Otto
.
ToValue
(
js
.
ethereum
.
NodeInfo
())
return
v
}
func
(
js
*
jsre
)
peers
(
call
otto
.
FunctionCall
)
otto
.
Value
{
return
js
.
re
.
ToVal
(
js
.
ethereum
.
PeersInfo
())
v
,
_
:=
call
.
Otto
.
ToValue
(
js
.
ethereum
.
PeersInfo
())
return
v
}
func
(
js
*
jsre
)
importChain
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -562,7 +593,8 @@ func (js *jsre) dumpBlock(call otto.FunctionCall) otto.Value {
statedb
:=
state
.
New
(
block
.
Root
(),
js
.
ethereum
.
StateDb
())
dump
:=
statedb
.
RawDump
()
return
js
.
re
.
ToVal
(
dump
)
v
,
_
:=
call
.
Otto
.
ToValue
(
dump
)
return
v
}
func
(
js
*
jsre
)
waitForBlocks
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -611,7 +643,8 @@ func (js *jsre) waitForBlocks(call otto.FunctionCall) otto.Value {
return
otto
.
UndefinedValue
()
case
height
=
<-
wait
:
}
return
js
.
re
.
ToVal
(
height
.
Uint64
())
v
,
_
:=
call
.
Otto
.
ToValue
(
height
.
Uint64
())
return
v
}
func
(
js
*
jsre
)
sleep
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -704,8 +737,8 @@ func (js *jsre) register(call otto.FunctionCall) otto.Value {
return
otto
.
UndefinedValue
()
}
return
js
.
re
.
ToVal
(
contenthash
.
Hex
())
v
,
_
:=
call
.
Otto
.
ToValue
(
contenthash
.
Hex
())
return
v
}
func
(
js
*
jsre
)
registerUrl
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
@@ -764,7 +797,8 @@ func (js *jsre) getContractInfo(call otto.FunctionCall) otto.Value {
fmt
.
Println
(
err
)
return
otto
.
UndefinedValue
()
}
return
js
.
re
.
ToVal
(
info
)
v
,
_
:=
call
.
Otto
.
ToValue
(
info
)
return
v
}
func
(
js
*
jsre
)
startNatSpec
(
call
otto
.
FunctionCall
)
otto
.
Value
{
...
...
cmd/geth/js.go
View file @
70867904
...
...
@@ -104,7 +104,7 @@ func newJSRE(ethereum *eth.Ethereum, libPath, corsDomain string, interactive boo
func
(
js
*
jsre
)
apiBindings
(
f
xeth
.
Frontend
)
{
xe
:=
xeth
.
New
(
js
.
ethereum
,
f
)
ethApi
:=
rpc
.
NewEthereumApi
(
xe
)
jeth
:=
rpc
.
NewJeth
(
ethApi
,
js
.
re
.
ToVal
,
js
.
re
)
jeth
:=
rpc
.
NewJeth
(
ethApi
,
js
.
re
)
js
.
re
.
Set
(
"jeth"
,
struct
{}{})
t
,
_
:=
js
.
re
.
Get
(
"jeth"
)
...
...
cmd/geth/js_test.go
View file @
70867904
...
...
@@ -35,6 +35,7 @@ const (
var
(
versionRE
=
regexp
.
MustCompile
(
strconv
.
Quote
(
`"compilerVersion":"`
+
solcVersion
+
`"`
))
testNodeKey
=
crypto
.
ToECDSA
(
common
.
Hex2Bytes
(
"4b50fa71f5c3eeb8fdc452224b2395af2fcc3d125e06c32c82e048c0559db03f"
))
testGenesis
=
`{"`
+
testAddress
[
2
:
]
+
`": {"balance": "`
+
testBalance
+
`"}}`
)
...
...
@@ -72,6 +73,7 @@ func testJEthRE(t *testing.T) (string, *testjethre, *eth.Ethereum) {
ks
:=
crypto
.
NewKeyStorePlain
(
filepath
.
Join
(
tmp
,
"keystore"
))
am
:=
accounts
.
NewManager
(
ks
)
ethereum
,
err
:=
eth
.
New
(
&
eth
.
Config
{
NodeKey
:
testNodeKey
,
DataDir
:
tmp
,
AccountManager
:
am
,
MaxPeers
:
0
,
...
...
@@ -122,7 +124,7 @@ func TestNodeInfo(t *testing.T) {
}
defer
ethereum
.
Stop
()
defer
os
.
RemoveAll
(
tmp
)
want
:=
`{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","NodeUrl":"enode://00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000@0.0.0.0:0","TCPPort":0,"Td":"0
"}`
want
:=
`{"DiscPort":0,"IP":"0.0.0.0","ListenAddr":"","Name":"test","NodeID":"
4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5","NodeUrl":"enode://4cb2fc32924e94277bf94b5e4c983beedb2eabd5a0bc941db32202735c6625d020ca14a5963d1738af43b6ac0a711d61b1a06de931a499fe2aa0b1a132a902b5@0.0.0.0:0","TCPPort":0,"Td":"131072
"}`
checkEvalJSON
(
t
,
repl
,
`admin.nodeInfo()`
,
want
)
}
...
...
cmd/geth/main.go
View file @
70867904
...
...
@@ -48,7 +48,7 @@ import _ "net/http/pprof"
const
(
ClientIdentifier
=
"Geth"
Version
=
"0.9.2
4
"
Version
=
"0.9.2
5
"
)
var
(
...
...
@@ -260,6 +260,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
utils
.
AutoDAGFlag
,
utils
.
NATFlag
,
utils
.
NatspecEnabledFlag
,
utils
.
NoDiscoverFlag
,
utils
.
NodeKeyFileFlag
,
utils
.
NodeKeyHexFlag
,
utils
.
RPCEnabledFlag
,
...
...
@@ -532,9 +533,9 @@ func importchain(ctx *cli.Context) {
}
// force database flush
ethereum
.
BlockDb
()
.
Close
()
ethereum
.
StateDb
()
.
Close
()
ethereum
.
ExtraDb
()
.
Close
()
ethereum
.
BlockDb
()
.
Flush
()
ethereum
.
StateDb
()
.
Flush
()
ethereum
.
ExtraDb
()
.
Flush
()
fmt
.
Printf
(
"Import done in %v"
,
time
.
Since
(
start
))
...
...
@@ -629,9 +630,9 @@ func upgradeDb(ctx *cli.Context) {
}
// force database flush
ethereum
.
BlockDb
()
.
Close
()
ethereum
.
StateDb
()
.
Close
()
ethereum
.
ExtraDb
()
.
Close
()
ethereum
.
BlockDb
()
.
Flush
()
ethereum
.
StateDb
()
.
Flush
()
ethereum
.
ExtraDb
()
.
Flush
()
os
.
Remove
(
exportFile
)
...
...
cmd/utils/flags.go
View file @
70867904
...
...
@@ -235,6 +235,10 @@ var (
Usage
:
"NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)"
,
Value
:
"any"
,
}
NoDiscoverFlag
=
cli
.
BoolFlag
{
Name
:
"nodiscover"
,
Usage
:
"Disables the peer discovery mechanism (manual peer addition)"
,
}
WhisperEnabledFlag
=
cli
.
BoolFlag
{
Name
:
"shh"
,
Usage
:
"Enable whisper"
,
...
...
@@ -312,6 +316,7 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
Port
:
ctx
.
GlobalString
(
ListenPortFlag
.
Name
),
NAT
:
GetNAT
(
ctx
),
NatSpec
:
ctx
.
GlobalBool
(
NatspecEnabledFlag
.
Name
),
Discovery
:
!
ctx
.
GlobalBool
(
NoDiscoverFlag
.
Name
),
NodeKey
:
GetNodeKey
(
ctx
),
Shh
:
ctx
.
GlobalBool
(
WhisperEnabledFlag
.
Name
),
Dial
:
true
,
...
...
@@ -320,7 +325,6 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
SolcPath
:
ctx
.
GlobalString
(
SolcPathFlag
.
Name
),
AutoDAG
:
ctx
.
GlobalBool
(
AutoDAGFlag
.
Name
)
||
ctx
.
GlobalBool
(
MiningEnabledFlag
.
Name
),
}
}
func
GetChain
(
ctx
*
cli
.
Context
)
(
*
core
.
ChainManager
,
common
.
Database
,
common
.
Database
)
{
...
...
common/compiler/solidity.go
View file @
70867904
...
...
@@ -34,6 +34,8 @@ var (
"file"
,
//
"--natspec-dev"
,
// Request to output the contract's Natspec developer documentation.
"file"
,
"--add-std"
,
"1"
,
}
)
...
...
core/block_processor.go
View file @
70867904
...
...
@@ -21,7 +21,7 @@ import (
const
(
// must be bumped when consensus algorithm is changed, this forces the upgradedb
// command to be run (forces the blocks to be imported again using the new algorithm)
BlockChainVersion
=
2
BlockChainVersion
=
3
)
var
receiptsPre
=
[]
byte
(
"receipts-"
)
...
...
@@ -159,6 +159,9 @@ func (sm *BlockProcessor) RetryProcess(block *types.Block) (logs state.Logs, err
return
nil
,
ParentError
(
header
.
ParentHash
)
}
parent
:=
sm
.
bc
.
GetBlock
(
header
.
ParentHash
)
if
!
sm
.
Pow
.
Verify
(
block
)
{
return
nil
,
ValidationError
(
"Block's nonce is invalid (= %x)"
,
block
.
Nonce
)
}
return
sm
.
processWithParent
(
block
,
parent
)
}
...
...
@@ -299,7 +302,7 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow b
a
:=
new
(
big
.
Int
)
.
Sub
(
block
.
GasLimit
,
parent
.
GasLimit
)
a
.
Abs
(
a
)
b
:=
new
(
big
.
Int
)
.
Div
(
parent
.
GasLimit
,
params
.
GasLimitBoundDivisor
)
if
!
(
a
.
Cmp
(
b
)
<
0
)
||
(
block
.
GasLimit
.
Cmp
(
params
.
MinGasLimit
)
==
-
1
)
{
if
!
(
a
.
Cmp
(
b
)
<
=
0
)
||
(
block
.
GasLimit
.
Cmp
(
params
.
MinGasLimit
)
==
-
1
)
{
return
fmt
.
Errorf
(
"GasLimit check failed for block %v (%v > %v)"
,
block
.
GasLimit
,
a
,
b
)
}
...
...
core/chain_manager.go
View file @
70867904
...
...
@@ -750,7 +750,7 @@ out:
func
blockErr
(
block
*
types
.
Block
,
err
error
)
{
h
:=
block
.
Header
()
glog
.
V
(
logger
.
Error
)
.
Infof
(
"
INVALID
block #%v (%x)
\n
"
,
h
.
Number
,
h
.
Hash
()
.
Bytes
())
glog
.
V
(
logger
.
Error
)
.
Infof
(
"
Bad
block #%v (%x)
\n
"
,
h
.
Number
,
h
.
Hash
()
.
Bytes
())
glog
.
V
(
logger
.
Error
)
.
Infoln
(
err
)
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
block
)
}
...
...
core/transaction_pool.go
View file @
70867904
...
...
@@ -25,6 +25,7 @@ var (
ErrInsufficientFunds
=
errors
.
New
(
"Insufficient funds for gas * price + value"
)
ErrIntrinsicGas
=
errors
.
New
(
"Intrinsic gas too low"
)
ErrGasLimit
=
errors
.
New
(
"Exceeds block gas limit"
)
ErrNegativeValue
=
errors
.
New
(
"Negative value"
)
)
const
txPoolQueueSize
=
50
...
...
@@ -125,6 +126,10 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
return
ErrGasLimit
}
if
tx
.
Amount
.
Cmp
(
common
.
Big0
)
<
0
{
return
ErrNegativeValue
}
total
:=
new
(
big
.
Int
)
.
Mul
(
tx
.
Price
,
tx
.
GasLimit
)
total
.
Add
(
total
,
tx
.
Value
())
if
pool
.
currentState
()
.
GetBalance
(
from
)
.
Cmp
(
total
)
<
0
{
...
...
core/transaction_pool_test.go
View file @
70867904
...
...
@@ -138,3 +138,17 @@ func TestRemoveTx(t *testing.T) {
t
.
Error
(
"expected txs to be 0, got"
,
len
(
pool
.
txs
))
}
}
func
TestNegativeValue
(
t
*
testing
.
T
)
{
pool
,
key
:=
setupTxPool
()
tx
:=
transaction
()
tx
.
Value
()
.
Set
(
big
.
NewInt
(
-
1
))
tx
.
SignECDSA
(
key
)
from
,
_
:=
tx
.
From
()
pool
.
currentState
()
.
AddBalance
(
from
,
big
.
NewInt
(
1
))
err
:=
pool
.
Add
(
tx
)
if
err
!=
ErrNegativeValue
{
t
.
Error
(
"expected"
,
ErrNegativeValue
,
"got"
,
err
)
}
}
eth/backend.go
View file @
70867904
...
...
@@ -72,6 +72,7 @@ type Config struct {
MaxPeers
int
MaxPendingPeers
int
Discovery
bool
Port
string
// Space-separated list of discovery node URLs
...
...
@@ -311,6 +312,7 @@ func New(config *Config) (*Ethereum, error) {
Name
:
config
.
Name
,
MaxPeers
:
config
.
MaxPeers
,
MaxPendingPeers
:
config
.
MaxPendingPeers
,
Discovery
:
config
.
Discovery
,
Protocols
:
protocols
,
NAT
:
config
.
NAT
,
NoDial
:
!
config
.
Dial
,
...
...
@@ -449,14 +451,10 @@ func (s *Ethereum) Start() error {
ClientString
:
s
.
net
.
Name
,
ProtocolVersion
:
ProtocolVersion
,
})
if
s
.
net
.
MaxPeers
>
0
{
err
:=
s
.
net
.
Start
()
if
err
!=
nil
{
return
err
}
err
:=
s
.
net
.
Start
()
if
err
!=
nil
{
return
err
}
// periodically flush databases
go
s
.
syncDatabases
()
...
...
eth/downloader/downloader.go
View file @
70867904
...
...
@@ -415,7 +415,7 @@ out:
peer
.
Demote
()
break
}
if
glog
.
V
(
logger
.
Debug
)
{
if
glog
.
V
(
logger
.
Debug
)
&&
len
(
blockPack
.
blocks
)
>
0
{
glog
.
Infof
(
"Added %d blocks from: %s
\n
"
,
len
(
blockPack
.
blocks
),
blockPack
.
peerId
)
}
// Promote the peer and update it's idle state
...
...
eth/sync.go
View file @
70867904
...
...
@@ -70,7 +70,6 @@ func (pm *ProtocolManager) processBlocks() error {
// Try to inset the blocks, drop the originating peer if there's an error
index
,
err
:=
pm
.
chainman
.
InsertChain
(
raw
)
if
err
!=
nil
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"Block insertion failed: %v"
,
err
)
pm
.
removePeer
(
blocks
[
index
]
.
OriginPeer
)
pm
.
downloader
.
Cancel
()
return
err
...
...
jsre/jsre.go
View file @
70867904
...
...
@@ -19,9 +19,7 @@ It provides some helper functions to
- bind native go objects
*/
type
JSRE
struct
{
assetPath
string
vm
*
otto
.
Otto
assetPath
string
evalQueue
chan
*
evalReq
stopEventLoop
chan
bool
loopWg
sync
.
WaitGroup
...
...
@@ -35,68 +33,37 @@ type jsTimer struct {
call
otto
.
FunctionCall
}
// evalResult is a structure to store the result of any serialized vm execution
type
evalResult
struct
{
result
otto
.
Value
err
error
}
// evalReq is a serialized vm execution request put in evalQueue and processed by runEventLoop
// evalReq is a serialized vm execution request processed by runEventLoop.
type
evalReq
struct
{
fn
func
(
res
*
evalResult
)
fn
func
(
vm
*
otto
.
Otto
)
done
chan
bool
res
evalResult
}
// runtime must be stopped with Stop() after use and cannot be used after stopping
func
New
(
assetPath
string
)
*
JSRE
{
re
:=
&
JSRE
{
assetPath
:
assetPath
,
vm
:
otto
.
New
(),
assetPath
:
assetPath
,
evalQueue
:
make
(
chan
*
evalReq
),
stopEventLoop
:
make
(
chan
bool
),
}
// load prettyprint func definition
re
.
vm
.
Run
(
pp_js
)
re
.
vm
.
Set
(
"loadScript"
,
re
.
loadScript
)
re
.
evalQueue
=
make
(
chan
*
evalReq
)
re
.
stopEventLoop
=
make
(
chan
bool
)
re
.
loopWg
.
Add
(
1
)
go
re
.
runEventLoop
()
re
.
Compile
(
"pp.js"
,
pp_js
)
// load prettyprint func definition
re
.
Set
(
"loadScript"
,
re
.
loadScript
)
return
re
}
// this function runs a piece of JS code either in a serialized way (when useEQ is true) or instantly, circumventing the evalQueue
func
(
self
*
JSRE
)
run
(
src
interface
{},
useEQ
bool
)
(
value
otto
.
Value
,
err
error
)
{
if
useEQ
{
done
:=
make
(
chan
bool
)
req
:=
&
evalReq
{
fn
:
func
(
res
*
evalResult
)
{
res
.
result
,
res
.
err
=
self
.
vm
.
Run
(
src
)
},
done
:
done
,
}
self
.
evalQueue
<-
req
<-
done
return
req
.
res
.
result
,
req
.
res
.
err
}
else
{
return
self
.
vm
.
Run
(
src
)
}
}
// This function runs the main event loop from a goroutine that is started
// when JSRE is created. Use Stop() before exiting to properly stop it.
// The event loop processes vm access requests from the evalQueue in a
// serialized way and calls timer callback functions at the appropriate time.
/*
This function runs the main event loop from a goroutine that is started
when JSRE is created. Use Stop() before exiting to properly stop it.
The event loop processes vm access requests from the evalQueue in a
serialized way and calls timer callback functions at the appropriate time.
Exported functions always access the vm through the event queue. You can
call the functions of the otto vm directly to circumvent the queue. These
functions should be used if and only if running a routine that was already
called from JS through an RPC call.
*/
// Exported functions always access the vm through the event queue. You can
// call the functions of the otto vm directly to circumvent the queue. These
// functions should be used if and only if running a routine that was already
// called from JS through an RPC call.
func
(
self
*
JSRE
)
runEventLoop
()
{
vm
:=
otto
.
New
()
registry
:=
map
[
*
jsTimer
]
*
jsTimer
{}
ready
:=
make
(
chan
*
jsTimer
)
...
...
@@ -143,10 +110,10 @@ func (self *JSRE) runEventLoop() {
}
return
otto
.
UndefinedValue
()
}
self
.
vm
.
Set
(
"setTimeout"
,
setTimeout
)
self
.
vm
.
Set
(
"setInterval"
,
setInterval
)
self
.
vm
.
Set
(
"clearTimeout"
,
clearTimeout
)
self
.
vm
.
Set
(
"clearInterval"
,
clearTimeout
)
vm
.
Set
(
"setTimeout"
,
setTimeout
)
vm
.
Set
(
"setInterval"
,
setInterval
)
vm
.
Set
(
"clearTimeout"
,
clearTimeout
)
vm
.
Set
(
"clearInterval"
,
clearTimeout
)
var
waitForCallbacks
bool
...
...
@@ -166,8 +133,7 @@ loop:
arguments
=
make
([]
interface
{},
1
)
}
arguments
[
0
]
=
timer
.
call
.
ArgumentList
[
0
]
_
,
err
:=
self
.
vm
.
Call
(
`Function.call.call`
,
nil
,
arguments
...
)
_
,
err
:=
vm
.
Call
(
`Function.call.call`
,
nil
,
arguments
...
)
if
err
!=
nil
{
fmt
.
Println
(
"js error:"
,
err
,
arguments
)
}
...
...
@@ -179,10 +145,10 @@ loop:
break
loop
}
}
case
evalR
eq
:=
<-
self
.
evalQueue
:
case
r
eq
:=
<-
self
.
evalQueue
:
// run the code, send the result back
evalReq
.
fn
(
&
evalReq
.
res
)
close
(
evalR
eq
.
done
)
req
.
fn
(
vm
)
close
(
r
eq
.
done
)
if
waitForCallbacks
&&
(
len
(
registry
)
==
0
)
{
break
loop
}
...
...
@@ -201,6 +167,14 @@ loop:
self
.
loopWg
.
Done
()
}
// do schedules the given function on the event loop.
func
(
self
*
JSRE
)
do
(
fn
func
(
*
otto
.
Otto
))
{
done
:=
make
(
chan
bool
)
req
:=
&
evalReq
{
fn
,
done
}
self
.
evalQueue
<-
req
<-
done
}
// stops the event loop before exit, optionally waits for all timers to expire
func
(
self
*
JSRE
)
Stop
(
waitForCallbacks
bool
)
{
self
.
stopEventLoop
<-
waitForCallbacks
...
...
@@ -210,119 +184,78 @@ func (self *JSRE) Stop(waitForCallbacks bool) {
// Exec(file) loads and runs the contents of a file
// if a relative path is given, the jsre's assetPath is used
func
(
self
*
JSRE
)
Exec
(
file
string
)
error
{
return
self
.
exec
(
common
.
AbsolutePath
(
self
.
assetPath
,
file
),
true
)
}
// circumvents the eval queue, see runEventLoop
func
(
self
*
JSRE
)
execWithoutEQ
(
file
string
)
error
{
return
self
.
exec
(
common
.
AbsolutePath
(
self
.
assetPath
,
file
),
false
)
}
func
(
self
*
JSRE
)
exec
(
path
string
,
useEQ
bool
)
error
{
code
,
err
:=
ioutil
.
ReadFile
(
path
)
code
,
err
:=
ioutil
.
ReadFile
(
common
.
AbsolutePath
(
self
.
assetPath
,
file
))
if
err
!=
nil
{
return
err
}
_
,
err
=
self
.
run
(
code
,
useEQ
)
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
_
,
err
=
vm
.
Run
(
code
)
}
)
return
err
}
// assigns value v to a variable in the JS environment
func
(
self
*
JSRE
)
Bind
(
name
string
,
v
interface
{})
(
err
error
)
{
self
.
Set
(
name
,
v
)
return
//
Bind
assigns value v to a variable in the JS environment
// This method is deprecated, use Set.
func
(
self
*
JSRE
)
Bind
(
name
string
,
v
interface
{})
error
{
return
self
.
Set
(
name
,
v
)
}
// runs a piece of JS code
func
(
self
*
JSRE
)
Run
(
code
string
)
(
otto
.
Value
,
error
)
{
return
self
.
run
(
code
,
true
)
// Run runs a piece of JS code.
func
(
self
*
JSRE
)
Run
(
code
string
)
(
v
otto
.
Value
,
err
error
)
{
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
v
,
err
=
vm
.
Run
(
code
)
})
return
v
,
err
}
// returns the value of a variable in the JS environment
func
(
self
*
JSRE
)
Get
(
ns
string
)
(
otto
.
Value
,
error
)
{
done
:=
make
(
chan
bool
)
req
:=
&
evalReq
{
fn
:
func
(
res
*
evalResult
)
{
res
.
result
,
res
.
err
=
self
.
vm
.
Get
(
ns
)
},
done
:
done
,
}
self
.
evalQueue
<-
req
<-
done
return
req
.
res
.
result
,
req
.
res
.
err
// Get returns the value of a variable in the JS environment.
func
(
self
*
JSRE
)
Get
(
ns
string
)
(
v
otto
.
Value
,
err
error
)
{
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
v
,
err
=
vm
.
Get
(
ns
)
})
return
v
,
err
}
// assigns value v to a variable in the JS environment
func
(
self
*
JSRE
)
Set
(
ns
string
,
v
interface
{})
error
{
done
:=
make
(
chan
bool
)
req
:=
&
evalReq
{
fn
:
func
(
res
*
evalResult
)
{
res
.
err
=
self
.
vm
.
Set
(
ns
,
v
)
},
done
:
done
,
}
self
.
evalQueue
<-
req
<-
done
return
req
.
res
.
err
// Set assigns value v to a variable in the JS environment.
func
(
self
*
JSRE
)
Set
(
ns
string
,
v
interface
{})
(
err
error
)
{
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
err
=
vm
.
Set
(
ns
,
v
)
})
return
err
}
/*
Executes a JS script from inside the currently executing JS code.
Should only be called from inside an RPC routine.
*/
// loadScript executes a JS script from inside the currently executing JS code.
func
(
self
*
JSRE
)
loadScript
(
call
otto
.
FunctionCall
)
otto
.
Value
{
file
,
err
:=
call
.
Argument
(
0
)
.
ToString
()
if
err
!=
nil
{
// TODO: throw exception
return
otto
.
FalseValue
()
}
file
=
common
.
AbsolutePath
(
self
.
assetPath
,
file
)
source
,
err
:=
ioutil
.
ReadFile
(
file
)
if
err
!=
nil
{
// TODO: throw exception
return
otto
.
FalseValue
()
}
if
err
:=
self
.
execWithoutEQ
(
file
);
err
!=
nil
{
// loadScript is only called from inside js
if
_
,
err
:=
compileAndRun
(
call
.
Otto
,
file
,
source
);
err
!=
nil
{
// TODO: throw exception
fmt
.
Println
(
"err:"
,
err
)
return
otto
.
FalseValue
()
}
// TODO: return evaluation result
return
otto
.
TrueValue
()
}
//
uses the "prettyPrint" JS function to format a value
//
PrettyPrint writes v to standard output.
func
(
self
*
JSRE
)
PrettyPrint
(
v
interface
{})
(
val
otto
.
Value
,
err
error
)
{
var
method
otto
.
Value
v
,
err
=
self
.
ToValue
(
v
)
if
err
!=
nil
{
return
}
method
,
err
=
self
.
vm
.
Get
(
"prettyPrint"
)
if
err
!=
nil
{
return
}
return
method
.
Call
(
method
,
v
)
}
// creates an otto value from a go type (serialized version)
func
(
self
*
JSRE
)
ToValue
(
v
interface
{})
(
otto
.
Value
,
error
)
{
done
:=
make
(
chan
bool
)
req
:=
&
evalReq
{
fn
:
func
(
res
*
evalResult
)
{
res
.
result
,
res
.
err
=
self
.
vm
.
ToValue
(
v
)
},
done
:
done
,
}
self
.
evalQueue
<-
req
<-
done
return
req
.
res
.
result
,
req
.
res
.
err
}
// creates an otto value from a go type (non-serialized version)
func
(
self
*
JSRE
)
ToVal
(
v
interface
{})
otto
.
Value
{
result
,
err
:=
self
.
vm
.
ToValue
(
v
)
if
err
!=
nil
{
fmt
.
Println
(
"Value unknown:"
,
err
)
return
otto
.
UndefinedValue
()
}
return
result
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
val
,
err
=
vm
.
ToValue
(
v
)
if
err
!=
nil
{
return
}
method
,
err
=
vm
.
Get
(
"prettyPrint"
)
if
err
!=
nil
{
return
}
val
,
err
=
method
.
Call
(
method
,
val
)
})
return
val
,
err
}
//
evaluates JS function and returns result in a pretty printed string format
//
Eval evaluates JS function and returns result in a pretty printed string format.
func
(
self
*
JSRE
)
Eval
(
code
string
)
(
s
string
,
err
error
)
{
var
val
otto
.
Value
val
,
err
=
self
.
Run
(
code
)
...
...
@@ -336,12 +269,16 @@ func (self *JSRE) Eval(code string) (s string, err error) {
return
fmt
.
Sprintf
(
"%v"
,
val
),
nil
}
// compiles and then runs a piece of JS code
func
(
self
*
JSRE
)
Compile
(
fn
string
,
src
interface
{})
error
{
script
,
err
:=
self
.
vm
.
Compile
(
fn
,
src
)
// Compile compiles and then runs a piece of JS code.
func
(
self
*
JSRE
)
Compile
(
filename
string
,
src
interface
{})
(
err
error
)
{
self
.
do
(
func
(
vm
*
otto
.
Otto
)
{
_
,
err
=
compileAndRun
(
vm
,
filename
,
src
)
})
return
err
}
func
compileAndRun
(
vm
*
otto
.
Otto
,
filename
string
,
src
interface
{})
(
otto
.
Value
,
error
)
{
script
,
err
:=
vm
.
Compile
(
filename
,
src
)
if
err
!=
nil
{
return
err
return
otto
.
Value
{},
err
}
self
.
run
(
script
,
true
)
return
nil
return
vm
.
Run
(
script
)
}
jsre/jsre_test.go
View file @
70867904
package
jsre
import
(
"github.com/robertkrimen/otto"
"io/ioutil"
"os"
"testing"
"time"
"github.com/robertkrimen/otto"
)
type
testNativeObjectBinding
struct
{
toVal
func
(
interface
{})
otto
.
Value
}
type
testNativeObjectBinding
struct
{}
type
msg
struct
{
Msg
string
...
...
@@ -21,7 +20,8 @@ func (no *testNativeObjectBinding) TestMethod(call otto.FunctionCall) otto.Value
if
err
!=
nil
{
return
otto
.
UndefinedValue
()
}
return
no
.
toVal
(
&
msg
{
m
})
v
,
_
:=
call
.
Otto
.
ToValue
(
&
msg
{
m
})
return
v
}
func
TestExec
(
t
*
testing
.
T
)
{
...
...
@@ -74,7 +74,7 @@ func TestNatto(t *testing.T) {
func
TestBind
(
t
*
testing
.
T
)
{
jsre
:=
New
(
"/tmp"
)
jsre
.
Bind
(
"no"
,
&
testNativeObjectBinding
{
jsre
.
ToVal
})
jsre
.
Bind
(
"no"
,
&
testNativeObjectBinding
{})
val
,
err
:=
jsre
.
Run
(
`no.TestMethod("testMsg")`
)
if
err
!=
nil
{
...
...
p2p/discover/database.go
View file @
70867904
...
...
@@ -44,9 +44,10 @@ var (
nodeDBVersionKey
=
[]
byte
(
"version"
)
// Version of the database to flush if changes
nodeDBItemPrefix
=
[]
byte
(
"n:"
)
// Identifier to prefix node entries with
nodeDBDiscoverRoot
=
":discover"
nodeDBDiscoverPing
=
nodeDBDiscoverRoot
+
":lastping"
nodeDBDiscoverPong
=
nodeDBDiscoverRoot
+
":lastpong"
nodeDBDiscoverRoot
=
":discover"
nodeDBDiscoverPing
=
nodeDBDiscoverRoot
+
":lastping"
nodeDBDiscoverPong
=
nodeDBDiscoverRoot
+
":lastpong"
nodeDBDiscoverFindFails
=
nodeDBDiscoverRoot
+
":findfail"
)
// newNodeDB creates a new node database for storing and retrieving infos about
...
...
@@ -275,6 +276,16 @@ func (db *nodeDB) updateLastPong(id NodeID, instance time.Time) error {
return
db
.
storeInt64
(
makeKey
(
id
,
nodeDBDiscoverPong
),
instance
.
Unix
())
}
// findFails retrieves the number of findnode failures since bonding.
func
(
db
*
nodeDB
)
findFails
(
id
NodeID
)
int
{
return
int
(
db
.
fetchInt64
(
makeKey
(
id
,
nodeDBDiscoverFindFails
)))
}
// updateFindFails updates the number of findnode failures since bonding.
func
(
db
*
nodeDB
)
updateFindFails
(
id
NodeID
,
fails
int
)
error
{
return
db
.
storeInt64
(
makeKey
(
id
,
nodeDBDiscoverFindFails
),
int64
(
fails
))
}
// querySeeds retrieves a batch of nodes to be used as potential seed servers
// during bootstrapping the node into the network.
//
...
...
p2p/discover/database_test.go
View file @
70867904
...
...
@@ -93,6 +93,7 @@ func TestNodeDBFetchStore(t *testing.T) {
30303
,
)
inst
:=
time
.
Now
()
num
:=
314
db
,
_
:=
newNodeDB
(
""
,
Version
,
NodeID
{})
defer
db
.
close
()
...
...
@@ -117,6 +118,16 @@ func TestNodeDBFetchStore(t *testing.T) {
if
stored
:=
db
.
lastPong
(
node
.
ID
);
stored
.
Unix
()
!=
inst
.
Unix
()
{
t
.
Errorf
(
"pong: value mismatch: have %v, want %v"
,
stored
,
inst
)
}
// Check fetch/store operations on a node findnode-failure object
if
stored
:=
db
.
findFails
(
node
.
ID
);
stored
!=
0
{
t
.
Errorf
(
"find-node fails: non-existing object: %v"
,
stored
)
}
if
err
:=
db
.
updateFindFails
(
node
.
ID
,
num
);
err
!=
nil
{
t
.
Errorf
(
"find-node fails: failed to update: %v"
,
err
)
}
if
stored
:=
db
.
findFails
(
node
.
ID
);
stored
!=
num
{
t
.
Errorf
(
"find-node fails: value mismatch: have %v, want %v"
,
stored
,
num
)
}
// Check fetch/store operations on an actual node object
if
stored
:=
db
.
node
(
node
.
ID
);
stored
!=
nil
{
t
.
Errorf
(
"node: non-existing object: %v"
,
stored
)
...
...
p2p/discover/table.go
View file @
70867904
...
...
@@ -27,6 +27,7 @@ const (
nBuckets
=
hashBits
+
1
// Number of buckets
maxBondingPingPongs
=
16
maxFindnodeFailures
=
5
)
type
Table
struct
{
...
...
@@ -190,6 +191,12 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
result
:=
tab
.
closest
(
target
,
bucketSize
)
tab
.
mutex
.
Unlock
()
// If the result set is empty, all nodes were dropped, refresh
if
len
(
result
.
entries
)
==
0
{
tab
.
refresh
()
return
nil
}
for
{
// ask the alpha closest nodes that we haven't asked yet
for
i
:=
0
;
i
<
len
(
result
.
entries
)
&&
pendingQueries
<
alpha
;
i
++
{
...
...
@@ -198,7 +205,19 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
asked
[
n
.
ID
]
=
true
pendingQueries
++
go
func
()
{
r
,
_
:=
tab
.
net
.
findnode
(
n
.
ID
,
n
.
addr
(),
targetID
)
// Find potential neighbors to bond with
r
,
err
:=
tab
.
net
.
findnode
(
n
.
ID
,
n
.
addr
(),
targetID
)
if
err
!=
nil
{
// Bump the failure counter to detect and evacuate non-bonded entries
fails
:=
tab
.
db
.
findFails
(
n
.
ID
)
+
1
tab
.
db
.
updateFindFails
(
n
.
ID
,
fails
)
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"Bumping failures for %x: %d"
,
n
.
ID
[
:
8
],
fails
)
if
fails
>=
maxFindnodeFailures
{
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"Evacuating node %x: %d findnode failures"
,
n
.
ID
[
:
8
],
fails
)
tab
.
del
(
n
)
}
}
reply
<-
tab
.
bondall
(
r
)
}()
}
...
...
@@ -219,30 +238,53 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
return
result
.
entries
}
// refresh performs a lookup for a random target to keep buckets full.
// refresh performs a lookup for a random target to keep buckets full, or seeds
// the table if it is empty (initial bootstrap or discarded faulty peers).
func
(
tab
*
Table
)
refresh
()
{
// The Kademlia paper specifies that the bucket refresh should
// perform a refresh in the least recently used bucket. We cannot
// adhere to this because the findnode target is a 512bit value
// (not hash-sized) and it is not easily possible to generate a
// sha3 preimage that falls into a chosen bucket.
//
// We perform a lookup with a random target instead.
var
target
NodeID
rand
.
Read
(
target
[
:
])
result
:=
tab
.
Lookup
(
target
)
if
len
(
result
)
==
0
{
seed
:=
true
// If the discovery table is empty, seed with previously known nodes
tab
.
mutex
.
Lock
()
for
_
,
bucket
:=
range
tab
.
buckets
{
if
len
(
bucket
.
entries
)
>
0
{
seed
=
false
break
}
}
tab
.
mutex
.
Unlock
()
// If the table is not empty, try to refresh using the live entries
if
!
seed
{
// The Kademlia paper specifies that the bucket refresh should
// perform a refresh in the least recently used bucket. We cannot
// adhere to this because the findnode target is a 512bit value
// (not hash-sized) and it is not easily possible to generate a
// sha3 preimage that falls into a chosen bucket.
//
// We perform a lookup with a random target instead.
var
target
NodeID
rand
.
Read
(
target
[
:
])
result
:=
tab
.
Lookup
(
target
)
if
len
(
result
)
==
0
{
// Lookup failed, seed after all
seed
=
true
}
}
if
seed
{
// Pick a batch of previously know seeds to lookup with
seeds
:=
tab
.
db
.
querySeeds
(
10
)
for
_
,
seed
:=
range
seeds
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"Seeding network with"
,
seed
)
}
// Bootstrap the table with a self lookup
all
:=
tab
.
bondall
(
append
(
tab
.
nursery
,
seeds
...
))
tab
.
mutex
.
Lock
()
tab
.
add
(
all
)
tab
.
mutex
.
Unlock
()
tab
.
Lookup
(
tab
.
self
.
ID
)
nodes
:=
append
(
tab
.
nursery
,
seeds
...
)
// Bond with all the seed nodes (will pingpong only if failed recently)
bonded
:=
tab
.
bondall
(
nodes
)
if
len
(
bonded
)
>
0
{
tab
.
Lookup
(
tab
.
self
.
ID
)
}
// TODO: the Kademlia paper says that we're supposed to perform
// random lookups in all buckets further away than our closest neighbor.
}
...
...
@@ -305,8 +347,16 @@ func (tab *Table) bondall(nodes []*Node) (result []*Node) {
// If pinged is true, the remote node has just pinged us and one half
// of the process can be skipped.
func
(
tab
*
Table
)
bond
(
pinged
bool
,
id
NodeID
,
addr
*
net
.
UDPAddr
,
tcpPort
uint16
)
(
*
Node
,
error
)
{
var
n
*
Node
if
n
=
tab
.
db
.
node
(
id
);
n
==
nil
{
// Retrieve a previously known node and any recent findnode failures
node
,
fails
:=
tab
.
db
.
node
(
id
),
0
if
node
!=
nil
{
fails
=
tab
.
db
.
findFails
(
id
)
}
// If the node is unknown (non-bonded) or failed (remotely unknown), bond from scratch
var
result
error
if
node
==
nil
||
fails
>
0
{
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"Bonding %x: known=%v, fails=%v"
,
id
[
:
8
],
node
!=
nil
,
fails
)
tab
.
bondmu
.
Lock
()
w
:=
tab
.
bonding
[
id
]
if
w
!=
nil
{
...
...
@@ -325,18 +375,24 @@ func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16
delete
(
tab
.
bonding
,
id
)
tab
.
bondmu
.
Unlock
()
}
n
=
w
.
n
if
w
.
err
!=
nil
{
return
nil
,
w
.
err
// Retrieve the bonding results
result
=
w
.
err
if
result
==
nil
{
node
=
w
.
n
}
}
tab
.
mutex
.
Lock
()
defer
tab
.
mutex
.
Unlock
()
b
:=
tab
.
buckets
[
logdist
(
tab
.
self
.
sha
,
n
.
sha
)]
if
!
b
.
bump
(
n
)
{
tab
.
pingreplace
(
n
,
b
)
// Even if bonding temporarily failed, give the node a chance
if
node
!=
nil
{
tab
.
mutex
.
Lock
()
defer
tab
.
mutex
.
Unlock
()
b
:=
tab
.
buckets
[
logdist
(
tab
.
self
.
sha
,
node
.
sha
)]
if
!
b
.
bump
(
node
)
{
tab
.
pingreplace
(
node
,
b
)
}
tab
.
db
.
updateFindFails
(
id
,
0
)
}
return
n
,
nil
return
n
ode
,
result
}
func
(
tab
*
Table
)
pingpong
(
w
*
bondproc
,
pinged
bool
,
id
NodeID
,
addr
*
net
.
UDPAddr
,
tcpPort
uint16
)
{
...
...
@@ -414,6 +470,21 @@ outer:
}
}
// del removes an entry from the node table (used to evacuate failed/non-bonded
// discovery peers).
func
(
tab
*
Table
)
del
(
node
*
Node
)
{
tab
.
mutex
.
Lock
()
defer
tab
.
mutex
.
Unlock
()
bucket
:=
tab
.
buckets
[
logdist
(
tab
.
self
.
sha
,
node
.
sha
)]
for
i
:=
range
bucket
.
entries
{
if
bucket
.
entries
[
i
]
.
ID
==
node
.
ID
{
bucket
.
entries
=
append
(
bucket
.
entries
[
:
i
],
bucket
.
entries
[
i
+
1
:
]
...
)
return
}
}
}
func
(
b
*
bucket
)
bump
(
n
*
Node
)
bool
{
for
i
:=
range
b
.
entries
{
if
b
.
entries
[
i
]
.
ID
==
n
.
ID
{
...
...
p2p/server.go
View file @
70867904
...
...
@@ -55,6 +55,10 @@ type Server struct {
// Zero defaults to preset values.
MaxPendingPeers
int
// Discovery specifies whether the peer discovery mechanism should be started
// or not. Disabling is usually useful for protocol debugging (manual topology).
Discovery
bool
// Name sets the node name of this server.
// Use common.MakeName to create a name that follows existing conventions.
Name
string
...
...
@@ -237,9 +241,26 @@ func (srv *Server) AddPeer(node *discover.Node) {
func
(
srv
*
Server
)
Self
()
*
discover
.
Node
{
srv
.
lock
.
Lock
()
defer
srv
.
lock
.
Unlock
()
// If the server's not running, return an empty node
if
!
srv
.
running
{
return
&
discover
.
Node
{
IP
:
net
.
ParseIP
(
"0.0.0.0"
)}
}
// If the node is running but discovery is off, manually assemble the node infos
if
srv
.
ntab
==
nil
{
// Inbound connections disabled, use zero address
if
srv
.
listener
==
nil
{
return
&
discover
.
Node
{
IP
:
net
.
ParseIP
(
"0.0.0.0"
),
ID
:
discover
.
PubkeyID
(
&
srv
.
PrivateKey
.
PublicKey
)}
}
// Otherwise inject the listener address too
addr
:=
srv
.
listener
.
Addr
()
.
(
*
net
.
TCPAddr
)
return
&
discover
.
Node
{
ID
:
discover
.
PubkeyID
(
&
srv
.
PrivateKey
.
PublicKey
),
IP
:
addr
.
IP
,
TCP
:
uint16
(
addr
.
Port
),
}
}
// Otherwise return the live node infos
return
srv
.
ntab
.
Self
()
}
...
...
@@ -275,9 +296,6 @@ func (srv *Server) Start() (err error) {
if
srv
.
PrivateKey
==
nil
{
return
fmt
.
Errorf
(
"Server.PrivateKey must be set to a non-nil key"
)
}
if
srv
.
MaxPeers
<=
0
{
return
fmt
.
Errorf
(
"Server.MaxPeers must be > 0"
)
}
if
srv
.
newTransport
==
nil
{
srv
.
newTransport
=
newRLPX
}
...
...
@@ -293,15 +311,22 @@ func (srv *Server) Start() (err error) {
srv
.
peerOpDone
=
make
(
chan
struct
{})
// node table
ntab
,
err
:=
discover
.
ListenUDP
(
srv
.
PrivateKey
,
srv
.
ListenAddr
,
srv
.
NAT
,
srv
.
NodeDatabase
)
if
err
!=
nil
{
return
err
if
srv
.
Discovery
{
ntab
,
err
:=
discover
.
ListenUDP
(
srv
.
PrivateKey
,
srv
.
ListenAddr
,
srv
.
NAT
,
srv
.
NodeDatabase
)
if
err
!=
nil
{
return
err
}
srv
.
ntab
=
ntab
}
srv
.
ntab
=
ntab
dialer
:=
newDialState
(
srv
.
StaticNodes
,
srv
.
ntab
,
srv
.
MaxPeers
/
2
)
dynPeers
:=
srv
.
MaxPeers
/
2
if
!
srv
.
Discovery
{
dynPeers
=
0
}
dialer
:=
newDialState
(
srv
.
StaticNodes
,
srv
.
ntab
,
dynPeers
)
// handshake
srv
.
ourHandshake
=
&
protoHandshake
{
Version
:
baseProtocolVersion
,
Name
:
srv
.
Name
,
ID
:
ntab
.
Self
()
.
ID
}
srv
.
ourHandshake
=
&
protoHandshake
{
Version
:
baseProtocolVersion
,
Name
:
srv
.
Name
,
ID
:
discover
.
PubkeyID
(
&
srv
.
PrivateKey
.
PublicKey
)
}
for
_
,
p
:=
range
srv
.
Protocols
{
srv
.
ourHandshake
.
Caps
=
append
(
srv
.
ourHandshake
.
Caps
,
p
.
cap
())
}
...
...
@@ -457,7 +482,9 @@ running:
}
// Terminate discovery. If there is a running lookup it will terminate soon.
srv
.
ntab
.
Close
()
if
srv
.
ntab
!=
nil
{
srv
.
ntab
.
Close
()
}
// Disconnect all peers.
for
_
,
p
:=
range
peers
{
p
.
Disconnect
(
DiscQuitting
)
...
...
@@ -489,7 +516,7 @@ func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn)
return
DiscTooManyPeers
case
peers
[
c
.
id
]
!=
nil
:
return
DiscAlreadyConnected
case
c
.
id
==
srv
.
ntab
.
Self
()
.
ID
:
case
c
.
id
==
srv
.
Self
()
.
ID
:
return
DiscSelf
default
:
return
nil
...
...
rpc/jeth.go
View file @
70867904
...
...
@@ -3,18 +3,18 @@ package rpc
import
(
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/jsre"
"github.com/robertkrimen/otto"
)
type
Jeth
struct
{
ethApi
*
EthereumApi
toVal
func
(
interface
{})
otto
.
Value
re
*
jsre
.
JSRE
}
func
NewJeth
(
ethApi
*
EthereumApi
,
toVal
func
(
interface
{})
otto
.
Value
,
re
*
jsre
.
JSRE
)
*
Jeth
{
return
&
Jeth
{
ethApi
,
toVal
,
re
}
func
NewJeth
(
ethApi
*
EthereumApi
,
re
*
jsre
.
JSRE
)
*
Jeth
{
return
&
Jeth
{
ethApi
,
re
}
}
func
(
self
*
Jeth
)
err
(
call
otto
.
FunctionCall
,
code
int
,
msg
string
,
id
interface
{})
(
response
otto
.
Value
)
{
...
...
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