Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
7f7abfe4
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
7f7abfe4
编写于
10月 17, 2017
作者:
P
Péter Szilágyi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
cmd/faucet: proper error handling all over
上级
0bb194c9
变更
3
展开全部
隐藏空白更改
内联
并排
Showing
3 changed file
with
135 addition
and
36 deletion
+135
-36
cmd/faucet/faucet.go
cmd/faucet/faucet.go
+132
-33
cmd/faucet/faucet.html
cmd/faucet/faucet.html
+2
-2
cmd/faucet/website.go
cmd/faucet/website.go
+1
-1
未找到文件。
cmd/faucet/faucet.go
浏览文件 @
7f7abfe4
...
...
@@ -302,6 +302,8 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
// apiHandler handles requests for Ether grants and transaction statuses.
func
(
f
*
faucet
)
apiHandler
(
conn
*
websocket
.
Conn
)
{
// Start tracking the connection and drop at the end
defer
conn
.
Close
()
f
.
lock
.
Lock
()
f
.
conns
=
append
(
f
.
conns
,
conn
)
f
.
lock
.
Unlock
()
...
...
@@ -316,25 +318,50 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
}
f
.
lock
.
Unlock
()
}()
// Send a few initial stats to the client
balance
,
_
:=
f
.
client
.
BalanceAt
(
context
.
Background
(),
f
.
account
.
Address
,
nil
)
nonce
,
_
:=
f
.
client
.
NonceAt
(
context
.
Background
(),
f
.
account
.
Address
,
nil
)
// Gather the initial stats from the network to report
var
(
head
*
types
.
Header
balance
*
big
.
Int
nonce
uint64
err
error
)
for
{
// Attempt to retrieve the stats, may error on no faucet connectivity
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
3
*
time
.
Second
)
head
,
err
=
f
.
client
.
HeaderByNumber
(
ctx
,
nil
)
if
err
==
nil
{
balance
,
err
=
f
.
client
.
BalanceAt
(
ctx
,
f
.
account
.
Address
,
head
.
Number
)
if
err
==
nil
{
nonce
,
err
=
f
.
client
.
NonceAt
(
ctx
,
f
.
account
.
Address
,
nil
)
}
}
cancel
()
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
interface
{}{
// If stats retrieval failed, wait a bit and retry
if
err
!=
nil
{
if
err
=
sendError
(
conn
,
errors
.
New
(
"Faucet offline: "
+
err
.
Error
()));
err
!=
nil
{
log
.
Warn
(
"Failed to send faucet error to client"
,
"err"
,
err
)
return
}
time
.
Sleep
(
3
*
time
.
Second
)
continue
}
// Initial stats reported successfully, proceed with user interaction
break
}
// Send over the initial stats and the latest header
if
err
=
send
(
conn
,
map
[
string
]
interface
{}{
"funds"
:
balance
.
Div
(
balance
,
ether
),
"funded"
:
nonce
,
"peers"
:
f
.
stack
.
Server
()
.
PeerCount
(),
"requests"
:
f
.
reqs
,
})
// Send the initial block to the client
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
time
.
Second
)
header
,
err
:=
f
.
client
.
HeaderByNumber
(
ctx
,
nil
)
cancel
()
if
err
!=
nil
{
log
.
Error
(
"Failed to retrieve latest header"
,
"err"
,
err
)
}
else
{
websocket
.
JSON
.
Send
(
conn
,
header
)
},
3
*
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send initial stats to client"
,
"err"
,
err
)
return
}
if
err
=
send
(
conn
,
head
,
3
*
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send initial header to client"
,
"err"
,
err
)
return
}
// Keep reading requests from the websocket until the connection breaks
for
{
...
...
@@ -344,16 +371,22 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
Tier
uint
`json:"tier"`
Captcha
string
`json:"captcha"`
}
if
err
:
=
websocket
.
JSON
.
Receive
(
conn
,
&
msg
);
err
!=
nil
{
if
err
=
websocket
.
JSON
.
Receive
(
conn
,
&
msg
);
err
!=
nil
{
return
}
if
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://gist.github.com/"
)
&&
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://twitter.com/"
)
&&
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://plus.google.com/"
)
&&
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://www.facebook.com/"
)
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
"URL doesn't link to supported services"
})
if
err
=
sendError
(
conn
,
errors
.
New
(
"URL doesn't link to supported services"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send URL error to client"
,
"err"
,
err
)
return
}
continue
}
if
msg
.
Tier
>=
uint
(
*
tiersFlag
)
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
"Invalid funding tier requested"
})
if
err
=
sendError
(
conn
,
errors
.
New
(
"Invalid funding tier requested"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send tier error to client"
,
"err"
,
err
)
return
}
continue
}
log
.
Info
(
"Faucet funds requested"
,
"url"
,
msg
.
URL
,
"tier"
,
msg
.
Tier
)
...
...
@@ -366,7 +399,10 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
res
,
err
:=
http
.
PostForm
(
"https://www.google.com/recaptcha/api/siteverify"
,
form
)
if
err
!=
nil
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()})
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha post error to client"
,
"err"
,
err
)
return
}
continue
}
var
result
struct
{
...
...
@@ -376,12 +412,18 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
err
=
json
.
NewDecoder
(
res
.
Body
)
.
Decode
(
&
result
)
res
.
Body
.
Close
()
if
err
!=
nil
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()})
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha decode error to client"
,
"err"
,
err
)
return
}
continue
}
if
!
result
.
Success
{
log
.
Warn
(
"Captcha verification failed"
,
"err"
,
string
(
result
.
Errors
))
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
"Beep-bop, you're a robot!"
})
if
err
=
sendError
(
conn
,
errors
.
New
(
"Beep-bop, you're a robot!"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha failure to client"
,
"err"
,
err
)
return
}
continue
}
}
...
...
@@ -404,7 +446,10 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
err
=
errors
.
New
(
"Something funky happened, please open an issue at https://github.com/ethereum/go-ethereum/issues"
)
}
if
err
!=
nil
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()})
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send prefix error to client"
,
"err"
,
err
)
return
}
continue
}
log
.
Info
(
"Faucet request valid"
,
"url"
,
msg
.
URL
,
"tier"
,
msg
.
Tier
,
"user"
,
username
,
"address"
,
address
)
...
...
@@ -424,14 +469,20 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
tx
:=
types
.
NewTransaction
(
f
.
nonce
+
uint64
(
len
(
f
.
reqs
)),
address
,
amount
,
big
.
NewInt
(
21000
),
f
.
price
,
nil
)
signed
,
err
:=
f
.
keystore
.
SignTx
(
f
.
account
,
tx
,
f
.
config
.
ChainId
)
if
err
!=
nil
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()})
f
.
lock
.
Unlock
()
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send transaction creation error to client"
,
"err"
,
err
)
return
}
continue
}
// Submit the transaction and mark as funded if successful
if
err
:=
f
.
client
.
SendTransaction
(
context
.
Background
(),
signed
);
err
!=
nil
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()})
f
.
lock
.
Unlock
()
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send transaction transmission error to client"
,
"err"
,
err
)
return
}
continue
}
f
.
reqs
=
append
(
f
.
reqs
,
&
request
{
...
...
@@ -447,10 +498,16 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
// Send an error if too frequent funding, othewise a success
if
!
fund
{
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"error"
:
fmt
.
Sprintf
(
"%s left until next allowance"
,
common
.
PrettyDuration
(
timeout
.
Sub
(
time
.
Now
())))})
if
err
=
sendError
(
conn
,
fmt
.
Errorf
(
"%s left until next allowance"
,
common
.
PrettyDuration
(
timeout
.
Sub
(
time
.
Now
()))));
err
!=
nil
{
log
.
Warn
(
"Failed to send funding error to client"
,
"err"
,
err
)
return
}
continue
}
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
string
{
"success"
:
fmt
.
Sprintf
(
"Funding request accepted for %s into %s"
,
username
,
address
.
Hex
())})
if
err
=
sendSuccess
(
conn
,
fmt
.
Sprintf
(
"Funding request accepted for %s into %s"
,
username
,
address
.
Hex
()));
err
!=
nil
{
log
.
Warn
(
"Failed to send funding success to client"
,
"err"
,
err
)
return
}
select
{
case
f
.
update
<-
struct
{}{}
:
default
:
...
...
@@ -473,11 +530,31 @@ func (f *faucet) loop() {
select
{
case
head
:=
<-
heads
:
// New chain head arrived, query the current stats and stream to clients
balance
,
_
:=
f
.
client
.
BalanceAt
(
context
.
Background
(),
f
.
account
.
Address
,
nil
)
balance
=
new
(
big
.
Int
)
.
Div
(
balance
,
ether
)
var
(
balance
*
big
.
Int
nonce
uint64
price
*
big
.
Int
err
error
)
ctx
,
cancel
:=
context
.
WithTimeout
(
context
.
Background
(),
5
*
time
.
Second
)
balance
,
err
=
f
.
client
.
BalanceAt
(
ctx
,
f
.
account
.
Address
,
head
.
Number
)
if
err
==
nil
{
nonce
,
err
=
f
.
client
.
NonceAt
(
ctx
,
f
.
account
.
Address
,
nil
)
if
err
==
nil
{
price
,
err
=
f
.
client
.
SuggestGasPrice
(
ctx
)
}
}
cancel
()
price
,
_
:=
f
.
client
.
SuggestGasPrice
(
context
.
Background
())
nonce
,
_
:=
f
.
client
.
NonceAt
(
context
.
Background
(),
f
.
account
.
Address
,
nil
)
// If querying the data failed, try for the next block
if
err
!=
nil
{
log
.
Warn
(
"Failed to update faucet state"
,
"block"
,
head
.
Number
,
"hash"
,
head
.
Hash
(),
"err"
,
err
)
continue
}
else
{
log
.
Info
(
"Updated faucet state"
,
"block"
,
head
.
Number
,
"hash"
,
head
.
Hash
(),
"balance"
,
balance
,
"nonce"
,
nonce
,
"price"
,
price
)
}
// Faucet state retrieved, update locally and send to clients
balance
=
new
(
big
.
Int
)
.
Div
(
balance
,
ether
)
f
.
lock
.
Lock
()
f
.
price
,
f
.
nonce
=
price
,
nonce
...
...
@@ -488,17 +565,17 @@ func (f *faucet) loop() {
f
.
lock
.
RLock
()
for
_
,
conn
:=
range
f
.
conns
{
if
err
:=
websocket
.
JSON
.
S
end
(
conn
,
map
[
string
]
interface
{}{
if
err
:=
s
end
(
conn
,
map
[
string
]
interface
{}{
"funds"
:
balance
,
"funded"
:
f
.
nonce
,
"peers"
:
f
.
stack
.
Server
()
.
PeerCount
(),
"requests"
:
f
.
reqs
,
});
err
!=
nil
{
}
,
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send stats to client"
,
"err"
,
err
)
conn
.
Close
()
continue
}
if
err
:=
websocket
.
JSON
.
Send
(
conn
,
hea
d
);
err
!=
nil
{
if
err
:=
send
(
conn
,
head
,
time
.
Secon
d
);
err
!=
nil
{
log
.
Warn
(
"Failed to send header to client"
,
"err"
,
err
)
conn
.
Close
()
}
...
...
@@ -509,7 +586,7 @@ func (f *faucet) loop() {
// Pending requests updated, stream to clients
f
.
lock
.
RLock
()
for
_
,
conn
:=
range
f
.
conns
{
if
err
:=
websocket
.
JSON
.
Send
(
conn
,
map
[
string
]
interface
{}{
"requests"
:
f
.
reqs
}
);
err
!=
nil
{
if
err
:=
send
(
conn
,
map
[
string
]
interface
{}{
"requests"
:
f
.
reqs
},
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send requests to client"
,
"err"
,
err
)
conn
.
Close
()
}
...
...
@@ -519,6 +596,28 @@ func (f *faucet) loop() {
}
}
// sends transmits a data packet to the remote end of the websocket, but also
// setting a write deadline to prevent waiting forever on the node.
func
send
(
conn
*
websocket
.
Conn
,
value
interface
{},
timeout
time
.
Duration
)
error
{
if
timeout
==
0
{
timeout
=
60
*
time
.
Second
}
conn
.
SetWriteDeadline
(
time
.
Now
()
.
Add
(
timeout
))
return
websocket
.
JSON
.
Send
(
conn
,
value
)
}
// sendError transmits an error to the remote end of the websocket, also setting
// the write deadline to 1 second to prevent waiting forever.
func
sendError
(
conn
*
websocket
.
Conn
,
err
error
)
error
{
return
send
(
conn
,
map
[
string
]
string
{
"error"
:
err
.
Error
()},
time
.
Second
)
}
// sendSuccess transmits a success message to the remote end of the websocket, also
// setting the write deadline to 1 second to prevent waiting forever.
func
sendSuccess
(
conn
*
websocket
.
Conn
,
msg
string
)
error
{
return
send
(
conn
,
map
[
string
]
string
{
"success"
:
msg
},
time
.
Second
)
}
// authGitHub tries to authenticate a faucet request using GitHub gists, returning
// the username, avatar URL and Ethereum address to fund on success.
func
authGitHub
(
url
string
)
(
string
,
string
,
common
.
Address
,
error
)
{
...
...
cmd/faucet/faucet.html
浏览文件 @
7f7abfe4
...
...
@@ -140,10 +140,10 @@
$
(
"
#block
"
).
text
(
parseInt
(
msg
.
number
,
16
));
}
if
(
msg
.
error
!==
undefined
)
{
noty
({
layout
:
'
topCenter
'
,
text
:
msg
.
error
,
type
:
'
error
'
});
noty
({
layout
:
'
topCenter
'
,
text
:
msg
.
error
,
type
:
'
error
'
,
timeout
:
5000
,
progressBar
:
true
});
}
if
(
msg
.
success
!==
undefined
)
{
noty
({
layout
:
'
topCenter
'
,
text
:
msg
.
success
,
type
:
'
success
'
});
noty
({
layout
:
'
topCenter
'
,
text
:
msg
.
success
,
type
:
'
success
'
,
timeout
:
15000
,
progressBar
:
true
});
}
if
(
msg
.
requests
!==
undefined
&&
msg
.
requests
!==
null
)
{
var
content
=
""
;
...
...
cmd/faucet/website.go
浏览文件 @
7f7abfe4
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录