mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-15 04:35:17 +00:00
359 lines
12 KiB
Go
359 lines
12 KiB
Go
|
package dht
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
dhtcfg "github.com/libp2p/go-libp2p-kad-dht/internal/config"
|
||
|
"github.com/libp2p/go-libp2p-kad-dht/providers"
|
||
|
"github.com/libp2p/go-libp2p-kbucket/peerdiversity"
|
||
|
record "github.com/libp2p/go-libp2p-record"
|
||
|
"github.com/libp2p/go-libp2p/core/peer"
|
||
|
"github.com/libp2p/go-libp2p/core/protocol"
|
||
|
|
||
|
ds "github.com/ipfs/go-datastore"
|
||
|
ma "github.com/multiformats/go-multiaddr"
|
||
|
)
|
||
|
|
||
|
// ModeOpt describes what mode the dht should operate in
|
||
|
type ModeOpt = dhtcfg.ModeOpt
|
||
|
|
||
|
const (
|
||
|
// ModeAuto utilizes EvtLocalReachabilityChanged events sent over the event bus to dynamically switch the DHT
|
||
|
// between Client and Server modes based on network conditions
|
||
|
ModeAuto ModeOpt = iota
|
||
|
// ModeClient operates the DHT as a client only, it cannot respond to incoming queries
|
||
|
ModeClient
|
||
|
// ModeServer operates the DHT as a server, it can both send and respond to queries
|
||
|
ModeServer
|
||
|
// ModeAutoServer operates in the same way as ModeAuto, but acts as a server when reachability is unknown
|
||
|
ModeAutoServer
|
||
|
)
|
||
|
|
||
|
// DefaultPrefix is the application specific prefix attached to all DHT protocols by default.
|
||
|
const DefaultPrefix protocol.ID = "/ipfs"
|
||
|
|
||
|
type Option = dhtcfg.Option
|
||
|
|
||
|
// ProviderStore sets the provider storage manager.
|
||
|
func ProviderStore(ps providers.ProviderStore) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.ProviderStore = ps
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RoutingTableLatencyTolerance sets the maximum acceptable latency for peers
|
||
|
// in the routing table's cluster.
|
||
|
func RoutingTableLatencyTolerance(latency time.Duration) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.LatencyTolerance = latency
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RoutingTableRefreshQueryTimeout sets the timeout for routing table refresh
|
||
|
// queries.
|
||
|
func RoutingTableRefreshQueryTimeout(timeout time.Duration) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.RefreshQueryTimeout = timeout
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RoutingTableRefreshPeriod sets the period for refreshing buckets in the
|
||
|
// routing table. The DHT will refresh buckets every period by:
|
||
|
//
|
||
|
// 1. First searching for nearby peers to figure out how many buckets we should try to fill.
|
||
|
// 1. Then searching for a random key in each bucket that hasn't been queried in
|
||
|
// the last refresh period.
|
||
|
func RoutingTableRefreshPeriod(period time.Duration) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.RefreshInterval = period
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Datastore configures the DHT to use the specified datastore.
|
||
|
//
|
||
|
// Defaults to an in-memory (temporary) map.
|
||
|
func Datastore(ds ds.Batching) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.Datastore = ds
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Mode configures which mode the DHT operates in (Client, Server, Auto).
|
||
|
//
|
||
|
// Defaults to ModeAuto.
|
||
|
func Mode(m ModeOpt) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.Mode = m
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Validator configures the DHT to use the specified validator.
|
||
|
//
|
||
|
// Defaults to a namespaced validator that can validate both public key (under the "pk"
|
||
|
// namespace) and IPNS records (under the "ipns" namespace). Setting the validator
|
||
|
// implies that the user wants to control the validators and therefore the default
|
||
|
// public key and IPNS validators will not be added.
|
||
|
func Validator(v record.Validator) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.Validator = v
|
||
|
c.ValidatorChanged = true
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NamespacedValidator adds a validator namespaced under `ns`. This option fails
|
||
|
// if the DHT is not using a `record.NamespacedValidator` as its validator (it
|
||
|
// uses one by default but this can be overridden with the `Validator` option).
|
||
|
// Adding a namespaced validator without changing the `Validator` will result in
|
||
|
// adding a new validator in addition to the default public key and IPNS validators.
|
||
|
// The "pk" and "ipns" namespaces cannot be overridden here unless a new `Validator`
|
||
|
// has been set first.
|
||
|
//
|
||
|
// Example: Given a validator registered as `NamespacedValidator("ipns",
|
||
|
// myValidator)`, all records with keys starting with `/ipns/` will be validated
|
||
|
// with `myValidator`.
|
||
|
func NamespacedValidator(ns string, v record.Validator) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
nsval, ok := c.Validator.(record.NamespacedValidator)
|
||
|
if !ok {
|
||
|
return fmt.Errorf("can only add namespaced validators to a NamespacedValidator")
|
||
|
}
|
||
|
nsval[ns] = v
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ProtocolPrefix sets an application specific prefix to be attached to all DHT protocols. For example,
|
||
|
// /myapp/kad/1.0.0 instead of /ipfs/kad/1.0.0. Prefix should be of the form /myapp.
|
||
|
//
|
||
|
// Defaults to dht.DefaultPrefix
|
||
|
func ProtocolPrefix(prefix protocol.ID) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.ProtocolPrefix = prefix
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ProtocolExtension adds an application specific protocol to the DHT protocol. For example,
|
||
|
// /ipfs/lan/kad/1.0.0 instead of /ipfs/kad/1.0.0. extension should be of the form /lan.
|
||
|
func ProtocolExtension(ext protocol.ID) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.ProtocolPrefix += ext
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// V1ProtocolOverride overrides the protocolID used for /kad/1.0.0 with another. This is an
|
||
|
// advanced feature, and should only be used to handle legacy networks that have not been
|
||
|
// using protocolIDs of the form /app/kad/1.0.0.
|
||
|
//
|
||
|
// This option will override and ignore the ProtocolPrefix and ProtocolExtension options
|
||
|
func V1ProtocolOverride(proto protocol.ID) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.V1ProtocolOverride = proto
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// BucketSize configures the bucket size (k in the Kademlia paper) of the routing table.
|
||
|
//
|
||
|
// The default value is 20.
|
||
|
func BucketSize(bucketSize int) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.BucketSize = bucketSize
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Concurrency configures the number of concurrent requests (alpha in the Kademlia paper) for a given query path.
|
||
|
//
|
||
|
// The default value is 10.
|
||
|
func Concurrency(alpha int) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.Concurrency = alpha
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Resiliency configures the number of peers closest to a target that must have responded in order for a given query
|
||
|
// path to complete.
|
||
|
//
|
||
|
// The default value is 3.
|
||
|
func Resiliency(beta int) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.Resiliency = beta
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// LookupInterval configures maximal number of go routines that can be used to
|
||
|
// perform a lookup check operation, before adding a new node to the routing table.
|
||
|
func LookupCheckConcurrency(n int) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.LookupCheckConcurrency = n
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MaxRecordAge specifies the maximum time that any node will hold onto a record ("PutValue record")
|
||
|
// from the time its received. This does not apply to any other forms of validity that
|
||
|
// the record may contain.
|
||
|
// For example, a record may contain an ipns entry with an EOL saying its valid
|
||
|
// until the year 2020 (a great time in the future). For that record to stick around
|
||
|
// it must be rebroadcasted more frequently than once every 'MaxRecordAge'
|
||
|
func MaxRecordAge(maxAge time.Duration) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.MaxRecordAge = maxAge
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DisableAutoRefresh completely disables 'auto-refresh' on the DHT routing
|
||
|
// table. This means that we will neither refresh the routing table periodically
|
||
|
// nor when the routing table size goes below the minimum threshold.
|
||
|
func DisableAutoRefresh() Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.AutoRefresh = false
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DisableProviders disables storing and retrieving provider records.
|
||
|
//
|
||
|
// Defaults to enabled.
|
||
|
//
|
||
|
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
|
||
|
// network and/or distinct DHT protocols with the `Protocols` option).
|
||
|
func DisableProviders() Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.EnableProviders = false
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DisableValues disables storing and retrieving value records (including
|
||
|
// public keys).
|
||
|
//
|
||
|
// Defaults to enabled.
|
||
|
//
|
||
|
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
|
||
|
// network and/or distinct DHT protocols with the `Protocols` option).
|
||
|
func DisableValues() Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.EnableValues = false
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// QueryFilter sets a function that approves which peers may be dialed in a query
|
||
|
func QueryFilter(filter QueryFilterFunc) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.QueryPeerFilter = filter
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RoutingTableFilter sets a function that approves which peers may be added to the routing table. The host should
|
||
|
// already have at least one connection to the peer under consideration.
|
||
|
func RoutingTableFilter(filter RouteTableFilterFunc) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.PeerFilter = filter
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// BootstrapPeers configures the bootstrapping nodes that we will connect to to seed
|
||
|
// and refresh our Routing Table if it becomes empty.
|
||
|
func BootstrapPeers(bootstrappers ...peer.AddrInfo) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.BootstrapPeers = func() []peer.AddrInfo {
|
||
|
return bootstrappers
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// BootstrapPeersFunc configures the function that returns the bootstrapping nodes that we will
|
||
|
// connect to to seed and refresh our Routing Table if it becomes empty.
|
||
|
func BootstrapPeersFunc(getBootstrapPeers func() []peer.AddrInfo) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.BootstrapPeers = getBootstrapPeers
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RoutingTablePeerDiversityFilter configures the implementation of the `PeerIPGroupFilter` that will be used
|
||
|
// to construct the diversity filter for the Routing Table.
|
||
|
// Please see the docs for `peerdiversity.PeerIPGroupFilter` AND `peerdiversity.Filter` for more details.
|
||
|
func RoutingTablePeerDiversityFilter(pg peerdiversity.PeerIPGroupFilter) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.RoutingTable.DiversityFilter = pg
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// disableFixLowPeersRoutine disables the "fixLowPeers" routine in the DHT.
|
||
|
// This is ONLY for tests.
|
||
|
func disableFixLowPeersRoutine(t *testing.T) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.DisableFixLowPeers = true
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// forceAddressUpdateProcessing forces the DHT to handle changes to the hosts addresses.
|
||
|
// This occurs even when AutoRefresh has been disabled.
|
||
|
// This is ONLY for tests.
|
||
|
func forceAddressUpdateProcessing(t *testing.T) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.TestAddressUpdateProcessing = true
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EnableOptimisticProvide enables an optimization that skips the last hops of the provide process.
|
||
|
// This works by using the network size estimator (which uses the keyspace density of queries)
|
||
|
// to optimistically send ADD_PROVIDER requests when we most likely have found the last hop.
|
||
|
// It will also run some ADD_PROVIDER requests asynchronously in the background after returning,
|
||
|
// this allows to optimistically return earlier if some threshold number of RPCs have succeeded.
|
||
|
// The number of background/in-flight queries can be configured with the OptimisticProvideJobsPoolSize
|
||
|
// option.
|
||
|
//
|
||
|
// EXPERIMENTAL: This is an experimental option and might be removed in the future. Use at your own risk.
|
||
|
func EnableOptimisticProvide() Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.EnableOptimisticProvide = true
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// OptimisticProvideJobsPoolSize allows to configure the asynchronicity limit for in-flight ADD_PROVIDER RPCs.
|
||
|
// It makes sense to set it to a multiple of optProvReturnRatio * BucketSize. Check the description of
|
||
|
// EnableOptimisticProvide for more details.
|
||
|
//
|
||
|
// EXPERIMENTAL: This is an experimental option and might be removed in the future. Use at your own risk.
|
||
|
func OptimisticProvideJobsPoolSize(size int) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.OptimisticProvideJobsPoolSize = size
|
||
|
return nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AddressFilter allows to configure the address filtering function.
|
||
|
// This function is run before addresses are added to the peerstore.
|
||
|
// It is most useful to avoid adding localhost / local addresses.
|
||
|
func AddressFilter(f func([]ma.Multiaddr) []ma.Multiaddr) Option {
|
||
|
return func(c *dhtcfg.Config) error {
|
||
|
c.AddressFilter = f
|
||
|
return nil
|
||
|
}
|
||
|
}
|