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
44208d92
Unverified
Commit
44208d92
authored
Jan 07, 2021
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd/faucet: fix websocket race regression after switching to gorilla
parent
8bd8e1b2
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
35 additions
and
24 deletions
+35
-24
faucet.go
cmd/faucet/faucet.go
+35
-24
No files found.
cmd/faucet/faucet.go
View file @
44208d92
...
...
@@ -213,7 +213,7 @@ type faucet struct {
nonce
uint64
// Current pending nonce of the faucet
price
*
big
.
Int
// Current gas price to issue funds with
conns
[]
*
w
ebsocket
.
Conn
// Currently live websocket connections
conns
[]
*
w
sConn
// Currently live websocket connections
timeouts
map
[
string
]
time
.
Time
// History of users and their funding timeouts
reqs
[]
*
request
// Currently pending funding requests
update
chan
struct
{}
// Channel to signal request updates
...
...
@@ -221,6 +221,13 @@ type faucet struct {
lock
sync
.
RWMutex
// Lock protecting the faucet's internals
}
// wsConn wraps a websocket connection with a write mutex as the underlying
// websocket library does not synchronize access to the stream.
type
wsConn
struct
{
conn
*
websocket
.
Conn
wlock
sync
.
Mutex
}
func
newFaucet
(
genesis
*
core
.
Genesis
,
port
int
,
enodes
[]
*
discv5
.
Node
,
network
uint64
,
stats
string
,
ks
*
keystore
.
KeyStore
,
index
[]
byte
)
(
*
faucet
,
error
)
{
// Assemble the raw devp2p protocol stack
stack
,
err
:=
node
.
New
(
&
node
.
Config
{
...
...
@@ -321,13 +328,14 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
defer
conn
.
Close
()
f
.
lock
.
Lock
()
f
.
conns
=
append
(
f
.
conns
,
conn
)
wsconn
:=
&
wsConn
{
conn
:
conn
}
f
.
conns
=
append
(
f
.
conns
,
wsconn
)
f
.
lock
.
Unlock
()
defer
func
()
{
f
.
lock
.
Lock
()
for
i
,
c
:=
range
f
.
conns
{
if
c
==
conn
{
if
c
.
conn
==
conn
{
f
.
conns
=
append
(
f
.
conns
[
:
i
],
f
.
conns
[
i
+
1
:
]
...
)
break
}
...
...
@@ -355,7 +363,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
if
head
==
nil
||
balance
==
nil
{
// Report the faucet offline until initial stats are ready
//lint:ignore ST1005 This error is to be displayed in the browser
if
err
=
sendError
(
conn
,
errors
.
New
(
"Faucet offline"
));
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
errors
.
New
(
"Faucet offline"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send faucet error to client"
,
"err"
,
err
)
return
}
...
...
@@ -366,7 +374,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
f
.
lock
.
RLock
()
reqs
:=
f
.
reqs
f
.
lock
.
RUnlock
()
if
err
=
send
(
conn
,
map
[
string
]
interface
{}{
if
err
=
send
(
ws
conn
,
map
[
string
]
interface
{}{
"funds"
:
new
(
big
.
Int
)
.
Div
(
balance
,
ether
),
"funded"
:
nonce
,
"peers"
:
f
.
stack
.
Server
()
.
PeerCount
(),
...
...
@@ -375,7 +383,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
log
.
Warn
(
"Failed to send initial stats to client"
,
"err"
,
err
)
return
}
if
err
=
send
(
conn
,
head
,
3
*
time
.
Second
);
err
!=
nil
{
if
err
=
send
(
ws
conn
,
head
,
3
*
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send initial header to client"
,
"err"
,
err
)
return
}
...
...
@@ -391,7 +399,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
return
}
if
!*
noauthFlag
&&
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://twitter.com/"
)
&&
!
strings
.
HasPrefix
(
msg
.
URL
,
"https://www.facebook.com/"
)
{
if
err
=
sendError
(
conn
,
errors
.
New
(
"URL doesn't link to supported services"
));
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
errors
.
New
(
"URL doesn't link to supported services"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send URL error to client"
,
"err"
,
err
)
return
}
...
...
@@ -399,7 +407,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
}
if
msg
.
Tier
>=
uint
(
*
tiersFlag
)
{
//lint:ignore ST1005 This error is to be displayed in the browser
if
err
=
sendError
(
conn
,
errors
.
New
(
"Invalid funding tier requested"
));
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
errors
.
New
(
"Invalid funding tier requested"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send tier error to client"
,
"err"
,
err
)
return
}
...
...
@@ -415,7 +423,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
res
,
err
:=
http
.
PostForm
(
"https://www.google.com/recaptcha/api/siteverify"
,
form
)
if
err
!=
nil
{
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha post error to client"
,
"err"
,
err
)
return
}
...
...
@@ -428,7 +436,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
err
=
json
.
NewDecoder
(
res
.
Body
)
.
Decode
(
&
result
)
res
.
Body
.
Close
()
if
err
!=
nil
{
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha decode error to client"
,
"err"
,
err
)
return
}
...
...
@@ -437,7 +445,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
if
!
result
.
Success
{
log
.
Warn
(
"Captcha verification failed"
,
"err"
,
string
(
result
.
Errors
))
//lint:ignore ST1005 it's funny and the robot won't mind
if
err
=
sendError
(
conn
,
errors
.
New
(
"Beep-bop, you're a robot!"
));
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
errors
.
New
(
"Beep-bop, you're a robot!"
));
err
!=
nil
{
log
.
Warn
(
"Failed to send captcha failure to client"
,
"err"
,
err
)
return
}
...
...
@@ -465,7 +473,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
err
=
errors
.
New
(
"Something funky happened, please open an issue at https://github.com/ethereum/go-ethereum/issues"
)
}
if
err
!=
nil
{
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send prefix error to client"
,
"err"
,
err
)
return
}
...
...
@@ -489,7 +497,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
signed
,
err
:=
f
.
keystore
.
SignTx
(
f
.
account
,
tx
,
f
.
config
.
ChainID
)
if
err
!=
nil
{
f
.
lock
.
Unlock
()
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send transaction creation error to client"
,
"err"
,
err
)
return
}
...
...
@@ -498,7 +506,7 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
// Submit the transaction and mark as funded if successful
if
err
:=
f
.
client
.
SendTransaction
(
context
.
Background
(),
signed
);
err
!=
nil
{
f
.
lock
.
Unlock
()
if
err
=
sendError
(
conn
,
err
);
err
!=
nil
{
if
err
=
sendError
(
ws
conn
,
err
);
err
!=
nil
{
log
.
Warn
(
"Failed to send transaction transmission error to client"
,
"err"
,
err
)
return
}
...
...
@@ -520,13 +528,13 @@ func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
// Send an error if too frequent funding, othewise a success
if
!
fund
{
if
err
=
sendError
(
conn
,
fmt
.
Errorf
(
"%s left until next allowance"
,
common
.
PrettyDuration
(
time
.
Until
(
timeout
))));
err
!=
nil
{
// nolint: gosimple
if
err
=
sendError
(
ws
conn
,
fmt
.
Errorf
(
"%s left until next allowance"
,
common
.
PrettyDuration
(
time
.
Until
(
timeout
))));
err
!=
nil
{
// nolint: gosimple
log
.
Warn
(
"Failed to send funding error to client"
,
"err"
,
err
)
return
}
continue
}
if
err
=
sendSuccess
(
conn
,
fmt
.
Sprintf
(
"Funding request accepted for %s into %s"
,
username
,
address
.
Hex
()));
err
!=
nil
{
if
err
=
sendSuccess
(
ws
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
}
...
...
@@ -619,12 +627,12 @@ func (f *faucet) loop() {
"requests"
:
f
.
reqs
,
},
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send stats to client"
,
"err"
,
err
)
conn
.
Close
()
conn
.
conn
.
Close
()
continue
}
if
err
:=
send
(
conn
,
head
,
time
.
Second
);
err
!=
nil
{
log
.
Warn
(
"Failed to send header to client"
,
"err"
,
err
)
conn
.
Close
()
conn
.
conn
.
Close
()
}
}
f
.
lock
.
RUnlock
()
...
...
@@ -646,7 +654,7 @@ func (f *faucet) loop() {
for
_
,
conn
:=
range
f
.
conns
{
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
()
conn
.
conn
.
Close
()
}
}
f
.
lock
.
RUnlock
()
...
...
@@ -656,23 +664,26 @@ 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
*
w
ebsocket
.
Conn
,
value
interface
{},
timeout
time
.
Duration
)
error
{
func
send
(
conn
*
w
s
Conn
,
value
interface
{},
timeout
time
.
Duration
)
error
{
if
timeout
==
0
{
timeout
=
60
*
time
.
Second
}
conn
.
SetWriteDeadline
(
time
.
Now
()
.
Add
(
timeout
))
return
conn
.
WriteJSON
(
value
)
conn
.
wlock
.
Lock
()
defer
conn
.
wlock
.
Unlock
()
conn
.
conn
.
SetWriteDeadline
(
time
.
Now
()
.
Add
(
timeout
))
return
conn
.
conn
.
WriteJSON
(
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
*
w
ebsocket
.
Conn
,
err
error
)
error
{
func
sendError
(
conn
*
w
s
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
*
w
ebsocket
.
Conn
,
msg
string
)
error
{
func
sendSuccess
(
conn
*
w
s
Conn
,
msg
string
)
error
{
return
send
(
conn
,
map
[
string
]
string
{
"success"
:
msg
},
time
.
Second
)
}
...
...
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