Skip to content

Commit

Permalink
p2p: test scenarios support (#5962)
Browse files Browse the repository at this point in the history
  • Loading branch information
algorandskiy authored Jun 12, 2024
1 parent 8f9ad90 commit 052792d
Show file tree
Hide file tree
Showing 52 changed files with 1,828 additions and 258 deletions.
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ const (
dnssecSRV = 1 << iota
dnssecRelayAddr
dnssecTelemetryAddr
dnssecTXT
)

const (
Expand Down
12 changes: 9 additions & 3 deletions config/localTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,9 @@ type Local struct {
// 0x01 (dnssecSRV) - validate SRV response
// 0x02 (dnssecRelayAddr) - validate relays' names to addresses resolution
// 0x04 (dnssecTelemetryAddr) - validate telemetry and metrics names to addresses resolution
// 0x08 (dnssecTXT) - validate TXT response
// ...
DNSSecurityFlags uint32 `version[6]:"1"`
DNSSecurityFlags uint32 `version[6]:"1" version[34]:"9"`

// EnablePingHandler controls whether the gossip node would respond to ping messages with a pong message.
EnablePingHandler bool `version[6]:"true"`
Expand Down Expand Up @@ -688,11 +689,16 @@ func (cfg Local) DNSSecurityRelayAddrEnforced() bool {
return cfg.DNSSecurityFlags&dnssecRelayAddr != 0
}

// DNSSecurityTelemeryAddrEnforced returns true if relay name to ip addr resolution enforced
func (cfg Local) DNSSecurityTelemeryAddrEnforced() bool {
// DNSSecurityTelemetryAddrEnforced returns true if relay name to ip addr resolution enforced
func (cfg Local) DNSSecurityTelemetryAddrEnforced() bool {
return cfg.DNSSecurityFlags&dnssecTelemetryAddr != 0
}

// DNSSecurityTXTEnforced returns true if TXT response verification enforced
func (cfg Local) DNSSecurityTXTEnforced() bool {
return cfg.DNSSecurityFlags&dnssecTXT != 0
}

// CatchupVerifyCertificate returns true if certificate verification is needed
func (cfg Local) CatchupVerifyCertificate() bool {
return cfg.CatchupBlockValidateMode&catchupValidationModeCertificate == 0
Expand Down
2 changes: 1 addition & 1 deletion config/local_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var defaultLocal = Local{
ConnectionsRateLimitingWindowSeconds: 1,
CrashDBDir: "",
DNSBootstrapID: "<network>.algorand.network?backup=<network>.algorand.net&dedup=<name>.algorand-<network>.(network|net)",
DNSSecurityFlags: 1,
DNSSecurityFlags: 9,
DeadlockDetection: 0,
DeadlockDetectionThreshold: 30,
DisableAPIAuth: false,
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require (
github.com/google/go-querystring v1.0.0
github.com/gorilla/mux v1.8.0
github.com/ipfs/go-log v1.0.5
github.com/ipfs/go-log/v2 v2.5.1
github.com/jmoiron/sqlx v1.2.0
github.com/karalabe/usb v0.0.2
github.com/labstack/echo/v4 v4.9.1
Expand All @@ -47,6 +48,7 @@ require (
github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.4
go.opencensus.io v0.24.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0
Expand Down Expand Up @@ -101,7 +103,6 @@ require (
github.com/ipfs/boxo v0.10.0 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipld/go-ipld-prime v0.20.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
Expand Down Expand Up @@ -171,7 +172,6 @@ require (
go.uber.org/fx v1.20.1 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/term v0.18.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion installer/config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"ConnectionsRateLimitingWindowSeconds": 1,
"CrashDBDir": "",
"DNSBootstrapID": "<network>.algorand.network?backup=<network>.algorand.net&dedup=<name>.algorand-<network>.(network|net)",
"DNSSecurityFlags": 1,
"DNSSecurityFlags": 9,
"DeadlockDetection": 0,
"DeadlockDetectionThreshold": 30,
"DisableAPIAuth": false,
Expand Down
7 changes: 7 additions & 0 deletions logging/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ type Logger interface {
// source adds file, line and function fields to the event
source() *logrus.Entry

// Entry returns the logrus raw entry
Entry() *logrus.Entry

// Adds a hook to the logger
AddHook(hook logrus.Hook)

Expand Down Expand Up @@ -319,6 +322,10 @@ func (l logger) SetJSONFormatter() {
l.entry.Logger.Formatter = &logrus.JSONFormatter{TimestampFormat: "2006-01-02T15:04:05.000000Z07:00"}
}

func (l logger) Entry() *logrus.Entry {
return l.entry
}

func (l logger) source() *logrus.Entry {
event := l.entry

Expand Down
1 change: 1 addition & 0 deletions netdeploy/remote/nodeConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type NodeConfig struct {
DashboardEndpoint string `json:",omitempty"`
DeadlockOverride int `json:",omitempty"` // -1 = Disable deadlock detection, 0 = Use Default for build, 1 = Enable
ConfigJSONOverride string `json:",omitempty"` // Raw json to merge into config.json after other modifications are complete
P2PBootstrap bool // True if this node should be a p2p bootstrap node and registered in DNS

// NodeNameMatchRegex is tested against Name in generated configs and if matched the rest of the configs in this record are applied as a template
NodeNameMatchRegex string `json:",omitempty"`
Expand Down
35 changes: 35 additions & 0 deletions netdeploy/remote/nodecfg/nodeConfigurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,19 @@ type nodeConfigurator struct {
bootstrappedTrackerDir string
relayEndpoints []srvEntry
metricsEndpoints []srvEntry
p2pBootstrapEndpoints []txtEntry
}

type srvEntry struct {
srvName string
port string
}

type txtEntry struct {
netAddress string
peerID string
}

// ApplyConfigurationToHost attempts to apply the provided configuration to the local host,
// based on the configuration specified for the provided hostName, with node
// directories being created / updated under the specified rootNodeDir
Expand Down Expand Up @@ -248,6 +254,31 @@ func (nc *nodeConfigurator) registerDNSRecords() (err error) {
return
}
}

dnsaddrsFrom := fmt.Sprintf("_dnsaddr.%s.algodev.network", nc.genesisData.Network)
for _, entry := range nc.p2pBootstrapEndpoints {
port, parseErr := strconv.ParseInt(strings.Split(entry.netAddress, ":")[1], 10, 64)
if parseErr != nil {
return parseErr
}
var addrType string
if isIP {
addrType = "ip4"
} else {
addrType = "dnsaddr"
}
addrInfoString := fmt.Sprintf("/%s/%s/tcp/%d/p2p/%s", addrType, nc.dnsName, port, entry.peerID)
to := fmt.Sprintf("dnsaddr=%s", addrInfoString)

fmt.Fprintf(os.Stdout, "...... Adding P2P TXT Record '%s' -> '%s' .\n", dnsaddrsFrom, to)
const priority = 1
const proxied = false
dnsErr := cloudflareDNS.CreateDNSRecord(context.Background(), "TXT", dnsaddrsFrom, to, cloudflare.AutomaticTTL, priority, proxied)
if dnsErr != nil {
return dnsErr
}
}

return
}

Expand Down Expand Up @@ -281,3 +312,7 @@ func (nc *nodeConfigurator) addRelaySrv(srvRecord string, port string) {
func (nc *nodeConfigurator) registerMetricsSrv(srvRecord string, port string) {
nc.metricsEndpoints = append(nc.metricsEndpoints, srvEntry{srvRecord, port})
}

func (nc *nodeConfigurator) addP2PBootstrap(netAddress string, peerID string) {
nc.p2pBootstrapEndpoints = append(nc.p2pBootstrapEndpoints, txtEntry{netAddress, peerID})
}
47 changes: 47 additions & 0 deletions netdeploy/remote/nodecfg/nodeDir.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package nodecfg

import (
"encoding/json"
"errors"
"fmt"
"net/url"
"os"
Expand All @@ -27,6 +28,7 @@ import (
"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/logging"
"github.com/algorand/go-algorand/netdeploy/remote"
"github.com/algorand/go-algorand/network/p2p"
"github.com/algorand/go-algorand/shared/algoh"
"github.com/algorand/go-algorand/util/tokens"
)
Expand Down Expand Up @@ -101,6 +103,12 @@ func (nd *nodeDir) configure() (err error) {
fmt.Fprintf(os.Stdout, "Error during configureNetAddress: %s\n", err)
return
}

if err = nd.configureP2PDNSBootstrap(nd.P2PBootstrap); err != nil {
fmt.Fprintf(os.Stdout, "Error during configureP2PDNSBootstrap: %s\n", err)
return
}

fmt.Println("Done configuring node directory.")
return
}
Expand Down Expand Up @@ -156,6 +164,45 @@ func (nd *nodeDir) configureNetAddress() (err error) {
return
}

func (nd *nodeDir) configureP2PDNSBootstrap(p2pBootstrap bool) error {
if !p2pBootstrap {
return nil
}
fmt.Fprintf(os.Stdout, " - Configuring P2P DNS Bootstrap: %s\n", nd.Name)
if err := nd.ensureConfig(); err != nil {
return err
}
// ensure p2p config params set are what is expected:
// - EnableP2P or EnableP2PHybridMode
// - NetAddress or P2PListenAddress is set
// - EnableGossipService
if !nd.config.EnableP2P && !nd.config.EnableP2PHybridMode {
return errors.New("p2p bootstrap requires EnableP2P or EnableP2PHybridMode to be set")
}
if nd.NetAddress == "" && nd.config.P2PListenAddress == "" {
return errors.New("p2p bootstrap requires NetAddress or P2PListenAddress to be set")
}
if !nd.config.EnableGossipService {
return errors.New("p2p bootstrap requires EnableGossipService to be set")
}

netAddress := nd.NetAddress
if nd.config.P2PListenAddress != "" {
netAddress = nd.config.P2PListenAddress
}

key, err := p2p.GetPrivKey(config.Local{P2PPersistPeerID: true}, nd.dataDir)
if err != nil {
return err
}
peerID, err := p2p.PeerIDFromPublicKey(key.GetPublic())
if err != nil {
return err
}
nd.configurator.addP2PBootstrap(netAddress, peerID.String())
return nil
}

func (nd *nodeDir) configureAPIEndpoint(address string) (err error) {
if err = nd.ensureConfig(); err != nil {
return
Expand Down
2 changes: 2 additions & 0 deletions network/p2p/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"
"time"

"github.com/algorand/go-algorand/logging"
"github.com/algorand/go-algorand/network/limitcaller"
"github.com/gorilla/mux"
"github.com/libp2p/go-libp2p"
Expand Down Expand Up @@ -62,6 +63,7 @@ func MakeHTTPClient(addrInfo *peer.AddrInfo) (*http.Client, error) {
if err != nil {
return nil, err
}
logging.Base().Debugf("MakeHTTPClient made a new P2P host %s for %s", clientStreamHost.ID(), addrInfo.String())

client := libp2phttp.Host{StreamHost: clientStreamHost}

Expand Down
118 changes: 118 additions & 0 deletions network/p2p/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.

// This package implement a zap.Core in order to wrap lip2p logger into algod's logger.

package p2p

import (
"runtime"

p2plogging "github.com/ipfs/go-log/v2"
"github.com/sirupsen/logrus"
"go.uber.org/zap/zapcore"

"github.com/algorand/go-algorand/logging"
)

// var levelsMap = map[logging.Level]zapcore.Level{
// logging.Debug: zapcore.DebugLevel,
// logging.Info: zapcore.InfoLevel,
// logging.Warn: zapcore.WarnLevel,
// logging.Error: zapcore.ErrorLevel,
// logging.Fatal: zapcore.FatalLevel,
// logging.Panic: zapcore.PanicLevel,
// }

var levelsMap = map[zapcore.Level]logging.Level{
zapcore.DebugLevel: logging.Debug,
zapcore.InfoLevel: logging.Info,
zapcore.WarnLevel: logging.Warn,
zapcore.ErrorLevel: logging.Error,
zapcore.FatalLevel: logging.Fatal,
zapcore.PanicLevel: logging.Panic,
}

// loggingCore implements zapcore.Core
type loggingCore struct {
log logging.Logger
level logging.Level
fields []zapcore.Field
zapcore.Core
}

// EnableP2PLogging enables libp2p logging into the provided logger with the provided level.
func EnableP2PLogging(log logging.Logger, l logging.Level) {
core := loggingCore{
log: log,
level: l,
}
for p2pLevel, logLevel := range levelsMap {
if logLevel == l {
p2plogging.SetAllLoggers(p2plogging.LogLevel(p2pLevel))
break
}
}
p2plogging.SetPrimaryCore(&core)
}

func (c *loggingCore) Enabled(l zapcore.Level) bool {
return c.log.IsLevelEnabled(c.level)
}

func (c *loggingCore) With(fields []zapcore.Field) zapcore.Core {
return &loggingCore{
log: c.log,
level: c.level,
fields: append(c.fields, fields...),
}
}

func (c *loggingCore) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
if c.Enabled(e.Level) {
return ce.AddCore(e, c)
}
return ce
}

func (c *loggingCore) Write(e zapcore.Entry, fields []zapcore.Field) error {
allFields := append(c.fields, fields...)
loggingFields := make(logging.Fields, len(allFields))

for _, f := range allFields {
if len(f.String) > 0 {
loggingFields[f.Key] = f.String
} else if f.Interface != nil {
loggingFields[f.Key] = f.Interface
} else {
loggingFields[f.Key] = f.Integer
}
}
event := c.log.WithFields(loggingFields).With("libp2p", e.LoggerName)
event = event.WithFields(logrus.Fields{
"file": e.Caller.File,
"line": e.Caller.Line,
})
if function := runtime.FuncForPC(e.Caller.PC); function != nil {
event = event.With("function", function.Name())
}
event.Entry().Log(logrus.Level(levelsMap[e.Level]), e.Message)
return nil
}

func (c *loggingCore) Sync() error {
return nil
}
Loading

0 comments on commit 052792d

Please sign in to comment.