Skip to content

Commit

Permalink
Merge branch 'dev' into version-bump-v1.10.9
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored Aug 24, 2023
2 parents 861d08d + 4db53b1 commit f5d40d1
Show file tree
Hide file tree
Showing 31 changed files with 325 additions and 140 deletions.
16 changes: 11 additions & 5 deletions chains/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/ava-labs/avalanchego/snow/networking/sender"
"github.com/ava-labs/avalanchego/snow/networking/timeout"
"github.com/ava-labs/avalanchego/snow/validators"
"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/subnets"
"github.com/ava-labs/avalanchego/trace"
"github.com/ava-labs/avalanchego/utils/buffer"
Expand Down Expand Up @@ -168,7 +169,7 @@ type ChainConfig struct {

type ManagerConfig struct {
SybilProtectionEnabled bool
StakingCert tls.Certificate // needed to sign snowman++ blocks
StakingTLSCert tls.Certificate // needed to sign snowman++ blocks
StakingBLSKey *bls.SecretKey
TracingEnabled bool
// Must not be used unless [TracingEnabled] is true as this may be nil.
Expand Down Expand Up @@ -234,6 +235,9 @@ type manager struct {
ids.Aliaser
ManagerConfig

stakingSigner crypto.Signer
stakingCert *staking.Certificate

// Those notified when a chain is created
registrants []Registrant

Expand Down Expand Up @@ -262,6 +266,8 @@ func New(config *ManagerConfig) Manager {
return &manager{
Aliaser: ids.NewAliaser(),
ManagerConfig: *config,
stakingSigner: config.StakingTLSCert.PrivateKey.(crypto.Signer),
stakingCert: staking.CertificateFromX509(config.StakingTLSCert.Leaf),
subnets: make(map[ids.ID]subnets.Subnet),
chains: make(map[ids.ID]handler.Handler),
chainsQueue: buffer.NewUnboundedBlockingDeque[ChainParameters](initialQueueSize),
Expand Down Expand Up @@ -772,8 +778,8 @@ func (m *manager) createAvalancheChain(
m.ApricotPhase4Time,
m.ApricotPhase4MinPChainHeight,
minBlockDelay,
m.StakingCert.PrivateKey.(crypto.Signer),
m.StakingCert.Leaf,
m.stakingSigner,
m.stakingCert,
)

if m.MeterVMEnabled {
Expand Down Expand Up @@ -1114,8 +1120,8 @@ func (m *manager) createSnowmanChain(
m.ApricotPhase4Time,
m.ApricotPhase4MinPChainHeight,
minBlockDelay,
m.StakingCert.PrivateKey.(crypto.Signer),
m.StakingCert.Leaf,
m.stakingSigner,
m.stakingCert,
)

if m.MeterVMEnabled {
Expand Down
4 changes: 2 additions & 2 deletions ids/node_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ package ids

import (
"bytes"
"crypto/x509"
"errors"
"fmt"

"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/utils/hashing"
)
Expand Down Expand Up @@ -76,7 +76,7 @@ func ToNodeID(bytes []byte) (NodeID, error) {
return NodeID(nodeID), err
}

func NodeIDFromCert(cert *x509.Certificate) NodeID {
func NodeIDFromCert(cert *staking.Certificate) NodeID {
return hashing.ComputeHash160Array(
hashing.ComputeHash256(cert.Raw),
)
Expand Down
6 changes: 4 additions & 2 deletions network/certs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func getTLS(t *testing.T, index int) (ids.NodeID, *tls.Certificate, *tls.Config)
tlsConfigs = append(tlsConfigs, tlsConfig)
}

cert := tlsCerts[index]
return ids.NodeIDFromCert(cert.Leaf), cert, tlsConfigs[index]
tlsCert := tlsCerts[index]
cert := staking.CertificateFromX509(tlsCert.Leaf)
nodeID := ids.NodeIDFromCert(cert)
return nodeID, tlsCert, tlsConfigs[index]
}
7 changes: 7 additions & 0 deletions network/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type metrics struct {
acceptFailed prometheus.Counter
inboundConnRateLimited prometheus.Counter
inboundConnAllowed prometheus.Counter
tlsConnRejected prometheus.Counter
numUselessPeerListBytes prometheus.Counter
nodeUptimeWeightedAverage prometheus.Gauge
nodeUptimeRewardingStake prometheus.Gauge
Expand Down Expand Up @@ -95,6 +96,11 @@ func newMetrics(namespace string, registerer prometheus.Registerer, initialSubne
Name: "inbound_conn_throttler_allowed",
Help: "Times this node allowed (attempted to upgrade) an inbound connection",
}),
tlsConnRejected: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "tls_conn_rejected",
Help: "Times this node rejected a connection due to an unsupported TLS certificate",
}),
numUselessPeerListBytes: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "num_useless_peerlist_bytes",
Expand Down Expand Up @@ -153,6 +159,7 @@ func newMetrics(namespace string, registerer prometheus.Registerer, initialSubne
registerer.Register(m.disconnected),
registerer.Register(m.acceptFailed),
registerer.Register(m.inboundConnAllowed),
registerer.Register(m.tlsConnRejected),
registerer.Register(m.numUselessPeerListBytes),
registerer.Register(m.inboundConnRateLimited),
registerer.Register(m.nodeUptimeWeightedAverage),
Expand Down
4 changes: 2 additions & 2 deletions network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ func NewNetwork(
inboundConnUpgradeThrottler: throttling.NewInboundConnUpgradeThrottler(log, config.ThrottlerConfig.InboundConnUpgradeThrottlerConfig),
listener: listener,
dialer: dialer,
serverUpgrader: peer.NewTLSServerUpgrader(config.TLSConfig),
clientUpgrader: peer.NewTLSClientUpgrader(config.TLSConfig),
serverUpgrader: peer.NewTLSServerUpgrader(config.TLSConfig, metrics.tlsConnRejected),
clientUpgrader: peer.NewTLSClientUpgrader(config.TLSConfig, metrics.tlsConnRejected),

onCloseCtx: onCloseCtx,
onCloseCtxCancel: cancel,
Expand Down
5 changes: 3 additions & 2 deletions network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/ava-labs/avalanchego/snow/networking/tracker"
"github.com/ava-labs/avalanchego/snow/uptime"
"github.com/ava-labs/avalanchego/snow/validators"
"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/subnets"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/ips"
Expand Down Expand Up @@ -407,7 +408,7 @@ func TestTrackVerifiesSignatures(t *testing.T) {
require.NoError(validators.Add(network.config.Validators, constants.PrimaryNetworkID, nodeID, nil, ids.Empty, 1))

_, err := network.Track(ids.EmptyNodeID, []*ips.ClaimedIPPort{{
Cert: tlsCert.Leaf,
Cert: staking.CertificateFromX509(tlsCert.Leaf),
IPPort: ips.IPPort{
IP: net.IPv4(123, 132, 123, 123),
Port: 10000,
Expand Down Expand Up @@ -589,7 +590,7 @@ func TestDialDeletesNonValidators(t *testing.T) {
for i, net := range networks {
if i != 0 {
peerAcks, err := net.Track(config.MyNodeID, []*ips.ClaimedIPPort{{
Cert: config.TLSConfig.Certificates[0].Leaf,
Cert: staking.CertificateFromX509(config.TLSConfig.Certificates[0].Leaf),
IPPort: ip.IPPort,
Timestamp: ip.Timestamp,
Signature: ip.Signature,
Expand Down
3 changes: 1 addition & 2 deletions network/peer/ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package peer
import (
"crypto"
"crypto/rand"
"crypto/x509"

"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/utils/hashing"
Expand Down Expand Up @@ -50,7 +49,7 @@ type SignedIP struct {
Signature []byte
}

func (ip *SignedIP) Verify(cert *x509.Certificate) error {
func (ip *SignedIP) Verify(cert *staking.Certificate) error {
return staking.CheckSignature(
cert,
ip.UnsignedIP.bytes(),
Expand Down
12 changes: 6 additions & 6 deletions network/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package peer
import (
"bufio"
"context"
"crypto/x509"
"errors"
"io"
"math"
Expand All @@ -20,6 +19,7 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/message"
"github.com/ava-labs/avalanchego/proto/pb/p2p"
"github.com/ava-labs/avalanchego/staking"
"github.com/ava-labs/avalanchego/utils"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/ips"
Expand All @@ -43,7 +43,7 @@ type Peer interface {

// Cert returns the certificate that the remote peer is using to
// authenticate their messages.
Cert() *x509.Certificate
Cert() *staking.Certificate

// LastSent returns the last time a message was sent to the peer.
LastSent() time.Time
Expand Down Expand Up @@ -112,7 +112,7 @@ type peer struct {

// [cert] is this peer's certificate, specifically the leaf of the
// certificate chain they provided.
cert *x509.Certificate
cert *staking.Certificate

// node ID of this peer.
id ids.NodeID
Expand Down Expand Up @@ -176,7 +176,7 @@ type peer struct {
func Start(
config *Config,
conn net.Conn,
cert *x509.Certificate,
cert *staking.Certificate,
id ids.NodeID,
messageQueue MessageQueue,
) Peer {
Expand Down Expand Up @@ -207,7 +207,7 @@ func (p *peer) ID() ids.NodeID {
return p.id
}

func (p *peer) Cert() *x509.Certificate {
func (p *peer) Cert() *staking.Certificate {
return p.cert
}

Expand Down Expand Up @@ -1009,7 +1009,7 @@ func (p *peer) handlePeerList(msg *p2p.PeerList) {
// the peers this peer told us about
discoveredIPs := make([]*ips.ClaimedIPPort, len(msg.ClaimedIpPorts))
for i, claimedIPPort := range msg.ClaimedIpPorts {
tlsCert, err := x509.ParseCertificate(claimedIPPort.X509Certificate)
tlsCert, err := staking.ParseCertificate(claimedIPPort.X509Certificate)
if err != nil {
p.Log.Debug("message with invalid field",
zap.Stringer("nodeID", p.id),
Expand Down
13 changes: 7 additions & 6 deletions network/peer/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package peer
import (
"context"
"crypto"
"crypto/x509"
"net"
"testing"
"time"
Expand Down Expand Up @@ -41,7 +40,7 @@ type testPeer struct {
type rawTestPeer struct {
config *Config
conn net.Conn
cert *x509.Certificate
cert *staking.Certificate
nodeID ids.NodeID
inboundMsgChan <-chan message.InboundMessage
}
Expand Down Expand Up @@ -69,12 +68,14 @@ func makeRawTestPeers(t *testing.T, trackedSubnets set.Set[ids.ID]) (*rawTestPee

tlsCert0, err := staking.NewTLSCert()
require.NoError(err)
cert0 := staking.CertificateFromX509(tlsCert0.Leaf)

tlsCert1, err := staking.NewTLSCert()
require.NoError(err)
cert1 := staking.CertificateFromX509(tlsCert1.Leaf)

nodeID0 := ids.NodeIDFromCert(tlsCert0.Leaf)
nodeID1 := ids.NodeIDFromCert(tlsCert1.Leaf)
nodeID0 := ids.NodeIDFromCert(cert0)
nodeID1 := ids.NodeIDFromCert(cert1)

mc := newMessageCreator(t)

Expand Down Expand Up @@ -134,14 +135,14 @@ func makeRawTestPeers(t *testing.T, trackedSubnets set.Set[ids.ID]) (*rawTestPee
peer0 := &rawTestPeer{
config: &peerConfig0,
conn: conn0,
cert: tlsCert0.Leaf,
cert: cert0,
nodeID: nodeID0,
inboundMsgChan: inboundMsgChan0,
}
peer1 := &rawTestPeer{
config: &peerConfig1,
conn: conn1,
cert: tlsCert1.Leaf,
cert: cert1,
nodeID: nodeID1,
inboundMsgChan: inboundMsgChan1,
}
Expand Down
5 changes: 4 additions & 1 deletion network/peer/test_peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ func StartTestPeer(
}

tlsConfg := TLSConfig(*tlsCert, nil)
clientUpgrader := NewTLSClientUpgrader(tlsConfg)
clientUpgrader := NewTLSClientUpgrader(
tlsConfg,
prometheus.NewCounter(prometheus.CounterOpts{}),
)

peerID, conn, cert, err := clientUpgrader.Upgrade(conn)
if err != nil {
Expand Down
60 changes: 43 additions & 17 deletions network/peer/upgrader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ package peer

import (
"crypto/tls"
"crypto/x509"
"errors"
"net"

"github.com/prometheus/client_golang/prometheus"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/staking"
)

var (
Expand All @@ -21,38 +23,42 @@ var (

type Upgrader interface {
// Must be thread safe
Upgrade(net.Conn) (ids.NodeID, net.Conn, *x509.Certificate, error)
Upgrade(net.Conn) (ids.NodeID, net.Conn, *staking.Certificate, error)
}

type tlsServerUpgrader struct {
config *tls.Config
config *tls.Config
invalidCerts prometheus.Counter
}

func NewTLSServerUpgrader(config *tls.Config) Upgrader {
return tlsServerUpgrader{
config: config,
func NewTLSServerUpgrader(config *tls.Config, invalidCerts prometheus.Counter) Upgrader {
return &tlsServerUpgrader{
config: config,
invalidCerts: invalidCerts,
}
}

func (t tlsServerUpgrader) Upgrade(conn net.Conn) (ids.NodeID, net.Conn, *x509.Certificate, error) {
return connToIDAndCert(tls.Server(conn, t.config))
func (t *tlsServerUpgrader) Upgrade(conn net.Conn) (ids.NodeID, net.Conn, *staking.Certificate, error) {
return connToIDAndCert(tls.Server(conn, t.config), t.invalidCerts)
}

type tlsClientUpgrader struct {
config *tls.Config
config *tls.Config
invalidCerts prometheus.Counter
}

func NewTLSClientUpgrader(config *tls.Config) Upgrader {
return tlsClientUpgrader{
config: config,
func NewTLSClientUpgrader(config *tls.Config, invalidCerts prometheus.Counter) Upgrader {
return &tlsClientUpgrader{
config: config,
invalidCerts: invalidCerts,
}
}

func (t tlsClientUpgrader) Upgrade(conn net.Conn) (ids.NodeID, net.Conn, *x509.Certificate, error) {
return connToIDAndCert(tls.Client(conn, t.config))
func (t *tlsClientUpgrader) Upgrade(conn net.Conn) (ids.NodeID, net.Conn, *staking.Certificate, error) {
return connToIDAndCert(tls.Client(conn, t.config), t.invalidCerts)
}

func connToIDAndCert(conn *tls.Conn) (ids.NodeID, net.Conn, *x509.Certificate, error) {
func connToIDAndCert(conn *tls.Conn, invalidCerts prometheus.Counter) (ids.NodeID, net.Conn, *staking.Certificate, error) {
if err := conn.Handshake(); err != nil {
return ids.NodeID{}, nil, nil, err
}
Expand All @@ -61,6 +67,26 @@ func connToIDAndCert(conn *tls.Conn) (ids.NodeID, net.Conn, *x509.Certificate, e
if len(state.PeerCertificates) == 0 {
return ids.NodeID{}, nil, nil, errNoCert
}
peerCert := state.PeerCertificates[0]
return ids.NodeIDFromCert(peerCert), conn, peerCert, nil

tlsCert := state.PeerCertificates[0]
// Invariant: ParseCertificate is used rather than CertificateFromX509 to
// ensure that signature verification can assume the certificate was
// parseable according the staking package's parser.
peerCert, err := staking.ParseCertificate(tlsCert.Raw)
if err != nil {
invalidCerts.Inc()
return ids.NodeID{}, nil, nil, err
}

// We validate the certificate here to attempt to make the validity of the
// peer certificate as clear as possible. Specifically, a node running a
// prior version using an invalid certificate should not be able to report
// healthy.
if err := staking.ValidateCertificate(peerCert); err != nil {
invalidCerts.Inc()
return ids.NodeID{}, nil, nil, err
}

nodeID := ids.NodeIDFromCert(peerCert)
return nodeID, conn, peerCert, nil
}
Loading

0 comments on commit f5d40d1

Please sign in to comment.