dashboard: send current block to the dashboard client (#19762)

This adds all dashboard changes from the last couple months.
We're about to remove the dashboard, but decided that we should
get all the recent work in first in case anyone wants to pick up this
project later on.

* cmd, dashboard, eth, p2p: send peer info to the dashboard
* dashboard: update npm packages, improve UI, rebase
* dashboard, p2p: remove println, change doc
* cmd, dashboard, eth, p2p: cleanup after review
* dashboard: send current block to the dashboard client
This commit is contained in:
Kurkó Mihály
2019-11-13 13:13:13 +02:00
committed by Felix Lange
parent 6f1a600f6c
commit 4ea9b62b5c
20 changed files with 11929 additions and 10886 deletions

View File

@@ -304,7 +304,7 @@ func (t *dialTask) dial(srv *Server, dest *enode.Node) error {
if err != nil {
return &dialError{err}
}
mfd := newMeteredConn(fd, false, dest.IP())
mfd := newMeteredConn(fd, false, &net.TCPAddr{IP: dest.IP(), Port: dest.TCP()})
return srv.SetupConn(mfd, t.flags, dest)
}

View File

@@ -19,7 +19,6 @@
package p2p
import (
"fmt"
"net"
"sync"
"sync/atomic"
@@ -28,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p/enode"
)
const (
@@ -58,24 +56,24 @@ var (
type MeteredPeerEventType int
const (
// PeerConnected is the type of event emitted when a peer successfully
// made the handshake.
PeerConnected MeteredPeerEventType = iota
// PeerHandshakeSucceeded is the type of event
// emitted when a peer successfully makes the handshake.
PeerHandshakeSucceeded MeteredPeerEventType = iota
// PeerHandshakeFailed is the type of event emitted when a peer fails to
// make the handshake or disconnects before it.
PeerHandshakeFailed
// PeerDisconnected is the type of event emitted when a peer disconnects.
PeerDisconnected
// PeerHandshakeFailed is the type of event emitted when a peer fails to
// make the handshake or disconnects before the handshake.
PeerHandshakeFailed
)
// MeteredPeerEvent is an event emitted when peers connect or disconnect.
type MeteredPeerEvent struct {
Type MeteredPeerEventType // Type of peer event
IP net.IP // IP address of the peer
ID enode.ID // NodeID of the peer
Addr string // TCP address of the peer
Elapsed time.Duration // Time elapsed between the connection and the handshake/disconnection
Peer *Peer // Connected remote node instance
Ingress uint64 // Ingress count at the moment of the event
Egress uint64 // Egress count at the moment of the event
}
@@ -91,9 +89,9 @@ func SubscribeMeteredPeerEvent(ch chan<- MeteredPeerEvent) event.Subscription {
type meteredConn struct {
net.Conn // Network connection to wrap with metering
connected time.Time // Connection time of the peer
ip net.IP // IP address of the peer
id enode.ID // NodeID of the peer
connected time.Time // Connection time of the peer
addr *net.TCPAddr // TCP address of the peer
peer *Peer // Peer instance
// trafficMetered denotes if the peer is registered in the traffic registries.
// Its value is true if the metered peer count doesn't reach the limit in the
@@ -109,13 +107,13 @@ type meteredConn struct {
// connection meter and also increases the metered peer count. If the metrics
// system is disabled or the IP address is unspecified, this function returns
// the original object.
func newMeteredConn(conn net.Conn, ingress bool, ip net.IP) net.Conn {
func newMeteredConn(conn net.Conn, ingress bool, addr *net.TCPAddr) net.Conn {
// Short circuit if metrics are disabled
if !metrics.Enabled {
return conn
}
if ip.IsUnspecified() {
log.Warn("Peer IP is unspecified")
if addr == nil || addr.IP.IsUnspecified() {
log.Warn("Peer address is unspecified")
return conn
}
// Bump the connection counters and wrap the connection
@@ -128,7 +126,7 @@ func newMeteredConn(conn net.Conn, ingress bool, ip net.IP) net.Conn {
return &meteredConn{
Conn: conn,
ip: ip,
addr: addr,
connected: time.Now(),
}
}
@@ -159,30 +157,27 @@ func (c *meteredConn) Write(b []byte) (n int, err error) {
return n, err
}
// handshakeDone is called when a peer handshake is done. Registers the peer to
// the ingress and the egress traffic registries using the peer's IP and node ID,
// also emits connect event.
func (c *meteredConn) handshakeDone(id enode.ID) {
// TODO (kurkomisi): use the node URL instead of the pure node ID. (the String() method of *Node)
// handshakeDone is called after the connection passes the handshake.
func (c *meteredConn) handshakeDone(peer *Peer) {
if atomic.AddInt32(&meteredPeerCount, 1) >= MeteredPeerLimit {
// Don't register the peer in the traffic registries.
atomic.AddInt32(&meteredPeerCount, -1)
c.lock.Lock()
c.id, c.trafficMetered = id, false
c.peer, c.trafficMetered = peer, false
c.lock.Unlock()
log.Warn("Metered peer count reached the limit")
} else {
key := fmt.Sprintf("%s/%s", c.ip, id.String())
enode := peer.Node().String()
c.lock.Lock()
c.id, c.trafficMetered = id, true
c.ingressMeter = metrics.NewRegisteredMeter(key, PeerIngressRegistry)
c.egressMeter = metrics.NewRegisteredMeter(key, PeerEgressRegistry)
c.peer, c.trafficMetered = peer, true
c.ingressMeter = metrics.NewRegisteredMeter(enode, PeerIngressRegistry)
c.egressMeter = metrics.NewRegisteredMeter(enode, PeerEgressRegistry)
c.lock.Unlock()
}
meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerConnected,
IP: c.ip,
ID: id,
Type: PeerHandshakeSucceeded,
Addr: c.addr.String(),
Peer: peer,
Elapsed: time.Since(c.connected),
})
}
@@ -192,44 +187,43 @@ func (c *meteredConn) handshakeDone(id enode.ID) {
func (c *meteredConn) Close() error {
err := c.Conn.Close()
c.lock.RLock()
if c.id == (enode.ID{}) {
// If the peer disconnects before the handshake.
if c.peer == nil {
// If the peer disconnects before/during the handshake.
c.lock.RUnlock()
meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerHandshakeFailed,
IP: c.ip,
Addr: c.addr.String(),
Elapsed: time.Since(c.connected),
})
activePeerGauge.Dec(1)
return err
}
id := c.id
peer := c.peer
if !c.trafficMetered {
// If the peer isn't registered in the traffic registries.
c.lock.RUnlock()
meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerDisconnected,
IP: c.ip,
ID: id,
Addr: c.addr.String(),
Peer: peer,
})
activePeerGauge.Dec(1)
return err
}
ingress, egress := uint64(c.ingressMeter.Count()), uint64(c.egressMeter.Count())
ingress, egress, enode := uint64(c.ingressMeter.Count()), uint64(c.egressMeter.Count()), c.peer.Node().String()
c.lock.RUnlock()
// Decrement the metered peer count
atomic.AddInt32(&meteredPeerCount, -1)
// Unregister the peer from the traffic registries
key := fmt.Sprintf("%s/%s", c.ip, id)
PeerIngressRegistry.Unregister(key)
PeerEgressRegistry.Unregister(key)
PeerIngressRegistry.Unregister(enode)
PeerEgressRegistry.Unregister(enode)
meteredPeerFeed.Send(MeteredPeerEvent{
Type: PeerDisconnected,
IP: c.ip,
ID: id,
Addr: c.addr.String(),
Peer: peer,
Ingress: ingress,
Egress: egress,
})

View File

@@ -779,6 +779,9 @@ running:
if p.Inbound() {
inboundCount++
}
if conn, ok := c.fd.(*meteredConn); ok {
conn.handshakeDone(p)
}
}
// The dialer logic relies on the assumption that
// dial tasks complete after the peer has been added or
@@ -902,9 +905,13 @@ func (srv *Server) listenLoop() {
continue
}
if remoteIP != nil {
fd = newMeteredConn(fd, true, remoteIP)
var addr *net.TCPAddr
if tcp, ok := fd.RemoteAddr().(*net.TCPAddr); ok {
addr = tcp
}
fd = newMeteredConn(fd, true, addr)
srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr())
}
srv.log.Trace("Accepted connection", "addr", fd.RemoteAddr())
go func() {
srv.SetupConn(fd, inboundConn, nil)
slots <- struct{}{}
@@ -974,9 +981,6 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *enode.Node) erro
} else {
c.node = nodeFromConn(remotePubkey, c.fd)
}
if conn, ok := c.fd.(*meteredConn); ok {
conn.handshakeDone(c.node.ID())
}
clog := srv.log.New("id", c.node.ID(), "addr", c.fd.RemoteAddr(), "conn", c.flags)
err = srv.checkpoint(c, srv.checkpointPostHandshake)
if err != nil {