master
go 291 lines 10.6 KB
Raw
1 /*
2 Package core implements the IpfsNode object and related methods.
3
4 Packages underneath core/ provide a (relatively) stable, low-level API
5 to carry out most IPFS-related tasks. For more details on the other
6 interfaces and how core/... fits into the bigger IPFS picture, see:
7
8 $ godoc github.com/ipfs/go-ipfs
9 */
10 package core
11
12 import (
13 "context"
14 "encoding/json"
15 "io"
16 "time"
17
18 "github.com/ipfs/boxo/filestore"
19 pin "github.com/ipfs/boxo/pinning/pinner"
20 "github.com/ipfs/go-datastore"
21
22 bitswap "github.com/ipfs/boxo/bitswap"
23 bserv "github.com/ipfs/boxo/blockservice"
24 bstore "github.com/ipfs/boxo/blockstore"
25 exchange "github.com/ipfs/boxo/exchange"
26 "github.com/ipfs/boxo/fetcher"
27 mfs "github.com/ipfs/boxo/mfs"
28 pathresolver "github.com/ipfs/boxo/path/resolver"
29 provider "github.com/ipfs/boxo/provider"
30 ipld "github.com/ipfs/go-ipld-format"
31 logging "github.com/ipfs/go-log/v2"
32 ddht "github.com/libp2p/go-libp2p-kad-dht/dual"
33 "github.com/libp2p/go-libp2p-kad-dht/fullrt"
34 pubsub "github.com/libp2p/go-libp2p-pubsub"
35 psrouter "github.com/libp2p/go-libp2p-pubsub-router"
36 record "github.com/libp2p/go-libp2p-record"
37 routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
38 connmgr "github.com/libp2p/go-libp2p/core/connmgr"
39 ic "github.com/libp2p/go-libp2p/core/crypto"
40 p2phost "github.com/libp2p/go-libp2p/core/host"
41 metrics "github.com/libp2p/go-libp2p/core/metrics"
42 "github.com/libp2p/go-libp2p/core/network"
43 peer "github.com/libp2p/go-libp2p/core/peer"
44 pstore "github.com/libp2p/go-libp2p/core/peerstore"
45 routing "github.com/libp2p/go-libp2p/core/routing"
46 "github.com/libp2p/go-libp2p/p2p/discovery/mdns"
47 p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
48 ma "github.com/multiformats/go-multiaddr"
49 madns "github.com/multiformats/go-multiaddr-dns"
50
51 "github.com/ipfs/boxo/bootstrap"
52 "github.com/ipfs/boxo/namesys"
53 ipnsrp "github.com/ipfs/boxo/namesys/republisher"
54 "github.com/ipfs/boxo/peering"
55 "github.com/ipfs/kubo/config"
56 "github.com/ipfs/kubo/core/node"
57 "github.com/ipfs/kubo/core/node/libp2p"
58 "github.com/ipfs/kubo/fuse/mount"
59 "github.com/ipfs/kubo/p2p"
60 "github.com/ipfs/kubo/repo"
61 irouting "github.com/ipfs/kubo/routing"
62 )
63
64 var log = logging.Logger("core")
65
66 // IpfsNode is IPFS Core module. It represents an IPFS instance.
67 type IpfsNode struct {
68 // Self
69 Identity peer.ID // the local node's identity
70
71 Repo repo.Repo
72
73 // Local node
74 Pinning pin.Pinner // the pinning manager
75 Mounts Mounts `optional:"true"` // current mount state, if any.
76 PrivateKey ic.PrivKey `optional:"true"` // the local node's private Key
77 PNetFingerprint libp2p.PNetFingerprint `optional:"true"` // fingerprint of private network
78
79 // Services
80 Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances
81 Blockstore bstore.GCBlockstore // the block store (lower level)
82 Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore
83 BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping
84 GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc
85 Blocks bserv.BlockService // the block service, get/add blocks.
86 DAG ipld.DAGService // the merkle dag service, get/add objects.
87 IPLDFetcherFactory fetcher.Factory `name:"ipldFetcher"` // fetcher that paths over the IPLD data model
88 UnixFSFetcherFactory fetcher.Factory `name:"unixfsFetcher"` // fetcher that interprets UnixFS data
89 OfflineIPLDFetcherFactory fetcher.Factory `name:"offlineIpldFetcher"` // fetcher that paths over the IPLD data model without fetching new blocks
90 OfflineUnixFSFetcherFactory fetcher.Factory `name:"offlineUnixfsFetcher"` // fetcher that interprets UnixFS data without fetching new blocks
91 Reporter *metrics.BandwidthCounter `optional:"true"`
92 Discovery mdns.Service `optional:"true"`
93 FilesRoot *mfs.Root
94 RecordValidator record.Validator
95
96 // Online
97 PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
98 Peering *peering.PeeringService `optional:"true"`
99 Filters *ma.Filters `optional:"true"`
100 Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
101 ContentDiscovery routing.ContentDiscovery `optional:"true"` // the discovery part of the routing system
102 DNSResolver *madns.Resolver // the DNS resolver
103 IPLDPathResolver pathresolver.Resolver `name:"ipldPathResolver"` // The IPLD path resolver
104 UnixFSPathResolver pathresolver.Resolver `name:"unixFSPathResolver"` // The UnixFS path resolver
105 OfflineIPLDPathResolver pathresolver.Resolver `name:"offlineIpldPathResolver"` // The IPLD path resolver that uses only locally available blocks
106 OfflineUnixFSPathResolver pathresolver.Resolver `name:"offlineUnixFSPathResolver"` // The UnixFS path resolver that uses only locally available blocks
107 Exchange exchange.Interface // the block exchange + strategy
108 Bitswap *bitswap.Bitswap `optional:"true"` // The Bitswap instance
109 Namesys namesys.NameSystem // the name system, resolves paths to hashes
110 ProvidingStrategy config.ProvideStrategy `optional:"true"`
111 ProvidingKeyChanFunc provider.KeyChanFunc `optional:"true"`
112 IpnsRepub *ipnsrp.Republisher `optional:"true"`
113 ResourceManager network.ResourceManager `optional:"true"`
114
115 PubSub *pubsub.PubSub `optional:"true"`
116 PSRouter *psrouter.PubsubValueStore `optional:"true"`
117
118 Routing irouting.ProvideManyRouter `optional:"true"` // the routing system. recommend ipfs-dht
119 Provider node.DHTProvider // the value provider system
120 DHT *ddht.DHT `optional:"true"`
121 DHTClient routing.Routing `name:"dhtc" optional:"true"`
122
123 P2P *p2p.P2P `optional:"true"`
124
125 ctx context.Context
126
127 stop func() error
128
129 // Flags
130 IsOnline bool `optional:"true"` // Online is set when networking is enabled.
131 IsDaemon bool `optional:"true"` // Daemon is set when running on a long-running daemon.
132 }
133
134 // Mounts defines what the node's mount state is. This should
135 // perhaps be moved to the daemon or mount. It's here because
136 // it needs to be accessible across daemon requests.
137 type Mounts struct {
138 Ipfs mount.Mount
139 Ipns mount.Mount
140 Mfs mount.Mount
141 }
142
143 // Close calls Close() on the App object
144 func (n *IpfsNode) Close() error {
145 return n.stop()
146 }
147
148 // HasActiveDHTClient checks if the node's DHT client is active and usable for DHT operations.
149 //
150 // Returns false for:
151 // - nil DHTClient
152 // - typed nil pointers (e.g., (*ddht.DHT)(nil))
153 // - no-op routers (routinghelpers.Null)
154 //
155 // Note: This method only checks for known DHT client types (ddht.DHT, fullrt.FullRT).
156 // Custom routing.Routing implementations are not explicitly validated.
157 //
158 // This method prevents the "typed nil interface" bug where an interface contains
159 // a nil pointer of a concrete type, which passes nil checks but panics when methods
160 // are called.
161 func (n *IpfsNode) HasActiveDHTClient() bool {
162 if n.DHTClient == nil {
163 return false
164 }
165
166 // Check for no-op router (Routing.Type=none)
167 if _, ok := n.DHTClient.(routinghelpers.Null); ok {
168 return false
169 }
170
171 // Check for typed nil *ddht.DHT (common when Routing.Type=delegated or HTTP-only)
172 if d, ok := n.DHTClient.(*ddht.DHT); ok && d == nil {
173 return false
174 }
175
176 // Check for typed nil *fullrt.FullRT (accelerated DHT client)
177 if f, ok := n.DHTClient.(*fullrt.FullRT); ok && f == nil {
178 return false
179 }
180
181 return true
182 }
183
184 // Context returns the IpfsNode context
185 func (n *IpfsNode) Context() context.Context {
186 if n.ctx == nil {
187 n.ctx = context.TODO()
188 }
189 return n.ctx
190 }
191
192 // Bootstrap will set and call the IpfsNodes bootstrap function.
193 func (n *IpfsNode) Bootstrap(cfg bootstrap.BootstrapConfig) error {
194 // TODO what should return value be when in offlineMode?
195 if n.Routing == nil {
196 return nil
197 }
198
199 if n.Bootstrapper != nil {
200 n.Bootstrapper.Close() // stop previous bootstrap process.
201 }
202
203 // if the caller did not specify a bootstrap peer function, get the
204 // freshest bootstrap peers from config. this responds to live changes.
205 if cfg.BootstrapPeers == nil {
206 cfg.BootstrapPeers = func() []peer.AddrInfo {
207 ps, err := n.loadBootstrapPeers()
208 if err != nil {
209 log.Warn("failed to parse bootstrap peers from config")
210 return nil
211 }
212 return ps
213 }
214 }
215 if load, _ := cfg.BackupPeers(); load == nil {
216 save := func(ctx context.Context, peerList []peer.AddrInfo) {
217 err := n.saveTempBootstrapPeers(ctx, peerList)
218 if err != nil {
219 log.Warnf("saveTempBootstrapPeers failed: %s", err)
220 return
221 }
222 }
223 load = func(ctx context.Context) []peer.AddrInfo {
224 peerList, err := n.loadTempBootstrapPeers(ctx)
225 if err != nil {
226 log.Warnf("loadTempBootstrapPeers failed: %s", err)
227 return nil
228 }
229 return peerList
230 }
231 cfg.SetBackupPeers(load, save)
232 }
233
234 repoConf, err := n.Repo.Config()
235 if err != nil {
236 return err
237 }
238 if repoConf.Internal.BackupBootstrapInterval != nil {
239 cfg.BackupBootstrapInterval = repoConf.Internal.BackupBootstrapInterval.WithDefault(time.Hour)
240 }
241
242 n.Bootstrapper, err = bootstrap.Bootstrap(n.Identity, n.PeerHost, n.Routing, cfg)
243 return err
244 }
245
246 var TempBootstrapPeersKey = datastore.NewKey("/local/temp_bootstrap_peers")
247
248 func (n *IpfsNode) loadBootstrapPeers() ([]peer.AddrInfo, error) {
249 cfg, err := n.Repo.Config()
250 if err != nil {
251 return nil, err
252 }
253
254 // Use auto-config resolution for actual bootstrap connectivity
255 return cfg.BootstrapPeersWithAutoConf()
256 }
257
258 func (n *IpfsNode) saveTempBootstrapPeers(ctx context.Context, peerList []peer.AddrInfo) error {
259 ds := n.Repo.Datastore()
260 bytes, err := json.Marshal(config.BootstrapPeerStrings(peerList))
261 if err != nil {
262 return err
263 }
264
265 if err := ds.Put(ctx, TempBootstrapPeersKey, bytes); err != nil {
266 return err
267 }
268 return ds.Sync(ctx, TempBootstrapPeersKey)
269 }
270
271 func (n *IpfsNode) loadTempBootstrapPeers(ctx context.Context) ([]peer.AddrInfo, error) {
272 ds := n.Repo.Datastore()
273 bytes, err := ds.Get(ctx, TempBootstrapPeersKey)
274 if err != nil {
275 return nil, err
276 }
277
278 var addrs []string
279 if err := json.Unmarshal(bytes, &addrs); err != nil {
280 return nil, err
281 }
282 return config.ParseBootstrapPeers(addrs)
283 }
284
285 type ConstructPeerHostOpts struct {
286 AddrsFactory p2pbhost.AddrsFactory
287 DisableNatPortMap bool
288 DisableRelay bool
289 EnableRelayHop bool
290 ConnectionManager connmgr.ConnManager
291 }