github.com/ethersphere/bee/v2@v2.2.0/pkg/node/node.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package node defines the concept of a Bee node 6 // by bootstrapping and injecting all necessary 7 // dependencies. 8 package node 9 10 import ( 11 "context" 12 "crypto/ecdsa" 13 "encoding/hex" 14 "errors" 15 "fmt" 16 "io" 17 stdlog "log" 18 "math/big" 19 "net" 20 "net/http" 21 "path/filepath" 22 "runtime" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethersphere/bee/v2/pkg/accesscontrol" 29 "github.com/ethersphere/bee/v2/pkg/accounting" 30 "github.com/ethersphere/bee/v2/pkg/addressbook" 31 "github.com/ethersphere/bee/v2/pkg/api" 32 "github.com/ethersphere/bee/v2/pkg/config" 33 "github.com/ethersphere/bee/v2/pkg/crypto" 34 "github.com/ethersphere/bee/v2/pkg/feeds/factory" 35 "github.com/ethersphere/bee/v2/pkg/hive" 36 "github.com/ethersphere/bee/v2/pkg/log" 37 "github.com/ethersphere/bee/v2/pkg/metrics" 38 "github.com/ethersphere/bee/v2/pkg/p2p" 39 "github.com/ethersphere/bee/v2/pkg/p2p/libp2p" 40 "github.com/ethersphere/bee/v2/pkg/pingpong" 41 "github.com/ethersphere/bee/v2/pkg/postage" 42 "github.com/ethersphere/bee/v2/pkg/postage/batchservice" 43 "github.com/ethersphere/bee/v2/pkg/postage/batchstore" 44 "github.com/ethersphere/bee/v2/pkg/postage/listener" 45 "github.com/ethersphere/bee/v2/pkg/postage/postagecontract" 46 "github.com/ethersphere/bee/v2/pkg/pricer" 47 "github.com/ethersphere/bee/v2/pkg/pricing" 48 "github.com/ethersphere/bee/v2/pkg/pss" 49 "github.com/ethersphere/bee/v2/pkg/puller" 50 "github.com/ethersphere/bee/v2/pkg/pullsync" 51 "github.com/ethersphere/bee/v2/pkg/pusher" 52 "github.com/ethersphere/bee/v2/pkg/pushsync" 53 "github.com/ethersphere/bee/v2/pkg/resolver/multiresolver" 54 "github.com/ethersphere/bee/v2/pkg/retrieval" 55 "github.com/ethersphere/bee/v2/pkg/salud" 56 "github.com/ethersphere/bee/v2/pkg/settlement/pseudosettle" 57 "github.com/ethersphere/bee/v2/pkg/settlement/swap" 58 "github.com/ethersphere/bee/v2/pkg/settlement/swap/chequebook" 59 "github.com/ethersphere/bee/v2/pkg/settlement/swap/erc20" 60 "github.com/ethersphere/bee/v2/pkg/settlement/swap/priceoracle" 61 "github.com/ethersphere/bee/v2/pkg/status" 62 "github.com/ethersphere/bee/v2/pkg/steward" 63 "github.com/ethersphere/bee/v2/pkg/storageincentives" 64 "github.com/ethersphere/bee/v2/pkg/storageincentives/redistribution" 65 "github.com/ethersphere/bee/v2/pkg/storageincentives/staking" 66 "github.com/ethersphere/bee/v2/pkg/storer" 67 "github.com/ethersphere/bee/v2/pkg/swarm" 68 "github.com/ethersphere/bee/v2/pkg/topology" 69 "github.com/ethersphere/bee/v2/pkg/topology/kademlia" 70 "github.com/ethersphere/bee/v2/pkg/topology/lightnode" 71 "github.com/ethersphere/bee/v2/pkg/tracing" 72 "github.com/ethersphere/bee/v2/pkg/transaction" 73 "github.com/ethersphere/bee/v2/pkg/util/abiutil" 74 "github.com/ethersphere/bee/v2/pkg/util/ioutil" 75 "github.com/ethersphere/bee/v2/pkg/util/nbhdutil" 76 "github.com/ethersphere/bee/v2/pkg/util/syncutil" 77 "github.com/hashicorp/go-multierror" 78 ma "github.com/multiformats/go-multiaddr" 79 promc "github.com/prometheus/client_golang/prometheus" 80 "golang.org/x/crypto/sha3" 81 "golang.org/x/sync/errgroup" 82 ) 83 84 // LoggerName is the tree path name of the logger for this package. 85 const LoggerName = "node" 86 87 type Bee struct { 88 p2pService io.Closer 89 p2pHalter p2p.Halter 90 ctxCancel context.CancelFunc 91 apiCloser io.Closer 92 apiServer *http.Server 93 resolverCloser io.Closer 94 errorLogWriter io.Writer 95 tracerCloser io.Closer 96 stateStoreCloser io.Closer 97 stamperStoreCloser io.Closer 98 localstoreCloser io.Closer 99 topologyCloser io.Closer 100 topologyHalter topology.Halter 101 pusherCloser io.Closer 102 pullerCloser io.Closer 103 accountingCloser io.Closer 104 pullSyncCloser io.Closer 105 pssCloser io.Closer 106 ethClientCloser func() 107 transactionMonitorCloser io.Closer 108 transactionCloser io.Closer 109 listenerCloser io.Closer 110 postageServiceCloser io.Closer 111 priceOracleCloser io.Closer 112 hiveCloser io.Closer 113 saludCloser io.Closer 114 storageIncetivesCloser io.Closer 115 pushSyncCloser io.Closer 116 retrievalCloser io.Closer 117 shutdownInProgress bool 118 shutdownMutex sync.Mutex 119 syncingStopped *syncutil.Signaler 120 accesscontrolCloser io.Closer 121 } 122 123 type Options struct { 124 DataDir string 125 CacheCapacity uint64 126 DBOpenFilesLimit uint64 127 DBWriteBufferSize uint64 128 DBBlockCacheCapacity uint64 129 DBDisableSeeksCompaction bool 130 APIAddr string 131 Addr string 132 NATAddr string 133 EnableWS bool 134 WelcomeMessage string 135 Bootnodes []string 136 CORSAllowedOrigins []string 137 Logger log.Logger 138 TracingEnabled bool 139 TracingEndpoint string 140 TracingServiceName string 141 PaymentThreshold string 142 PaymentTolerance int64 143 PaymentEarly int64 144 ResolverConnectionCfgs []multiresolver.ConnectionConfig 145 RetrievalCaching bool 146 BootnodeMode bool 147 BlockchainRpcEndpoint string 148 SwapFactoryAddress string 149 SwapInitialDeposit string 150 SwapEnable bool 151 ChequebookEnable bool 152 FullNodeMode bool 153 PostageContractAddress string 154 PostageContractStartBlock uint64 155 StakingContractAddress string 156 PriceOracleAddress string 157 RedistributionContractAddress string 158 BlockTime time.Duration 159 DeployGasPrice string 160 WarmupTime time.Duration 161 ChainID int64 162 Resync bool 163 BlockProfile bool 164 MutexProfile bool 165 StaticNodes []swarm.Address 166 AllowPrivateCIDRs bool 167 UsePostageSnapshot bool 168 EnableStorageIncentives bool 169 StatestoreCacheCapacity uint64 170 TargetNeighborhood string 171 NeighborhoodSuggester string 172 WhitelistedWithdrawalAddress []string 173 TrxDebugMode bool 174 MinimumStorageRadius uint 175 } 176 177 const ( 178 refreshRate = int64(4_500_000) // accounting units refreshed per second 179 lightFactor = 10 // downscale payment thresholds and their change rate, and refresh rates by this for light nodes 180 lightRefreshRate = refreshRate / lightFactor // refresh rate used by / for light nodes 181 basePrice = 10_000 // minimal price for retrieval and pushsync requests of maximum proximity 182 postageSyncingStallingTimeout = 10 * time.Minute // 183 postageSyncingBackoffTimeout = 5 * time.Second // 184 minPaymentThreshold = 2 * refreshRate // minimal accepted payment threshold of full nodes 185 maxPaymentThreshold = 24 * refreshRate // maximal accepted payment threshold of full nodes 186 mainnetNetworkID = uint64(1) // 187 ReserveCapacity = 4_194_304 // 2^22 chunks 188 reserveWakeUpDuration = 15 * time.Minute // time to wait before waking up reserveWorker 189 reserveTreshold = ReserveCapacity * 5 / 10 190 reserveMinEvictCount = 1_000 191 cacheMinEvictCount = 10_000 192 ) 193 194 func NewBee( 195 ctx context.Context, 196 addr string, 197 publicKey *ecdsa.PublicKey, 198 signer crypto.Signer, 199 networkID uint64, 200 logger log.Logger, 201 libp2pPrivateKey, 202 pssPrivateKey *ecdsa.PrivateKey, 203 session accesscontrol.Session, 204 o *Options, 205 ) (b *Bee, err error) { 206 tracer, tracerCloser, err := tracing.NewTracer(&tracing.Options{ 207 Enabled: o.TracingEnabled, 208 Endpoint: o.TracingEndpoint, 209 ServiceName: o.TracingServiceName, 210 }) 211 if err != nil { 212 return nil, fmt.Errorf("tracer: %w", err) 213 } 214 215 ctx, ctxCancel := context.WithCancel(ctx) 216 defer func() { 217 // if there's been an error on this function 218 // we'd like to cancel the p2p context so that 219 // incoming connections will not be possible 220 if err != nil { 221 ctxCancel() 222 } 223 }() 224 225 // light nodes have zero warmup time for pull/pushsync protocols 226 warmupTime := o.WarmupTime 227 if !o.FullNodeMode { 228 warmupTime = 0 229 } 230 231 sink := ioutil.WriterFunc(func(p []byte) (int, error) { 232 logger.Error(nil, string(p)) 233 return len(p), nil 234 }) 235 236 b = &Bee{ 237 ctxCancel: ctxCancel, 238 errorLogWriter: sink, 239 tracerCloser: tracerCloser, 240 syncingStopped: syncutil.NewSignaler(), 241 } 242 243 defer func(b *Bee) { 244 if err != nil { 245 logger.Error(err, "got error, shutting down...") 246 if err2 := b.Shutdown(); err2 != nil { 247 logger.Error(err2, "got error while shutting down") 248 } 249 } 250 }(b) 251 252 stateStore, stateStoreMetrics, err := InitStateStore(logger, o.DataDir, o.StatestoreCacheCapacity) 253 if err != nil { 254 return nil, err 255 } 256 257 pubKey, err := signer.PublicKey() 258 if err != nil { 259 return nil, err 260 } 261 262 nonce, nonceExists, err := overlayNonceExists(stateStore) 263 if err != nil { 264 return nil, fmt.Errorf("check presence of nonce: %w", err) 265 } 266 267 swarmAddress, err := crypto.NewOverlayAddress(*pubKey, networkID, nonce) 268 if err != nil { 269 return nil, fmt.Errorf("compute overlay address: %w", err) 270 } 271 272 targetNeighborhood := o.TargetNeighborhood 273 if targetNeighborhood == "" && !nonceExists && o.NeighborhoodSuggester != "" { 274 logger.Info("fetching target neighborhood from suggester", "url", o.NeighborhoodSuggester) 275 targetNeighborhood, err = nbhdutil.FetchNeighborhood(&http.Client{}, o.NeighborhoodSuggester) 276 if err != nil { 277 return nil, fmt.Errorf("neighborhood suggestion: %w", err) 278 } 279 } 280 281 var changedOverlay, resetReserve bool 282 if targetNeighborhood != "" { 283 neighborhood, err := swarm.ParseBitStrAddress(targetNeighborhood) 284 if err != nil { 285 return nil, fmt.Errorf("invalid neighborhood. %s", targetNeighborhood) 286 } 287 288 if swarm.Proximity(swarmAddress.Bytes(), neighborhood.Bytes()) < uint8(len(targetNeighborhood)) { 289 // mine the overlay 290 logger.Info("mining a new overlay address to target the selected neighborhood", "target", targetNeighborhood) 291 newSwarmAddress, newNonce, err := nbhdutil.MineOverlay(ctx, *pubKey, networkID, targetNeighborhood) 292 if err != nil { 293 return nil, fmt.Errorf("mine overlay address: %w", err) 294 } 295 296 if nonceExists { 297 logger.Info("Override nonce and clean state for neighborhood", "old_none", hex.EncodeToString(nonce), "new_nonce", hex.EncodeToString(newNonce)) 298 logger.Warning("you have another 10 seconds to change your mind and kill this process with CTRL-C...") 299 time.Sleep(10 * time.Second) 300 301 err := ioutil.RemoveContent(filepath.Join(o.DataDir, ioutil.DataPathKademlia)) 302 if err != nil { 303 return nil, fmt.Errorf("delete %s: %w", ioutil.DataPathKademlia, err) 304 } 305 306 if err := stateStore.ClearForHopping(); err != nil { 307 return nil, fmt.Errorf("clearing stateStore %w", err) 308 } 309 resetReserve = true 310 } 311 312 swarmAddress = newSwarmAddress 313 nonce = newNonce 314 err = setOverlay(stateStore, swarmAddress, nonce) 315 if err != nil { 316 return nil, fmt.Errorf("statestore: save new overlay: %w", err) 317 } 318 changedOverlay = true 319 } 320 } 321 322 b.stateStoreCloser = stateStore 323 // Check if the batchstore exists. If not, we can assume it's missing 324 // due to a migration or it's a fresh install. 325 batchStoreExists, err := batchStoreExists(stateStore) 326 if err != nil { 327 return nil, fmt.Errorf("batchstore: exists: %w", err) 328 } 329 330 addressbook := addressbook.New(stateStore) 331 332 logger.Info("using overlay address", "address", swarmAddress) 333 334 // this will set overlay if it was not set before 335 if err = checkOverlay(stateStore, swarmAddress); err != nil { 336 return nil, fmt.Errorf("check overlay address: %w", err) 337 } 338 339 var ( 340 chainBackend transaction.Backend 341 overlayEthAddress common.Address 342 chainID int64 343 transactionService transaction.Service 344 transactionMonitor transaction.Monitor 345 chequebookFactory chequebook.Factory 346 chequebookService chequebook.Service = new(noOpChequebookService) 347 chequeStore chequebook.ChequeStore 348 cashoutService chequebook.CashoutService 349 erc20Service erc20.Service 350 ) 351 352 chainEnabled := isChainEnabled(o, o.BlockchainRpcEndpoint, logger) 353 354 var batchStore postage.Storer = new(postage.NoOpBatchStore) 355 var evictFn func([]byte) error 356 357 if chainEnabled { 358 batchStore, err = batchstore.New( 359 stateStore, 360 func(id []byte) error { 361 return evictFn(id) 362 }, 363 ReserveCapacity, 364 logger, 365 ) 366 if err != nil { 367 return nil, fmt.Errorf("batchstore: %w", err) 368 } 369 } 370 371 chainBackend, overlayEthAddress, chainID, transactionMonitor, transactionService, err = InitChain( 372 ctx, 373 logger, 374 stateStore, 375 o.BlockchainRpcEndpoint, 376 o.ChainID, 377 signer, 378 o.BlockTime, 379 chainEnabled) 380 if err != nil { 381 return nil, fmt.Errorf("init chain: %w", err) 382 } 383 b.ethClientCloser = chainBackend.Close 384 385 logger.Info("using chain with network network", "chain_id", chainID, "network_id", networkID) 386 387 if o.ChainID != -1 && o.ChainID != chainID { 388 return nil, fmt.Errorf("connected to wrong blockchain network; network chainID %d; configured chainID %d", chainID, o.ChainID) 389 } 390 391 b.transactionCloser = tracerCloser 392 b.transactionMonitorCloser = transactionMonitor 393 394 beeNodeMode := api.LightMode 395 if o.FullNodeMode { 396 beeNodeMode = api.FullMode 397 } else if !chainEnabled { 398 beeNodeMode = api.UltraLightMode 399 } 400 401 // Create api.Probe in healthy state and switch to ready state after all components have been constructed 402 probe := api.NewProbe() 403 probe.SetHealthy(api.ProbeStatusOK) 404 defer func(probe *api.Probe) { 405 if err != nil { 406 probe.SetHealthy(api.ProbeStatusNOK) 407 } else { 408 probe.SetReady(api.ProbeStatusOK) 409 } 410 }(probe) 411 412 stamperStore, err := InitStamperStore(logger, o.DataDir, stateStore) 413 if err != nil { 414 return nil, fmt.Errorf("failed to initialize stamper store: %w", err) 415 } 416 b.stamperStoreCloser = stamperStore 417 418 var apiService *api.Service 419 420 if o.APIAddr != "" { 421 if o.MutexProfile { 422 _ = runtime.SetMutexProfileFraction(1) 423 } 424 if o.BlockProfile { 425 runtime.SetBlockProfileRate(1) 426 } 427 428 apiListener, err := net.Listen("tcp", o.APIAddr) 429 if err != nil { 430 return nil, fmt.Errorf("api listener: %w", err) 431 } 432 433 apiService = api.New( 434 *publicKey, 435 pssPrivateKey.PublicKey, 436 overlayEthAddress, 437 o.WhitelistedWithdrawalAddress, 438 logger, 439 transactionService, 440 batchStore, 441 beeNodeMode, 442 o.ChequebookEnable, 443 o.SwapEnable, 444 chainBackend, 445 o.CORSAllowedOrigins, 446 stamperStore, 447 ) 448 apiService.MountTechnicalDebug() 449 apiService.SetProbe(probe) 450 451 apiServer := &http.Server{ 452 IdleTimeout: 30 * time.Second, 453 ReadHeaderTimeout: 3 * time.Second, 454 Handler: apiService, 455 ErrorLog: stdlog.New(b.errorLogWriter, "", 0), 456 } 457 458 go func() { 459 logger.Info("starting debug & api server", "address", apiListener.Addr()) 460 461 if err := apiServer.Serve(apiListener); err != nil && !errors.Is(err, http.ErrServerClosed) { 462 logger.Debug("debug & api server failed to start", "error", err) 463 logger.Error(nil, "debug & api server failed to start") 464 } 465 }() 466 467 b.apiServer = apiServer 468 b.apiCloser = apiServer 469 } 470 471 // Sync the with the given Ethereum backend: 472 isSynced, _, err := transaction.IsSynced(ctx, chainBackend, maxDelay) 473 if err != nil { 474 return nil, fmt.Errorf("is synced: %w", err) 475 } 476 if !isSynced { 477 logger.Info("waiting to sync with the blockchain backend") 478 479 err := transaction.WaitSynced(ctx, logger, chainBackend, maxDelay) 480 if err != nil { 481 return nil, fmt.Errorf("waiting backend sync: %w", err) 482 } 483 } 484 485 if o.SwapEnable { 486 chequebookFactory, err = InitChequebookFactory(logger, chainBackend, chainID, transactionService, o.SwapFactoryAddress) 487 if err != nil { 488 return nil, err 489 } 490 491 erc20Address, err := chequebookFactory.ERC20Address(ctx) 492 if err != nil { 493 return nil, fmt.Errorf("factory fail: %w", err) 494 } 495 496 erc20Service = erc20.New(transactionService, erc20Address) 497 498 if o.ChequebookEnable && chainEnabled { 499 chequebookService, err = InitChequebookService( 500 ctx, 501 logger, 502 stateStore, 503 signer, 504 chainID, 505 chainBackend, 506 overlayEthAddress, 507 transactionService, 508 chequebookFactory, 509 o.SwapInitialDeposit, 510 o.DeployGasPrice, 511 erc20Service, 512 ) 513 if err != nil { 514 return nil, err 515 } 516 } 517 518 chequeStore, cashoutService = initChequeStoreCashout( 519 stateStore, 520 chainBackend, 521 chequebookFactory, 522 chainID, 523 overlayEthAddress, 524 transactionService, 525 ) 526 } 527 528 lightNodes := lightnode.NewContainer(swarmAddress) 529 530 bootnodes := make([]ma.Multiaddr, 0, len(o.Bootnodes)) 531 532 for _, a := range o.Bootnodes { 533 addr, err := ma.NewMultiaddr(a) 534 if err != nil { 535 logger.Debug("create bootnode multiaddress from string failed", "string", a, "error", err) 536 logger.Warning("create bootnode multiaddress from string failed", "string", a) 537 continue 538 } 539 540 bootnodes = append(bootnodes, addr) 541 } 542 543 // Perform checks related to payment threshold calculations here to not duplicate 544 // the checks in bootstrap process 545 paymentThreshold, ok := new(big.Int).SetString(o.PaymentThreshold, 10) 546 if !ok { 547 return nil, fmt.Errorf("invalid payment threshold: %s", paymentThreshold) 548 } 549 550 if paymentThreshold.Cmp(big.NewInt(minPaymentThreshold)) < 0 { 551 return nil, fmt.Errorf("payment threshold below minimum generally accepted value, need at least %d", minPaymentThreshold) 552 } 553 554 if paymentThreshold.Cmp(big.NewInt(maxPaymentThreshold)) > 0 { 555 return nil, fmt.Errorf("payment threshold above maximum generally accepted value, needs to be reduced to at most %d", maxPaymentThreshold) 556 } 557 558 if o.PaymentTolerance < 0 { 559 return nil, fmt.Errorf("invalid payment tolerance: %d", o.PaymentTolerance) 560 } 561 562 if o.PaymentEarly > 100 || o.PaymentEarly < 0 { 563 return nil, fmt.Errorf("invalid payment early: %d", o.PaymentEarly) 564 } 565 566 var initBatchState *postage.ChainSnapshot 567 // Bootstrap node with postage snapshot only if it is running on mainnet, is a fresh 568 // install or explicitly asked by user to resync 569 if networkID == mainnetNetworkID && o.UsePostageSnapshot && (!batchStoreExists || o.Resync) { 570 start := time.Now() 571 logger.Info("cold postage start detected. fetching postage stamp snapshot from swarm") 572 initBatchState, err = bootstrapNode( 573 ctx, 574 addr, 575 swarmAddress, 576 nonce, 577 addressbook, 578 bootnodes, 579 lightNodes, 580 stateStore, 581 signer, 582 networkID, 583 log.Noop, 584 libp2pPrivateKey, 585 o, 586 ) 587 logger.Info("bootstrapper created", "elapsed", time.Since(start)) 588 if err != nil { 589 logger.Error(err, "bootstrapper failed to fetch batch state") 590 } 591 } 592 593 var registry *promc.Registry 594 595 if apiService != nil { 596 registry = apiService.MetricsRegistry() 597 } 598 599 p2ps, err := libp2p.New(ctx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{ 600 PrivateKey: libp2pPrivateKey, 601 NATAddr: o.NATAddr, 602 EnableWS: o.EnableWS, 603 WelcomeMessage: o.WelcomeMessage, 604 FullNode: o.FullNodeMode, 605 Nonce: nonce, 606 ValidateOverlay: chainEnabled, 607 Registry: registry, 608 }) 609 if err != nil { 610 return nil, fmt.Errorf("p2p service: %w", err) 611 } 612 613 apiService.SetP2P(p2ps) 614 615 b.p2pService = p2ps 616 b.p2pHalter = p2ps 617 618 post, err := postage.NewService(logger, stamperStore, batchStore, chainID) 619 if err != nil { 620 return nil, fmt.Errorf("postage service: %w", err) 621 } 622 b.postageServiceCloser = post 623 batchStore.SetBatchExpiryHandler(post) 624 625 var ( 626 postageStampContractService postagecontract.Interface 627 batchSvc postage.EventUpdater 628 eventListener postage.Listener 629 ) 630 631 chainCfg, found := config.GetByChainID(chainID) 632 postageStampContractAddress, postageSyncStart := chainCfg.PostageStampAddress, chainCfg.PostageStampStartBlock 633 if o.PostageContractAddress != "" { 634 if !common.IsHexAddress(o.PostageContractAddress) { 635 return nil, errors.New("malformed postage stamp address") 636 } 637 postageStampContractAddress = common.HexToAddress(o.PostageContractAddress) 638 if o.PostageContractStartBlock == 0 { 639 return nil, errors.New("postage contract start block option not provided") 640 } 641 postageSyncStart = o.PostageContractStartBlock 642 } else if !found { 643 return nil, errors.New("no known postage stamp addresses for this network") 644 } 645 646 postageStampContractABI := abiutil.MustParseABI(chainCfg.PostageStampABI) 647 648 bzzTokenAddress, err := postagecontract.LookupERC20Address(ctx, transactionService, postageStampContractAddress, postageStampContractABI, chainEnabled) 649 if err != nil { 650 return nil, err 651 } 652 653 postageStampContractService = postagecontract.New( 654 overlayEthAddress, 655 postageStampContractAddress, 656 postageStampContractABI, 657 bzzTokenAddress, 658 transactionService, 659 post, 660 batchStore, 661 chainEnabled, 662 o.TrxDebugMode, 663 ) 664 665 eventListener = listener.New(b.syncingStopped, logger, chainBackend, postageStampContractAddress, postageStampContractABI, o.BlockTime, postageSyncingStallingTimeout, postageSyncingBackoffTimeout) 666 b.listenerCloser = eventListener 667 668 batchSvc, err = batchservice.New(stateStore, batchStore, logger, eventListener, overlayEthAddress.Bytes(), post, sha3.New256, o.Resync) 669 if err != nil { 670 return nil, err 671 } 672 673 // Construct protocols. 674 pingPong := pingpong.New(p2ps, logger, tracer) 675 676 if err = p2ps.AddProtocol(pingPong.Protocol()); err != nil { 677 return nil, fmt.Errorf("pingpong service: %w", err) 678 } 679 680 hive := hive.New(p2ps, addressbook, networkID, o.BootnodeMode, o.AllowPrivateCIDRs, logger) 681 682 if err = p2ps.AddProtocol(hive.Protocol()); err != nil { 683 return nil, fmt.Errorf("hive service: %w", err) 684 } 685 b.hiveCloser = hive 686 687 var swapService *swap.Service 688 689 kad, err := kademlia.New(swarmAddress, addressbook, hive, p2ps, logger, 690 kademlia.Options{Bootnodes: bootnodes, BootnodeMode: o.BootnodeMode, StaticNodes: o.StaticNodes, DataDir: o.DataDir}) 691 if err != nil { 692 return nil, fmt.Errorf("unable to create kademlia: %w", err) 693 } 694 b.topologyCloser = kad 695 b.topologyHalter = kad 696 hive.SetAddPeersHandler(kad.AddPeers) 697 p2ps.SetPickyNotifier(kad) 698 699 var path string 700 701 if o.DataDir != "" { 702 logger.Info("using datadir", "path", o.DataDir) 703 path = filepath.Join(o.DataDir, ioutil.DataPathLocalstore) 704 } 705 706 lo := &storer.Options{ 707 Address: swarmAddress, 708 CacheCapacity: o.CacheCapacity, 709 LdbOpenFilesLimit: o.DBOpenFilesLimit, 710 LdbBlockCacheCapacity: o.DBBlockCacheCapacity, 711 LdbWriteBufferSize: o.DBWriteBufferSize, 712 LdbDisableSeeksCompaction: o.DBDisableSeeksCompaction, 713 Batchstore: batchStore, 714 StateStore: stateStore, 715 RadiusSetter: kad, 716 WarmupDuration: o.WarmupTime, 717 Logger: logger, 718 Tracer: tracer, 719 CacheMinEvictCount: cacheMinEvictCount, 720 MinimumStorageRadius: o.MinimumStorageRadius, 721 } 722 723 if o.FullNodeMode && !o.BootnodeMode { 724 // configure reserve only for full node 725 lo.ReserveCapacity = ReserveCapacity 726 lo.ReserveWakeUpDuration = reserveWakeUpDuration 727 lo.ReserveMinEvictCount = reserveMinEvictCount 728 lo.RadiusSetter = kad 729 } 730 731 localStore, err := storer.New(ctx, path, lo) 732 if err != nil { 733 return nil, fmt.Errorf("localstore: %w", err) 734 } 735 b.localstoreCloser = localStore 736 evictFn = func(id []byte) error { return localStore.EvictBatch(context.Background(), id) } 737 738 if resetReserve { 739 logger.Warning("resetting the reserve") 740 err := localStore.ResetReserve(ctx) 741 if err != nil { 742 return nil, fmt.Errorf("reset reserve: %w", err) 743 } 744 } 745 746 actLogic := accesscontrol.NewLogic(session) 747 accesscontrol := accesscontrol.NewController(actLogic) 748 b.accesscontrolCloser = accesscontrol 749 750 var ( 751 syncErr atomic.Value 752 syncStatus atomic.Value 753 754 syncStatusFn = func() (isDone bool, err error) { 755 iErr := syncErr.Load() 756 if iErr != nil { 757 err = iErr.(error) 758 } 759 isDone = syncStatus.Load() != nil 760 return isDone, err 761 } 762 ) 763 764 if batchSvc != nil && chainEnabled { 765 logger.Info("waiting to sync postage contract data, this may take a while... more info available in Debug loglevel") 766 767 paused, err := postageStampContractService.Paused(ctx) 768 if err != nil { 769 logger.Error(err, "Error checking postage contract is paused") 770 } 771 772 if paused { 773 return nil, errors.New("postage contract is paused") 774 } 775 776 if o.FullNodeMode { 777 err = batchSvc.Start(ctx, postageSyncStart, initBatchState) 778 syncStatus.Store(true) 779 if err != nil { 780 syncErr.Store(err) 781 return nil, fmt.Errorf("unable to start batch service: %w", err) 782 } 783 } else { 784 go func() { 785 logger.Info("started postage contract data sync in the background...") 786 err := batchSvc.Start(ctx, postageSyncStart, initBatchState) 787 syncStatus.Store(true) 788 if err != nil { 789 syncErr.Store(err) 790 logger.Error(err, "unable to sync batches") 791 b.syncingStopped.Signal() // trigger shutdown in start.go 792 } 793 }() 794 } 795 796 } 797 798 minThreshold := big.NewInt(2 * refreshRate) 799 maxThreshold := big.NewInt(24 * refreshRate) 800 801 if !o.FullNodeMode { 802 minThreshold = big.NewInt(2 * lightRefreshRate) 803 } 804 805 lightPaymentThreshold := new(big.Int).Div(paymentThreshold, big.NewInt(lightFactor)) 806 807 pricer := pricer.NewFixedPricer(swarmAddress, basePrice) 808 809 if paymentThreshold.Cmp(minThreshold) < 0 { 810 return nil, fmt.Errorf("payment threshold below minimum generally accepted value, need at least %s", minThreshold) 811 } 812 813 if paymentThreshold.Cmp(maxThreshold) > 0 { 814 return nil, fmt.Errorf("payment threshold above maximum generally accepted value, needs to be reduced to at most %s", maxThreshold) 815 } 816 817 pricing := pricing.New(p2ps, logger, paymentThreshold, lightPaymentThreshold, minThreshold) 818 819 if err = p2ps.AddProtocol(pricing.Protocol()); err != nil { 820 return nil, fmt.Errorf("pricing service: %w", err) 821 } 822 823 addrs, err := p2ps.Addresses() 824 if err != nil { 825 return nil, fmt.Errorf("get server addresses: %w", err) 826 } 827 828 for _, addr := range addrs { 829 logger.Debug("p2p address", "address", addr) 830 } 831 832 var enforcedRefreshRate *big.Int 833 834 if o.FullNodeMode { 835 enforcedRefreshRate = big.NewInt(refreshRate) 836 } else { 837 enforcedRefreshRate = big.NewInt(lightRefreshRate) 838 } 839 840 acc, err := accounting.NewAccounting( 841 paymentThreshold, 842 o.PaymentTolerance, 843 o.PaymentEarly, 844 logger, 845 stateStore, 846 pricing, 847 new(big.Int).Set(enforcedRefreshRate), 848 lightFactor, 849 p2ps, 850 ) 851 if err != nil { 852 return nil, fmt.Errorf("accounting: %w", err) 853 } 854 b.accountingCloser = acc 855 856 pseudosettleService := pseudosettle.New(p2ps, logger, stateStore, acc, new(big.Int).Set(enforcedRefreshRate), big.NewInt(lightRefreshRate), p2ps) 857 if err = p2ps.AddProtocol(pseudosettleService.Protocol()); err != nil { 858 return nil, fmt.Errorf("pseudosettle service: %w", err) 859 } 860 861 acc.SetRefreshFunc(pseudosettleService.Pay) 862 863 if o.SwapEnable && chainEnabled { 864 var priceOracle priceoracle.Service 865 swapService, priceOracle, err = InitSwap( 866 p2ps, 867 logger, 868 stateStore, 869 networkID, 870 overlayEthAddress, 871 chequebookService, 872 chequeStore, 873 cashoutService, 874 acc, 875 o.PriceOracleAddress, 876 chainID, 877 transactionService, 878 ) 879 if err != nil { 880 return nil, err 881 } 882 b.priceOracleCloser = priceOracle 883 884 if o.ChequebookEnable { 885 acc.SetPayFunc(swapService.Pay) 886 } 887 } 888 889 pricing.SetPaymentThresholdObserver(acc) 890 891 pssService := pss.New(pssPrivateKey, logger) 892 b.pssCloser = pssService 893 894 validStamp := postage.ValidStamp(batchStore) 895 896 nodeStatus := status.NewService(logger, p2ps, kad, beeNodeMode.String(), batchStore, localStore) 897 if err = p2ps.AddProtocol(nodeStatus.Protocol()); err != nil { 898 return nil, fmt.Errorf("status service: %w", err) 899 } 900 901 saludService := salud.New(nodeStatus, kad, localStore, logger, warmupTime, api.FullMode.String(), salud.DefaultMinPeersPerBin, salud.DefaultDurPercentile, salud.DefaultConnsPercentile) 902 b.saludCloser = saludService 903 904 rC, unsub := saludService.SubscribeNetworkStorageRadius() 905 initialRadiusC := make(chan struct{}) 906 var networkR atomic.Uint32 907 networkR.Store(uint32(swarm.MaxBins)) 908 909 go func() { 910 for { 911 select { 912 case r := <-rC: 913 prev := networkR.Load() 914 networkR.Store(uint32(r)) 915 if prev == uint32(swarm.MaxBins) { 916 close(initialRadiusC) 917 } 918 if !o.FullNodeMode { // light and ultra-light nodes do not have a reserve worker to set the radius. 919 kad.SetStorageRadius(r) 920 } 921 case <-ctx.Done(): 922 unsub() 923 return 924 } 925 } 926 }() 927 928 waitNetworkRFunc := func() (uint8, error) { 929 if networkR.Load() == uint32(swarm.MaxBins) { 930 select { 931 case <-initialRadiusC: 932 case <-ctx.Done(): 933 return 0, ctx.Err() 934 } 935 } 936 937 local, network := localStore.StorageRadius(), uint8(networkR.Load()) 938 if local <= uint8(o.MinimumStorageRadius) { 939 return max(network, uint8(o.MinimumStorageRadius)), nil 940 } else { 941 return local, nil 942 } 943 } 944 945 pushSyncProtocol := pushsync.New(swarmAddress, networkID, nonce, p2ps, localStore, waitNetworkRFunc, kad, o.FullNodeMode, pssService.TryUnwrap, validStamp, logger, acc, pricer, signer, tracer, warmupTime) 946 b.pushSyncCloser = pushSyncProtocol 947 948 // set the pushSyncer in the PSS 949 pssService.SetPushSyncer(pushSyncProtocol) 950 951 retrieval := retrieval.New(swarmAddress, waitNetworkRFunc, localStore, p2ps, kad, logger, acc, pricer, tracer, o.RetrievalCaching) 952 localStore.SetRetrievalService(retrieval) 953 954 pusherService := pusher.New(networkID, localStore, pushSyncProtocol, validStamp, logger, warmupTime, pusher.DefaultRetryCount) 955 b.pusherCloser = pusherService 956 957 pusherService.AddFeed(localStore.PusherFeed()) 958 959 pullSyncProtocol := pullsync.New(p2ps, localStore, pssService.TryUnwrap, validStamp, logger, pullsync.DefaultMaxPage) 960 b.pullSyncCloser = pullSyncProtocol 961 962 retrieveProtocolSpec := retrieval.Protocol() 963 pushSyncProtocolSpec := pushSyncProtocol.Protocol() 964 pullSyncProtocolSpec := pullSyncProtocol.Protocol() 965 966 if o.FullNodeMode && !o.BootnodeMode { 967 logger.Info("starting in full mode") 968 } else { 969 if chainEnabled { 970 logger.Info("starting in light mode") 971 } else { 972 logger.Info("starting in ultra-light mode") 973 } 974 p2p.WithBlocklistStreams(p2p.DefaultBlocklistTime, retrieveProtocolSpec) 975 p2p.WithBlocklistStreams(p2p.DefaultBlocklistTime, pushSyncProtocolSpec) 976 p2p.WithBlocklistStreams(p2p.DefaultBlocklistTime, pullSyncProtocolSpec) 977 } 978 979 if err = p2ps.AddProtocol(retrieveProtocolSpec); err != nil { 980 return nil, fmt.Errorf("retrieval service: %w", err) 981 } 982 if err = p2ps.AddProtocol(pushSyncProtocolSpec); err != nil { 983 return nil, fmt.Errorf("pushsync service: %w", err) 984 } 985 if err = p2ps.AddProtocol(pullSyncProtocolSpec); err != nil { 986 return nil, fmt.Errorf("pullsync protocol: %w", err) 987 } 988 989 stakingContractAddress := chainCfg.StakingAddress 990 if o.StakingContractAddress != "" { 991 if !common.IsHexAddress(o.StakingContractAddress) { 992 return nil, errors.New("malformed staking contract address") 993 } 994 stakingContractAddress = common.HexToAddress(o.StakingContractAddress) 995 } 996 997 stakingContract := staking.New(overlayEthAddress, stakingContractAddress, abiutil.MustParseABI(chainCfg.StakingABI), bzzTokenAddress, transactionService, common.BytesToHash(nonce), o.TrxDebugMode) 998 999 if chainEnabled && changedOverlay { 1000 stake, err := stakingContract.GetPotentialStake(ctx) 1001 if err != nil { 1002 return nil, errors.New("getting stake balance") 1003 } 1004 if stake.Cmp(big.NewInt(0)) > 0 { 1005 logger.Debug("changing overlay address in staking contract") 1006 tx, err := stakingContract.ChangeStakeOverlay(ctx, common.BytesToHash(nonce)) 1007 if err != nil { 1008 return nil, fmt.Errorf("cannot change staking overlay address: %v", err.Error()) 1009 } 1010 logger.Info("overlay address changed in staking contract", "transaction", tx) 1011 } 1012 } 1013 1014 var ( 1015 pullerService *puller.Puller 1016 agent *storageincentives.Agent 1017 ) 1018 1019 if o.FullNodeMode && !o.BootnodeMode { 1020 pullerService = puller.New(swarmAddress, stateStore, kad, localStore, pullSyncProtocol, p2ps, logger, puller.Options{}) 1021 b.pullerCloser = pullerService 1022 1023 localStore.StartReserveWorker(ctx, pullerService, waitNetworkRFunc) 1024 nodeStatus.SetSync(pullerService) 1025 1026 if o.EnableStorageIncentives { 1027 1028 redistributionContractAddress := chainCfg.RedistributionAddress 1029 if o.RedistributionContractAddress != "" { 1030 if !common.IsHexAddress(o.RedistributionContractAddress) { 1031 return nil, errors.New("malformed redistribution contract address") 1032 } 1033 redistributionContractAddress = common.HexToAddress(o.RedistributionContractAddress) 1034 } 1035 1036 isFullySynced := func() bool { 1037 return localStore.ReserveSize() >= reserveTreshold && pullerService.SyncRate() == 0 1038 } 1039 1040 redistributionContract := redistribution.New(swarmAddress, overlayEthAddress, logger, transactionService, redistributionContractAddress, abiutil.MustParseABI(chainCfg.RedistributionABI), o.TrxDebugMode) 1041 agent, err = storageincentives.New( 1042 swarmAddress, 1043 overlayEthAddress, 1044 chainBackend, 1045 redistributionContract, 1046 postageStampContractService, 1047 stakingContract, 1048 localStore, 1049 isFullySynced, 1050 o.BlockTime, 1051 storageincentives.DefaultBlocksPerRound, 1052 storageincentives.DefaultBlocksPerPhase, 1053 stateStore, 1054 batchStore, 1055 erc20Service, 1056 transactionService, 1057 saludService, 1058 logger, 1059 ) 1060 if err != nil { 1061 return nil, fmt.Errorf("storage incentives agent: %w", err) 1062 } 1063 b.storageIncetivesCloser = agent 1064 } 1065 1066 } 1067 multiResolver := multiresolver.NewMultiResolver( 1068 multiresolver.WithConnectionConfigs(o.ResolverConnectionCfgs), 1069 multiresolver.WithLogger(o.Logger), 1070 multiresolver.WithDefaultCIDResolver(), 1071 ) 1072 b.resolverCloser = multiResolver 1073 1074 feedFactory := factory.New(localStore.Download(true)) 1075 steward := steward.New(localStore, retrieval, localStore.Cache()) 1076 1077 extraOpts := api.ExtraOptions{ 1078 Pingpong: pingPong, 1079 TopologyDriver: kad, 1080 LightNodes: lightNodes, 1081 Accounting: acc, 1082 Pseudosettle: pseudosettleService, 1083 Swap: swapService, 1084 Chequebook: chequebookService, 1085 BlockTime: o.BlockTime, 1086 Storer: localStore, 1087 Resolver: multiResolver, 1088 Pss: pssService, 1089 FeedFactory: feedFactory, 1090 Post: post, 1091 AccessControl: accesscontrol, 1092 PostageContract: postageStampContractService, 1093 Staking: stakingContract, 1094 Steward: steward, 1095 SyncStatus: syncStatusFn, 1096 NodeStatus: nodeStatus, 1097 PinIntegrity: localStore.PinIntegrity(), 1098 } 1099 1100 if o.APIAddr != "" { 1101 // register metrics from components 1102 apiService.MustRegisterMetrics(p2ps.Metrics()...) 1103 apiService.MustRegisterMetrics(pingPong.Metrics()...) 1104 apiService.MustRegisterMetrics(acc.Metrics()...) 1105 apiService.MustRegisterMetrics(localStore.Metrics()...) 1106 apiService.MustRegisterMetrics(kad.Metrics()...) 1107 apiService.MustRegisterMetrics(saludService.Metrics()...) 1108 apiService.MustRegisterMetrics(stateStoreMetrics.Metrics()...) 1109 1110 if pullerService != nil { 1111 apiService.MustRegisterMetrics(pullerService.Metrics()...) 1112 } 1113 1114 if agent != nil { 1115 apiService.MustRegisterMetrics(agent.Metrics()...) 1116 } 1117 1118 apiService.MustRegisterMetrics(pushSyncProtocol.Metrics()...) 1119 apiService.MustRegisterMetrics(pusherService.Metrics()...) 1120 apiService.MustRegisterMetrics(pullSyncProtocol.Metrics()...) 1121 apiService.MustRegisterMetrics(retrieval.Metrics()...) 1122 apiService.MustRegisterMetrics(lightNodes.Metrics()...) 1123 apiService.MustRegisterMetrics(hive.Metrics()...) 1124 1125 if bs, ok := batchStore.(metrics.Collector); ok { 1126 apiService.MustRegisterMetrics(bs.Metrics()...) 1127 } 1128 if ls, ok := eventListener.(metrics.Collector); ok { 1129 apiService.MustRegisterMetrics(ls.Metrics()...) 1130 } 1131 if pssServiceMetrics, ok := pssService.(metrics.Collector); ok { 1132 apiService.MustRegisterMetrics(pssServiceMetrics.Metrics()...) 1133 } 1134 if swapBackendMetrics, ok := chainBackend.(metrics.Collector); ok { 1135 apiService.MustRegisterMetrics(swapBackendMetrics.Metrics()...) 1136 } 1137 1138 if l, ok := logger.(metrics.Collector); ok { 1139 apiService.MustRegisterMetrics(l.Metrics()...) 1140 } 1141 apiService.MustRegisterMetrics(pseudosettleService.Metrics()...) 1142 if swapService != nil { 1143 apiService.MustRegisterMetrics(swapService.Metrics()...) 1144 } 1145 1146 apiService.Configure(signer, tracer, api.Options{ 1147 CORSAllowedOrigins: o.CORSAllowedOrigins, 1148 WsPingPeriod: 60 * time.Second, 1149 }, extraOpts, chainID, erc20Service) 1150 1151 apiService.MountDebug() 1152 apiService.MountAPI() 1153 1154 apiService.SetSwarmAddress(&swarmAddress) 1155 apiService.SetRedistributionAgent(agent) 1156 } 1157 1158 if err := kad.Start(ctx); err != nil { 1159 return nil, err 1160 } 1161 1162 if err := p2ps.Ready(); err != nil { 1163 return nil, err 1164 } 1165 1166 return b, nil 1167 } 1168 1169 func (b *Bee) SyncingStopped() chan struct{} { 1170 return b.syncingStopped.C 1171 } 1172 1173 func (b *Bee) Shutdown() error { 1174 var mErr error 1175 1176 // if a shutdown is already in process, return here 1177 b.shutdownMutex.Lock() 1178 if b.shutdownInProgress { 1179 b.shutdownMutex.Unlock() 1180 return ErrShutdownInProgress 1181 } 1182 b.shutdownInProgress = true 1183 b.shutdownMutex.Unlock() 1184 1185 // halt kademlia while shutting down other 1186 // components. 1187 if b.topologyHalter != nil { 1188 b.topologyHalter.Halt() 1189 } 1190 1191 // halt p2p layer from accepting new connections 1192 // while shutting down other components 1193 if b.p2pHalter != nil { 1194 b.p2pHalter.Halt() 1195 } 1196 // tryClose is a convenient closure which decrease 1197 // repetitive io.Closer tryClose procedure. 1198 tryClose := func(c io.Closer, errMsg string) { 1199 if c == nil { 1200 return 1201 } 1202 if err := c.Close(); err != nil { 1203 mErr = multierror.Append(mErr, fmt.Errorf("%s: %w", errMsg, err)) 1204 } 1205 } 1206 1207 tryClose(b.apiCloser, "api") 1208 1209 ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) 1210 defer cancel() 1211 1212 var eg errgroup.Group 1213 if b.apiServer != nil { 1214 eg.Go(func() error { 1215 if err := b.apiServer.Shutdown(ctx); err != nil { 1216 return fmt.Errorf("api server: %w", err) 1217 } 1218 return nil 1219 }) 1220 } 1221 if err := eg.Wait(); err != nil { 1222 mErr = multierror.Append(mErr, err) 1223 } 1224 1225 var wg sync.WaitGroup 1226 wg.Add(7) 1227 go func() { 1228 defer wg.Done() 1229 tryClose(b.pssCloser, "pss") 1230 }() 1231 go func() { 1232 defer wg.Done() 1233 tryClose(b.pusherCloser, "pusher") 1234 }() 1235 go func() { 1236 defer wg.Done() 1237 tryClose(b.pullerCloser, "puller") 1238 }() 1239 go func() { 1240 defer wg.Done() 1241 tryClose(b.accountingCloser, "accounting") 1242 }() 1243 1244 b.ctxCancel() 1245 go func() { 1246 defer wg.Done() 1247 tryClose(b.pullSyncCloser, "pull sync") 1248 }() 1249 go func() { 1250 defer wg.Done() 1251 tryClose(b.hiveCloser, "hive") 1252 }() 1253 go func() { 1254 defer wg.Done() 1255 tryClose(b.saludCloser, "salud") 1256 }() 1257 1258 wg.Wait() 1259 1260 tryClose(b.p2pService, "p2p server") 1261 tryClose(b.priceOracleCloser, "price oracle service") 1262 1263 wg.Add(3) 1264 go func() { 1265 defer wg.Done() 1266 tryClose(b.transactionMonitorCloser, "transaction monitor") 1267 tryClose(b.transactionCloser, "transaction") 1268 }() 1269 go func() { 1270 defer wg.Done() 1271 tryClose(b.listenerCloser, "listener") 1272 }() 1273 go func() { 1274 defer wg.Done() 1275 tryClose(b.postageServiceCloser, "postage service") 1276 }() 1277 1278 wg.Wait() 1279 1280 if c := b.ethClientCloser; c != nil { 1281 c() 1282 } 1283 1284 tryClose(b.accesscontrolCloser, "accesscontrol") 1285 tryClose(b.tracerCloser, "tracer") 1286 tryClose(b.topologyCloser, "topology driver") 1287 tryClose(b.storageIncetivesCloser, "storage incentives agent") 1288 tryClose(b.stateStoreCloser, "statestore") 1289 tryClose(b.stamperStoreCloser, "stamperstore") 1290 tryClose(b.localstoreCloser, "localstore") 1291 tryClose(b.resolverCloser, "resolver service") 1292 1293 return mErr 1294 } 1295 1296 var ErrShutdownInProgress error = errors.New("shutdown in progress") 1297 1298 func isChainEnabled(o *Options, swapEndpoint string, logger log.Logger) bool { 1299 chainDisabled := swapEndpoint == "" 1300 lightMode := !o.FullNodeMode 1301 1302 if lightMode && chainDisabled { // ultra light mode is LightNode mode with chain disabled 1303 logger.Info("starting with a disabled chain backend") 1304 return false 1305 } 1306 1307 logger.Info("starting with an enabled chain backend") 1308 return true // all other modes operate require chain enabled 1309 }