From e386677459c1509017d711031a0606182057c312 Mon Sep 17 00:00:00 2001 From: Calin Martinconi Date: Thu, 9 Apr 2026 12:56:27 +0300 Subject: [PATCH 1/3] refactor: replace full-node flag with explicit node-mode config --- cmd/bee/cmd/cmd.go | 13 +- cmd/bee/cmd/start.go | 53 +++++++- packaging/bee.yaml | 216 +++++++++++++++++------------- packaging/homebrew-amd64/bee.yaml | 216 +++++++++++++++++------------- packaging/homebrew-arm64/bee.yaml | 216 +++++++++++++++++------------- packaging/scoop/bee.yaml | 216 +++++++++++++++++------------- pkg/node/node.go | 70 ++++++---- 7 files changed, 580 insertions(+), 420 deletions(-) diff --git a/cmd/bee/cmd/cmd.go b/cmd/bee/cmd/cmd.go index 37542a7bd38..8eb9a631a52 100644 --- a/cmd/bee/cmd/cmd.go +++ b/cmd/bee/cmd/cmd.go @@ -52,9 +52,10 @@ const ( optionNameBootnodeMode = "bootnode-mode" optionNameSwapFactoryAddress = "swap-factory-address" optionNameSwapInitialDeposit = "swap-initial-deposit" + optionNameNodeMode = "node-mode" optionNameSwapEnable = "swap-enable" optionNameChequebookEnable = "chequebook-enable" - optionNameFullNode = "full-node" + optionNameFullNode = "full-node" // Deprecated: use node-mode instead. optionNamePostageContractAddress = "postage-stamp-address" optionNamePostageContractStartBlock = "postage-stamp-start-block" optionNamePriceOracleAddress = "price-oracle-address" @@ -304,9 +305,13 @@ func (c *command) setAllFlags(cmd *cobra.Command) { cmd.Flags().Duration(optionNameBlockchainRpcKeepalive, 30*time.Second, "blockchain rpc TCP keepalive interval") cmd.Flags().String(optionNameSwapFactoryAddress, "", "swap factory addresses") cmd.Flags().String(optionNameSwapInitialDeposit, "0", "initial deposit if deploying a new chequebook") + cmd.Flags().String(optionNameNodeMode, string(node.UltraLightMode), "node operational mode: full, light, or ultra-light") cmd.Flags().Bool(optionNameSwapEnable, false, "enable swap") - cmd.Flags().Bool(optionNameChequebookEnable, true, "enable chequebook") - cmd.Flags().Bool(optionNameFullNode, false, "cause the node to start in full mode") + cmd.Flags().Bool(optionNameChequebookEnable, false, "enable chequebook (requires swap-enable)") + cmd.Flags().Bool(optionNameFullNode, false, "cause the node to start in full mode (deprecated: use --node-mode=full)") + if err := cmd.Flags().MarkDeprecated(optionNameFullNode, "use --node-mode=full instead"); err != nil { + panic(err) + } cmd.Flags().String(optionNamePostageContractAddress, "", "postage stamp contract address") cmd.Flags().Uint64(optionNamePostageContractStartBlock, 0, "postage stamp contract start block number") cmd.Flags().String(optionNamePriceOracleAddress, "", "price oracle contract address") @@ -322,7 +327,7 @@ func (c *command) setAllFlags(cmd *cobra.Command) { cmd.Flags().Bool(optionNamePProfMutex, false, "enable pprof mutex profile") cmd.Flags().StringSlice(optionNameStaticNodes, []string{}, "protect nodes from getting kicked out on bootnode") cmd.Flags().Bool(optionNameAllowPrivateCIDRs, false, "allow to advertise private CIDRs to the public network") - cmd.Flags().Bool(optionNameStorageIncentivesEnable, true, "enable storage incentives feature") + cmd.Flags().Bool(optionNameStorageIncentivesEnable, false, "enable storage incentives feature (full node only)") cmd.Flags().Uint64(optionNameStateStoreCacheCapacity, 100_000, "lru memory caching capacity in number of statestore entries") cmd.Flags().String(optionNameTargetNeighborhood, "", "neighborhood to target in binary format (ex: 111111001) for mining the initial overlay") cmd.Flags().String(optionNameNeighborhoodSuggester, "https://api.swarmscan.io/v1/network/neighborhoods/suggestion", "suggester for target neighborhood") diff --git a/cmd/bee/cmd/start.go b/cmd/bee/cmd/start.go index 5773c4af3e3..9dc382d8f93 100644 --- a/cmd/bee/cmd/start.go +++ b/cmd/bee/cmd/start.go @@ -204,9 +204,13 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo } bootNode := c.config.GetBool(optionNameBootnodeMode) - fullNode := c.config.GetBool(optionNameFullNode) - if bootNode && !fullNode { + nodeMode, err := c.resolveNodeMode(logger) + if err != nil { + return nil, err + } + + if bootNode && nodeMode != node.FullMode { return nil, errors.New("boot node must be started as a full node") } @@ -297,7 +301,7 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo EnableWS: c.config.GetBool(optionNameP2PWSEnable), AutoTLSDomain: c.config.GetString(optionAutoTLSDomain), AutoTLSRegistrationEndpoint: c.config.GetString(optionAutoTLSRegistrationEndpoint), - FullNodeMode: fullNode, + NodeMode: nodeMode, Logger: logger, MinimumGasTipCap: c.config.GetUint64(optionNameMinimumGasTipCap), GasLimitFallback: c.config.GetUint64(optionNameGasLimitFallback), @@ -337,6 +341,49 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo return b, err } +// resolveNodeMode determines the effective node mode from config. +// --node-mode takes precedence; the deprecated --full-node flag is honoured as a fallback. +// It also validates that the required options for each mode are present. +func (c *command) resolveNodeMode(logger log.Logger) (node.NodeMode, error) { + rpcEndpoint := c.config.GetString(configKeyBlockchainRpcEndpoint) + swapEnable := c.config.GetBool(optionNameSwapEnable) + + // Resolve the mode: explicit node-mode wins, then legacy full-node, then default ultra-light. + var mode node.NodeMode + if c.config.IsSet(optionNameNodeMode) { + mode = node.NodeMode(c.config.GetString(optionNameNodeMode)) + if !mode.IsValid() { + return "", fmt.Errorf("invalid node-mode %q: must be one of full, light, ultra-light", mode) + } + } else if c.config.GetBool(optionNameFullNode) { + logger.Warning("--full-node is deprecated, use --node-mode=full instead") + mode = node.FullMode + } else { + mode = node.UltraLightMode + } + + // Validate mode-specific requirements. + switch mode { + case node.FullMode: + if rpcEndpoint == "" { + return "", errors.New("full node requires blockchain-rpc-endpoint to be set") + } + if !swapEnable { + return "", errors.New("full node requires swap-enable to be true") + } + case node.LightMode: + if rpcEndpoint == "" { + return "", errors.New("light node requires blockchain-rpc-endpoint to be set") + } + case node.UltraLightMode: + if swapEnable { + return "", errors.New("ultra-light node cannot have swap-enable set to true") + } + } + + return mode, nil +} + type program struct { start func() stop func() diff --git a/packaging/bee.yaml b/packaging/bee.yaml index ef04fb716c6..d90ce63c2a1 100644 --- a/packaging/bee.yaml +++ b/packaging/bee.yaml @@ -1,13 +1,13 @@ ## Bee configuration - https://docs.ethswarm.org/docs/working-with-bee/configuration -## allow to advertise private CIDRs to the public network -# allow-private-cidrs: false -## HTTP API listen address -# api-addr: 127.0.0.1:1633 -## chain block time -# block-time: "5" -## block number cache sync interval in blocks -# block-sync-interval: 10 +## ── Node mode ──────────────────────────────────────────────────────────────── +## Selects the operational mode of this node. +## full - participates in storage and incentives; requires swap-enable and blockchain-rpc +## light - uploads and downloads only; requires blockchain-rpc +## ultra-light - free-tier downloads only; no blockchain connection needed (default) +# node-mode: ultra-light + +## ── Blockchain / RPC (required for full and light nodes) ───────────────────── ## blockchain rpc configuration # blockchain-rpc: # endpoint: "" @@ -15,22 +15,96 @@ # tls-timeout: 10s # idle-timeout: 90s # keepalive: 30s +## chain block time +# block-time: "5" +## block number cache sync interval in blocks +# block-sync-interval: 10 + +## ── Swap / chequebook (full and light nodes only) ──────────────────────────── +## enable swap +# swap-enable: false +## enable chequebook +# chequebook-enable: false +## swap factory addresses +# swap-factory-address: "" +## initial deposit if deploying a new chequebook +# swap-initial-deposit: "0" + +## ── Full node only ──────────────────────────────────────────────────────────── +## enable storage incentives feature +# storage-incentives-enable: false +## reserve capacity doubling +# reserve-capacity-doubling: 0 +## minimum radius storage threshold +# minimum-storage-radius: "0" +## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay +# target-neighborhood: "" +## suggester for target neighborhood +# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion +## redistribution contract address +# redistribution-address: "" +## staking contract address +# staking-address: "" + +## ── Network ─────────────────────────────────────────────────────────────────── +## triggers connect to main net bootnodes +# mainnet: true +## ID of the Swarm network +# network-id: "1" ## initial nodes to connect to # bootnode: ["/dnsaddr/mainnet.ethswarm.org"] ## cause the node to always accept incoming connections # bootnode-mode: false -## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes -# cache-capacity: "1000000" -## enable forwarded content caching -# cache-retrieval: true -## enable chequebook -# chequebook-enable: true -## config file (default is $HOME/.bee.yaml) -config: "/etc/bee/bee.yaml" +## protect nodes from getting kicked out on bootnode +# static-nodes: [] +## P2P listen address +# p2p-addr: :1634 +## enable P2P WebSocket transport +# p2p-ws-enable: false +## enable wss p2p connections +# p2p-wss-enable: false +## wss address +# p2p-wss-addr: :1635 +## NAT exposed address +# nat-addr: "" +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain +# autotls-domain: "" +## autotls registration endpoint +# autotls-registration-endpoint: "" +## autotls ca endpoint +# autotls-ca-endpoint: "" +## allow to advertise private CIDRs to the public network +# allow-private-cidrs: false + +## ── HTTP API ────────────────────────────────────────────────────────────────── +## HTTP API listen address +# api-addr: 127.0.0.1:1633 ## origins with CORS headers enabled # cors-allowed-origins: [] + +## ── Storage ─────────────────────────────────────────────────────────────────── ## data directory data-dir: "/var/lib/bee" +## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes +# cache-capacity: "1000000" +## enable forwarded content caching +# cache-retrieval: true +## postage stamp contract address +# postage-stamp-address: "" +## postage stamp contract start block number +# postage-stamp-start-block: "0" +## skip postage snapshot +# skip-postage-snapshot: false +## forces the node to resync postage contract data +# resync: false +## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url +# resolver-options: [] +## price oracle contract address +# price-oracle-address: "" + +## ── Database ────────────────────────────────────────────────────────────────── ## size of block cache of the database in bytes # db-block-cache-capacity: "33554432" ## disables db compactions triggered by seeks @@ -39,72 +113,36 @@ data-dir: "/var/lib/bee" # db-open-files-limit: "200" ## size of the database write buffer in bytes # db-write-buffer-size: "33554432" -## cause the node to start in full mode -# full-node: false -## help for printconfig -# help: false -## triggers connect to main net bootnodes. -# mainnet: true +## lru memory caching capacity in number of statestore entries +# statestore-cache-capacity: "100000" + +## ── Payments ────────────────────────────────────────────────────────────────── +## threshold in BZZ where you expect to get paid from your peers +# payment-threshold: "13500000" +## percentage below the peers payment threshold when we initiate settlement +# payment-early-percent: 50 +## excess debt above payment threshold in percentages where you disconnect from your peer +# payment-tolerance-percent: 25 ## minimum gas tip cap in wei for transactions, 0 means use suggested gas tip cap # minimum-gas-tip-cap: 0 -## minimum radius storage threshold -# minimum-storage-radius: "0" -## NAT exposed address -# nat-addr: "" -## suggester for target neighborhood -# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion -## ID of the Swarm network -# network-id: "1" -## P2P listen address -# p2p-addr: :1634 -## enable P2P WebSocket transport -# p2p-ws-enable: false +## gas limit fallback when estimation fails for contract transactions (default 500000) +# gas-limit-fallback: 500000 +## skips the gas estimate step for contract transactions +# transaction-debug-mode: false +## withdrawal target addresses +# withdrawal-addresses-whitelist: [] + +## ── Keys / identity ─────────────────────────────────────────────────────────── +## config file (default is $HOME/.bee.yaml) +config: "/etc/bee/bee.yaml" ## password for decrypting keys # password: "" ## path to a file that contains password for decrypting keys password-file: "/var/lib/bee/password" -## percentage below the peers payment threshold when we initiate settlement -# payment-early-percent: 50 -## threshold in BZZ where you expect to get paid from your peers -# payment-threshold: "13500000" -## excess debt above payment threshold in percentages where you disconnect from your peer -# payment-tolerance-percent: 25 -## postage stamp contract address -# postage-stamp-address: "" -## postage stamp contract start block number -# postage-stamp-start-block: "0" -## enable pprof mutex profile -# pprof-mutex: false -## enable pprof block profile -# pprof-profile: false -## price oracle contract address -# price-oracle-address: "" -## redistribution contract address -# redistribution-address: "" -## reserve capacity doubling -# reserve-capacity-doubling: 0 -## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url -# resolver-options: [] -## forces the node to resync postage contract data -# resync: false -## skip postage snapshot -# skip-postage-snapshot: false -## staking contract address -# staking-address: "" -## lru memory caching capacity in number of statestore entries -# statestore-cache-capacity: "100000" -## protect nodes from getting kicked out on bootnode -# static-nodes: [] -## enable storage incentives feature -# storage-incentives-enable: true -## enable swap -# swap-enable: false -## swap factory addresses -# swap-factory-address: "" -## initial deposit if deploying a new chequebook -# swap-initial-deposit: "0" -## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay -# target-neighborhood: "" + +## ── Logging / tracing ───────────────────────────────────────────────────────── +## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace +# verbosity: info ## enable tracing # tracing-enable: false ## endpoint to send tracing data @@ -115,27 +153,13 @@ password-file: "/var/lib/bee/password" # tracing-port: "" ## service name identifier for tracing # tracing-service-name: bee -## gas limit fallback when estimation fails for contract transactions (default 500000) -# gas-limit-fallback: 500000 -## skips the gas estimate step for contract transactions -# transaction-debug-mode: false -## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace -# verbosity: info +## enable pprof mutex profile +# pprof-mutex: false +## enable pprof block profile +# pprof-profile: false + +## ── Miscellaneous ───────────────────────────────────────────────────────────── ## maximum node warmup duration; proceeds when stable or after this time # warmup-time: 5m0s ## send a welcome message string during handshakes # welcome-message: "" -## withdrawal target addresses -# withdrawal-addresses-whitelist: [] -## enable wss p2p connections (default: false) -# p2p-wss-enable: false -## wss address (default: :1635) -# p2p-wss-addr: :1635 -## WSS NAT exposed address -# nat-wss-addr: "" -## autotls domain (default: libp2p.direct) -# autotls-domain: "" -## autotls registration endpoint (default: https://registration.libp2p.direct) -# autotls-registration-endpoint: "" -## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) -# autotls-ca-endpoint: "" diff --git a/packaging/homebrew-amd64/bee.yaml b/packaging/homebrew-amd64/bee.yaml index 2aac12016fe..1258eee70b8 100644 --- a/packaging/homebrew-amd64/bee.yaml +++ b/packaging/homebrew-amd64/bee.yaml @@ -1,13 +1,13 @@ ## Bee configuration - https://docs.ethswarm.org/docs/working-with-bee/configuration -## allow to advertise private CIDRs to the public network -# allow-private-cidrs: false -## HTTP API listen address -# api-addr: 127.0.0.1:1633 -## chain block time -# block-time: "5" -## block number cache sync interval in blocks -# block-sync-interval: 10 +## ── Node mode ──────────────────────────────────────────────────────────────── +## Selects the operational mode of this node. +## full - participates in storage and incentives; requires swap-enable and blockchain-rpc +## light - uploads and downloads only; requires blockchain-rpc +## ultra-light - free-tier downloads only; no blockchain connection needed (default) +# node-mode: ultra-light + +## ── Blockchain / RPC (required for full and light nodes) ───────────────────── ## blockchain rpc configuration # blockchain-rpc: # endpoint: "" @@ -15,22 +15,96 @@ # tls-timeout: 10s # idle-timeout: 90s # keepalive: 30s +## chain block time +# block-time: "5" +## block number cache sync interval in blocks +# block-sync-interval: 10 + +## ── Swap / chequebook (full and light nodes only) ──────────────────────────── +## enable swap +# swap-enable: false +## enable chequebook +# chequebook-enable: false +## swap factory addresses +# swap-factory-address: "" +## initial deposit if deploying a new chequebook +# swap-initial-deposit: "0" + +## ── Full node only ──────────────────────────────────────────────────────────── +## enable storage incentives feature +# storage-incentives-enable: false +## reserve capacity doubling +# reserve-capacity-doubling: 0 +## minimum radius storage threshold +# minimum-storage-radius: "0" +## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay +# target-neighborhood: "" +## suggester for target neighborhood +# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion +## redistribution contract address +# redistribution-address: "" +## staking contract address +# staking-address: "" + +## ── Network ─────────────────────────────────────────────────────────────────── +## triggers connect to main net bootnodes +# mainnet: true +## ID of the Swarm network +# network-id: "1" ## initial nodes to connect to # bootnode: ["/dnsaddr/mainnet.ethswarm.org"] ## cause the node to always accept incoming connections # bootnode-mode: false -## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes -# cache-capacity: "1000000" -## enable forwarded content caching -# cache-retrieval: true -## enable chequebook -# chequebook-enable: true -## config file (default is $HOME/.bee.yaml) -config: "/usr/local/etc/swarm-bee/bee.yaml" +## protect nodes from getting kicked out on bootnode +# static-nodes: [] +## P2P listen address +# p2p-addr: :1634 +## enable P2P WebSocket transport +# p2p-ws-enable: false +## enable wss p2p connections +# p2p-wss-enable: false +## wss address +# p2p-wss-addr: :1635 +## NAT exposed address +# nat-addr: "" +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain +# autotls-domain: "" +## autotls registration endpoint +# autotls-registration-endpoint: "" +## autotls ca endpoint +# autotls-ca-endpoint: "" +## allow to advertise private CIDRs to the public network +# allow-private-cidrs: false + +## ── HTTP API ────────────────────────────────────────────────────────────────── +## HTTP API listen address +# api-addr: 127.0.0.1:1633 ## origins with CORS headers enabled # cors-allowed-origins: [] + +## ── Storage ─────────────────────────────────────────────────────────────────── ## data directory data-dir: "/usr/local/var/lib/swarm-bee" +## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes +# cache-capacity: "1000000" +## enable forwarded content caching +# cache-retrieval: true +## postage stamp contract address +# postage-stamp-address: "" +## postage stamp contract start block number +# postage-stamp-start-block: "0" +## skip postage snapshot +# skip-postage-snapshot: false +## forces the node to resync postage contract data +# resync: false +## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url +# resolver-options: [] +## price oracle contract address +# price-oracle-address: "" + +## ── Database ────────────────────────────────────────────────────────────────── ## size of block cache of the database in bytes # db-block-cache-capacity: "33554432" ## disables db compactions triggered by seeks @@ -39,72 +113,36 @@ data-dir: "/usr/local/var/lib/swarm-bee" # db-open-files-limit: "200" ## size of the database write buffer in bytes # db-write-buffer-size: "33554432" -## cause the node to start in full mode -# full-node: false -## help for printconfig -# help: false -## triggers connect to main net bootnodes. -# mainnet: true +## lru memory caching capacity in number of statestore entries +# statestore-cache-capacity: "100000" + +## ── Payments ────────────────────────────────────────────────────────────────── +## threshold in BZZ where you expect to get paid from your peers +# payment-threshold: "13500000" +## percentage below the peers payment threshold when we initiate settlement +# payment-early-percent: 50 +## excess debt above payment threshold in percentages where you disconnect from your peer +# payment-tolerance-percent: 25 ## minimum gas tip cap in wei for transactions, 0 means use suggested gas tip cap # minimum-gas-tip-cap: 0 -## minimum radius storage threshold -# minimum-storage-radius: "0" -## NAT exposed address -# nat-addr: "" -## suggester for target neighborhood -# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion -## ID of the Swarm network -# network-id: "1" -## P2P listen address -# p2p-addr: :1634 -## enable P2P WebSocket transport -# p2p-ws-enable: false +## gas limit fallback when estimation fails for contract transactions (default 500000) +# gas-limit-fallback: 500000 +## skips the gas estimate step for contract transactions +# transaction-debug-mode: false +## withdrawal target addresses +# withdrawal-addresses-whitelist: [] + +## ── Keys / identity ─────────────────────────────────────────────────────────── +## config file (default is $HOME/.bee.yaml) +config: "/usr/local/etc/swarm-bee/bee.yaml" ## password for decrypting keys # password: "" ## path to a file that contains password for decrypting keys password-file: "/usr/local/var/lib/swarm-bee/password" -## percentage below the peers payment threshold when we initiate settlement -# payment-early-percent: 50 -## threshold in BZZ where you expect to get paid from your peers -# payment-threshold: "13500000" -## excess debt above payment threshold in percentages where you disconnect from your peer -# payment-tolerance-percent: 25 -## postage stamp contract address -# postage-stamp-address: "" -## postage stamp contract start block number -# postage-stamp-start-block: "0" -## enable pprof mutex profile -# pprof-mutex: false -## enable pprof block profile -# pprof-profile: false -## price oracle contract address -# price-oracle-address: "" -## redistribution contract address -# redistribution-address: "" -## reserve capacity doubling -# reserve-capacity-doubling: 0 -## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url -# resolver-options: [] -## forces the node to resync postage contract data -# resync: false -## skip postage snapshot -# skip-postage-snapshot: false -## staking contract address -# staking-address: "" -## lru memory caching capacity in number of statestore entries -# statestore-cache-capacity: "100000" -## protect nodes from getting kicked out on bootnode -# static-nodes: [] -## enable storage incentives feature -# storage-incentives-enable: true -## enable swap -# swap-enable: false -## swap factory addresses -# swap-factory-address: "" -## initial deposit if deploying a new chequebook -# swap-initial-deposit: "0" -## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay -# target-neighborhood: "" + +## ── Logging / tracing ───────────────────────────────────────────────────────── +## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace +# verbosity: info ## enable tracing # tracing-enable: false ## endpoint to send tracing data @@ -115,27 +153,13 @@ password-file: "/usr/local/var/lib/swarm-bee/password" # tracing-port: "" ## service name identifier for tracing # tracing-service-name: bee -## gas limit fallback when estimation fails for contract transactions (default 500000) -# gas-limit-fallback: 500000 -## skips the gas estimate step for contract transactions -# transaction-debug-mode: false -## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace -# verbosity: info +## enable pprof mutex profile +# pprof-mutex: false +## enable pprof block profile +# pprof-profile: false + +## ── Miscellaneous ───────────────────────────────────────────────────────────── ## maximum node warmup duration; proceeds when stable or after this time # warmup-time: 5m0s ## send a welcome message string during handshakes # welcome-message: "" -## withdrawal target addresses -# withdrawal-addresses-whitelist: [] -## enable wss p2p connections (default: false) -# p2p-wss-enable: false -## wss address (default: :1635) -# p2p-wss-addr: :1635 -## WSS NAT exposed address -# nat-wss-addr: "" -## autotls domain (default: libp2p.direct) -# autotls-domain: "" -## autotls registration endpoint (default: https://registration.libp2p.direct) -# autotls-registration-endpoint: "" -## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) -# autotls-ca-endpoint: "" diff --git a/packaging/homebrew-arm64/bee.yaml b/packaging/homebrew-arm64/bee.yaml index f812f395f07..5734d6eb924 100644 --- a/packaging/homebrew-arm64/bee.yaml +++ b/packaging/homebrew-arm64/bee.yaml @@ -1,13 +1,13 @@ ## Bee configuration - https://docs.ethswarm.org/docs/working-with-bee/configuration -## allow to advertise private CIDRs to the public network -# allow-private-cidrs: false -## HTTP API listen address -# api-addr: 127.0.0.1:1633 -## chain block time -# block-time: "5" -## block number cache sync interval in blocks -# block-sync-interval: 10 +## ── Node mode ──────────────────────────────────────────────────────────────── +## Selects the operational mode of this node. +## full - participates in storage and incentives; requires swap-enable and blockchain-rpc +## light - uploads and downloads only; requires blockchain-rpc +## ultra-light - free-tier downloads only; no blockchain connection needed (default) +# node-mode: ultra-light + +## ── Blockchain / RPC (required for full and light nodes) ───────────────────── ## blockchain rpc configuration # blockchain-rpc: # endpoint: "" @@ -15,22 +15,96 @@ # tls-timeout: 10s # idle-timeout: 90s # keepalive: 30s +## chain block time +# block-time: "5" +## block number cache sync interval in blocks +# block-sync-interval: 10 + +## ── Swap / chequebook (full and light nodes only) ──────────────────────────── +## enable swap +# swap-enable: false +## enable chequebook +# chequebook-enable: false +## swap factory addresses +# swap-factory-address: "" +## initial deposit if deploying a new chequebook +# swap-initial-deposit: "0" + +## ── Full node only ──────────────────────────────────────────────────────────── +## enable storage incentives feature +# storage-incentives-enable: false +## reserve capacity doubling +# reserve-capacity-doubling: 0 +## minimum radius storage threshold +# minimum-storage-radius: "0" +## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay +# target-neighborhood: "" +## suggester for target neighborhood +# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion +## redistribution contract address +# redistribution-address: "" +## staking contract address +# staking-address: "" + +## ── Network ─────────────────────────────────────────────────────────────────── +## triggers connect to main net bootnodes +# mainnet: true +## ID of the Swarm network +# network-id: "1" ## initial nodes to connect to # bootnode: ["/dnsaddr/mainnet.ethswarm.org"] ## cause the node to always accept incoming connections # bootnode-mode: false -## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes -# cache-capacity: "1000000" -## enable forwarded content caching -# cache-retrieval: true -## enable chequebook -# chequebook-enable: true -## config file (default is $HOME/.bee.yaml) -config: "/opt/homebrew/etc/swarm-bee/bee.yaml" +## protect nodes from getting kicked out on bootnode +# static-nodes: [] +## P2P listen address +# p2p-addr: :1634 +## enable P2P WebSocket transport +# p2p-ws-enable: false +## enable wss p2p connections +# p2p-wss-enable: false +## wss address +# p2p-wss-addr: :1635 +## NAT exposed address +# nat-addr: "" +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain +# autotls-domain: "" +## autotls registration endpoint +# autotls-registration-endpoint: "" +## autotls ca endpoint +# autotls-ca-endpoint: "" +## allow to advertise private CIDRs to the public network +# allow-private-cidrs: false + +## ── HTTP API ────────────────────────────────────────────────────────────────── +## HTTP API listen address +# api-addr: 127.0.0.1:1633 ## origins with CORS headers enabled # cors-allowed-origins: [] + +## ── Storage ─────────────────────────────────────────────────────────────────── ## data directory data-dir: "/opt/homebrew/var/lib/swarm-bee" +## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes +# cache-capacity: "1000000" +## enable forwarded content caching +# cache-retrieval: true +## postage stamp contract address +# postage-stamp-address: "" +## postage stamp contract start block number +# postage-stamp-start-block: "0" +## skip postage snapshot +# skip-postage-snapshot: false +## forces the node to resync postage contract data +# resync: false +## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url +# resolver-options: [] +## price oracle contract address +# price-oracle-address: "" + +## ── Database ────────────────────────────────────────────────────────────────── ## size of block cache of the database in bytes # db-block-cache-capacity: "33554432" ## disables db compactions triggered by seeks @@ -39,72 +113,36 @@ data-dir: "/opt/homebrew/var/lib/swarm-bee" # db-open-files-limit: "200" ## size of the database write buffer in bytes # db-write-buffer-size: "33554432" -## cause the node to start in full mode -# full-node: false -## help for printconfig -# help: false -## triggers connect to main net bootnodes. -# mainnet: true +## lru memory caching capacity in number of statestore entries +# statestore-cache-capacity: "100000" + +## ── Payments ────────────────────────────────────────────────────────────────── +## threshold in BZZ where you expect to get paid from your peers +# payment-threshold: "13500000" +## percentage below the peers payment threshold when we initiate settlement +# payment-early-percent: 50 +## excess debt above payment threshold in percentages where you disconnect from your peer +# payment-tolerance-percent: 25 ## minimum gas tip cap in wei for transactions, 0 means use suggested gas tip cap # minimum-gas-tip-cap: 0 -## minimum radius storage threshold -# minimum-storage-radius: "0" -## NAT exposed address -# nat-addr: "" -## suggester for target neighborhood -# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion -## ID of the Swarm network -# network-id: "1" -## P2P listen address -# p2p-addr: :1634 -## enable P2P WebSocket transport -# p2p-ws-enable: false +## gas limit fallback when estimation fails for contract transactions (default 500000) +# gas-limit-fallback: 500000 +## skips the gas estimate step for contract transactions +# transaction-debug-mode: false +## withdrawal target addresses +# withdrawal-addresses-whitelist: [] + +## ── Keys / identity ─────────────────────────────────────────────────────────── +## config file (default is $HOME/.bee.yaml) +config: "/opt/homebrew/etc/swarm-bee/bee.yaml" ## password for decrypting keys # password: "" ## path to a file that contains password for decrypting keys password-file: "/opt/homebrew/var/lib/swarm-bee/password" -## percentage below the peers payment threshold when we initiate settlement -# payment-early-percent: 50 -## threshold in BZZ where you expect to get paid from your peers -# payment-threshold: "13500000" -## excess debt above payment threshold in percentages where you disconnect from your peer -# payment-tolerance-percent: 25 -## postage stamp contract address -# postage-stamp-address: "" -## postage stamp contract start block number -# postage-stamp-start-block: "0" -## enable pprof mutex profile -# pprof-mutex: false -## enable pprof block profile -# pprof-profile: false -## price oracle contract address -# price-oracle-address: "" -## redistribution contract address -# redistribution-address: "" -## reserve capacity doubling -# reserve-capacity-doubling: 0 -## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url -# resolver-options: [] -## forces the node to resync postage contract data -# resync: false -## skip postage snapshot -# skip-postage-snapshot: false -## staking contract address -# staking-address: "" -## lru memory caching capacity in number of statestore entries -# statestore-cache-capacity: "100000" -## protect nodes from getting kicked out on bootnode -# static-nodes: [] -## enable storage incentives feature -# storage-incentives-enable: true -## enable swap -# swap-enable: false -## swap factory addresses -# swap-factory-address: "" -## initial deposit if deploying a new chequebook -# swap-initial-deposit: "0" -## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay -# target-neighborhood: "" + +## ── Logging / tracing ───────────────────────────────────────────────────────── +## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace +# verbosity: info ## enable tracing # tracing-enable: false ## endpoint to send tracing data @@ -115,27 +153,13 @@ password-file: "/opt/homebrew/var/lib/swarm-bee/password" # tracing-port: "" ## service name identifier for tracing # tracing-service-name: bee -## gas limit fallback when estimation fails for contract transactions (default 500000) -# gas-limit-fallback: 500000 -## skips the gas estimate step for contract transactions -# transaction-debug-mode: false -## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace -# verbosity: info +## enable pprof mutex profile +# pprof-mutex: false +## enable pprof block profile +# pprof-profile: false + +## ── Miscellaneous ───────────────────────────────────────────────────────────── ## maximum node warmup duration; proceeds when stable or after this time # warmup-time: 5m0s ## send a welcome message string during handshakes # welcome-message: "" -## withdrawal target addresses -# withdrawal-addresses-whitelist: [] -## enable wss p2p connections (default: false) -# p2p-wss-enable: false -## wss address (default: :1635) -# p2p-wss-addr: :1635 -## WSS NAT exposed address -# nat-wss-addr: "" -## autotls domain (default: libp2p.direct) -# autotls-domain: "" -## autotls registration endpoint (default: https://registration.libp2p.direct) -# autotls-registration-endpoint: "" -## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) -# autotls-ca-endpoint: "" diff --git a/packaging/scoop/bee.yaml b/packaging/scoop/bee.yaml index f44aaf0e0d0..620245831b8 100644 --- a/packaging/scoop/bee.yaml +++ b/packaging/scoop/bee.yaml @@ -1,13 +1,13 @@ ## Bee configuration - https://docs.ethswarm.org/docs/working-with-bee/configuration -## allow to advertise private CIDRs to the public network -# allow-private-cidrs: false -## HTTP API listen address -# api-addr: 127.0.0.1:1633 -## chain block time -# block-time: "5" -## block number cache sync interval in blocks -# block-sync-interval: 10 +## ── Node mode ──────────────────────────────────────────────────────────────── +## Selects the operational mode of this node. +## full - participates in storage and incentives; requires swap-enable and blockchain-rpc +## light - uploads and downloads only; requires blockchain-rpc +## ultra-light - free-tier downloads only; no blockchain connection needed (default) +# node-mode: ultra-light + +## ── Blockchain / RPC (required for full and light nodes) ───────────────────── ## blockchain rpc configuration # blockchain-rpc: # endpoint: "" @@ -15,22 +15,96 @@ # tls-timeout: 10s # idle-timeout: 90s # keepalive: 30s +## chain block time +# block-time: "5" +## block number cache sync interval in blocks +# block-sync-interval: 10 + +## ── Swap / chequebook (full and light nodes only) ──────────────────────────── +## enable swap +# swap-enable: false +## enable chequebook +# chequebook-enable: false +## swap factory addresses +# swap-factory-address: "" +## initial deposit if deploying a new chequebook +# swap-initial-deposit: "0" + +## ── Full node only ──────────────────────────────────────────────────────────── +## enable storage incentives feature +# storage-incentives-enable: false +## reserve capacity doubling +# reserve-capacity-doubling: 0 +## minimum radius storage threshold +# minimum-storage-radius: "0" +## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay +# target-neighborhood: "" +## suggester for target neighborhood +# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion +## redistribution contract address +# redistribution-address: "" +## staking contract address +# staking-address: "" + +## ── Network ─────────────────────────────────────────────────────────────────── +## triggers connect to main net bootnodes +# mainnet: true +## ID of the Swarm network +# network-id: "1" ## initial nodes to connect to # bootnode: ["/dnsaddr/mainnet.ethswarm.org"] ## cause the node to always accept incoming connections # bootnode-mode: false -## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes -# cache-capacity: "1000000" -## enable forwarded content caching -# cache-retrieval: true -## enable chequebook -# chequebook-enable: true -## config file (default is $HOME/.bee.yaml) -config: "./bee.yaml" +## protect nodes from getting kicked out on bootnode +# static-nodes: [] +## P2P listen address +# p2p-addr: :1634 +## enable P2P WebSocket transport +# p2p-ws-enable: false +## enable wss p2p connections +# p2p-wss-enable: false +## wss address +# p2p-wss-addr: :1635 +## NAT exposed address +# nat-addr: "" +## WSS NAT exposed address +# nat-wss-addr: "" +## autotls domain +# autotls-domain: "" +## autotls registration endpoint +# autotls-registration-endpoint: "" +## autotls ca endpoint +# autotls-ca-endpoint: "" +## allow to advertise private CIDRs to the public network +# allow-private-cidrs: false + +## ── HTTP API ────────────────────────────────────────────────────────────────── +## HTTP API listen address +# api-addr: 127.0.0.1:1633 ## origins with CORS headers enabled # cors-allowed-origins: [] + +## ── Storage ─────────────────────────────────────────────────────────────────── ## data directory data-dir: "./data" +## cache capacity in chunks, multiply by 4096 to get approximate capacity in bytes +# cache-capacity: "1000000" +## enable forwarded content caching +# cache-retrieval: true +## postage stamp contract address +# postage-stamp-address: "" +## postage stamp contract start block number +# postage-stamp-start-block: "0" +## skip postage snapshot +# skip-postage-snapshot: false +## forces the node to resync postage contract data +# resync: false +## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url +# resolver-options: [] +## price oracle contract address +# price-oracle-address: "" + +## ── Database ────────────────────────────────────────────────────────────────── ## size of block cache of the database in bytes # db-block-cache-capacity: "33554432" ## disables db compactions triggered by seeks @@ -39,72 +113,36 @@ data-dir: "./data" # db-open-files-limit: "200" ## size of the database write buffer in bytes # db-write-buffer-size: "33554432" -## cause the node to start in full mode -# full-node: false -## help for printconfig -# help: false -## triggers connect to main net bootnodes. -# mainnet: true +## lru memory caching capacity in number of statestore entries +# statestore-cache-capacity: "100000" + +## ── Payments ────────────────────────────────────────────────────────────────── +## threshold in BZZ where you expect to get paid from your peers +# payment-threshold: "13500000" +## percentage below the peers payment threshold when we initiate settlement +# payment-early-percent: 50 +## excess debt above payment threshold in percentages where you disconnect from your peer +# payment-tolerance-percent: 25 ## minimum gas tip cap in wei for transactions, 0 means use suggested gas tip cap # minimum-gas-tip-cap: 0 -## minimum radius storage threshold -# minimum-storage-radius: "0" -## NAT exposed address -# nat-addr: "" -## suggester for target neighborhood -# neighborhood-suggester: https://api.swarmscan.io/v1/network/neighborhoods/suggestion -## ID of the Swarm network -# network-id: "1" -## P2P listen address -# p2p-addr: :1634 -## enable P2P WebSocket transport -# p2p-ws-enable: false +## gas limit fallback when estimation fails for contract transactions (default 500000) +# gas-limit-fallback: 500000 +## skips the gas estimate step for contract transactions +# transaction-debug-mode: false +## withdrawal target addresses +# withdrawal-addresses-whitelist: [] + +## ── Keys / identity ─────────────────────────────────────────────────────────── +## config file (default is $HOME/.bee.yaml) +config: "./bee.yaml" ## password for decrypting keys # password: "" ## path to a file that contains password for decrypting keys password-file: "./password" -## percentage below the peers payment threshold when we initiate settlement -# payment-early-percent: 50 -## threshold in BZZ where you expect to get paid from your peers -# payment-threshold: "13500000" -## excess debt above payment threshold in percentages where you disconnect from your peer -# payment-tolerance-percent: 25 -## postage stamp contract address -# postage-stamp-address: "" -## postage stamp contract start block number -# postage-stamp-start-block: "0" -## enable pprof mutex profile -# pprof-mutex: false -## enable pprof block profile -# pprof-profile: false -## price oracle contract address -# price-oracle-address: "" -## redistribution contract address -# redistribution-address: "" -## reserve capacity doubling -# reserve-capacity-doubling: 0 -## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url -# resolver-options: [] -## forces the node to resync postage contract data -# resync: false -## skip postage snapshot -# skip-postage-snapshot: false -## staking contract address -# staking-address: "" -## lru memory caching capacity in number of statestore entries -# statestore-cache-capacity: "100000" -## protect nodes from getting kicked out on bootnode -# static-nodes: [] -## enable storage incentives feature -# storage-incentives-enable: true -## enable swap -# swap-enable: false -## swap factory addresses -# swap-factory-address: "" -## initial deposit if deploying a new chequebook -# swap-initial-deposit: "0" -## neighborhood to target in binary format (ex: 111111001) for mining the initial overlay -# target-neighborhood: "" + +## ── Logging / tracing ───────────────────────────────────────────────────────── +## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace +# verbosity: info ## enable tracing # tracing-enable: false ## endpoint to send tracing data @@ -115,27 +153,13 @@ password-file: "./password" # tracing-port: "" ## service name identifier for tracing # tracing-service-name: bee -## gas limit fallback when estimation fails for contract transactions (default 500000) -# gas-limit-fallback: 500000 -## skips the gas estimate step for contract transactions -# transaction-debug-mode: false -## log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace -# verbosity: info +## enable pprof mutex profile +# pprof-mutex: false +## enable pprof block profile +# pprof-profile: false + +## ── Miscellaneous ───────────────────────────────────────────────────────────── ## maximum node warmup duration; proceeds when stable or after this time # warmup-time: 5m0s ## send a welcome message string during handshakes # welcome-message: "" -## withdrawal target addresses -# withdrawal-addresses-whitelist: [] -## enable wss p2p connections (default: false) -# p2p-wss-enable: false -## wss address (default: :1635) -# p2p-wss-addr: :1635 -## WSS NAT exposed address -# nat-wss-addr: "" -## autotls domain (default: libp2p.direct) -# autotls-domain: "" -## autotls registration endpoint (default: https://registration.libp2p.direct) -# autotls-registration-endpoint: "" -## autotls ca endpoint (default: https://acme-v02.api.letsencrypt.org/directory) -# autotls-ca-endpoint: "" diff --git a/pkg/node/node.go b/pkg/node/node.go index 0b3be605b53..bd2ff2309a0 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -127,6 +127,23 @@ type Bee struct { ethClientCloser func() } +// NodeMode represents the operational mode of a Bee node as configured by the operator. +type NodeMode string + +const ( + FullMode NodeMode = "full" + LightMode NodeMode = "light" + UltraLightMode NodeMode = "ultra-light" +) + +func (m NodeMode) IsValid() bool { + switch m { + case FullMode, LightMode, UltraLightMode: + return true + } + return false +} + type Options struct { Addr string AllowPrivateCIDRs bool @@ -158,7 +175,7 @@ type Options struct { EnableWS bool AutoTLSDomain string AutoTLSRegistrationEndpoint string - FullNodeMode bool + NodeMode NodeMode GasLimitFallback uint64 Logger log.Logger MinimumGasTipCap uint64 @@ -258,7 +275,7 @@ func NewBee( // light nodes have zero warmup time for pull/pushsync protocols warmupTime := o.WarmupTime - if !o.FullNodeMode { + if o.NodeMode != FullMode { warmupTime = 0 } @@ -284,7 +301,7 @@ func NewBee( } }(b) - if !o.FullNodeMode && o.ReserveCapacityDoubling != 0 { + if o.NodeMode != FullMode && o.ReserveCapacityDoubling != 0 { return nil, fmt.Errorf("reserve capacity doubling is only allowed for full nodes") } @@ -389,7 +406,7 @@ func NewBee( erc20Service erc20.Service ) - chainEnabled := isChainEnabled(o, o.BlockchainRpcEndpoint, logger) + chainEnabled := isChainEnabled(o, logger) var batchStore postage.Storer = new(postage.NoOpBatchStore) var evictFn func([]byte) error @@ -437,10 +454,13 @@ func NewBee( b.transactionCloser = tracerCloser b.transactionMonitorCloser = transactionMonitor - beeNodeMode := api.LightMode - if o.FullNodeMode { + var beeNodeMode api.BeeNodeMode + switch o.NodeMode { + case FullMode: beeNodeMode = api.FullMode - } else if !chainEnabled { + case LightMode: + beeNodeMode = api.LightMode + default: beeNodeMode = api.UltraLightMode } @@ -663,7 +683,7 @@ func NewBee( AutoTLSRegistrationEndpoint: o.AutoTLSRegistrationEndpoint, AutoTLSCAEndpoint: o.AutoTLSCAEndpoint, WelcomeMessage: o.WelcomeMessage, - FullNode: o.FullNodeMode, + FullNode: o.NodeMode == FullMode, Nonce: nonce, ValidateOverlay: chainEnabled, Registry: registry, @@ -789,7 +809,7 @@ func NewBee( MinimumStorageRadius: o.MinimumStorageRadius, } - if o.FullNodeMode && !o.BootnodeMode { + if o.NodeMode == FullMode && !o.BootnodeMode { // configure reserve only for full node lo.ReserveCapacity = reserveCapacity lo.ReserveWakeUpDuration = reserveWakeUpDuration @@ -867,7 +887,7 @@ func NewBee( return nil, errors.New("postage contract is paused") } - if o.FullNodeMode { + if o.NodeMode == FullMode { err = batchSvc.Start(ctx, postageSyncStart) syncStatus.Store(true) if err != nil { @@ -892,7 +912,7 @@ func NewBee( minThreshold := big.NewInt(2 * refreshRate) maxThreshold := big.NewInt(24 * refreshRate) - if !o.FullNodeMode { + if o.NodeMode != FullMode { minThreshold = big.NewInt(2 * lightRefreshRate) } @@ -925,7 +945,7 @@ func NewBee( var enforcedRefreshRate *big.Int - if o.FullNodeMode { + if o.NodeMode == FullMode { enforcedRefreshRate = big.NewInt(refreshRate) } else { enforcedRefreshRate = big.NewInt(lightRefreshRate) @@ -1020,7 +1040,7 @@ func NewBee( if prev == uint32(swarm.MaxBins) { close(initialRadiusC) } - if !o.FullNodeMode { // light and ultra-light nodes do not have a reserve worker to set the radius. + if o.NodeMode != FullMode { // light and ultra-light nodes do not have a reserve worker to set the radius. kad.SetStorageRadius(r) } case <-ctx.Done(): @@ -1047,7 +1067,7 @@ func NewBee( } } - pushSyncProtocol := pushsync.New(swarmAddress, networkID, nonce, p2ps, localStore, waitNetworkRFunc, kad, o.FullNodeMode && !o.BootnodeMode, pssService.TryUnwrap, gsocService.Handle, validStamp, logger, acc, pricer, signer, tracer, detector, uint8(shallowReceiptTolerance)) + pushSyncProtocol := pushsync.New(swarmAddress, networkID, nonce, p2ps, localStore, waitNetworkRFunc, kad, o.NodeMode == FullMode && !o.BootnodeMode, pssService.TryUnwrap, gsocService.Handle, validStamp, logger, acc, pricer, signer, tracer, detector, uint8(shallowReceiptTolerance)) b.pushSyncCloser = pushSyncProtocol // set the pushSyncer in the PSS @@ -1070,7 +1090,7 @@ func NewBee( pushSyncProtocolSpec := pushSyncProtocol.Protocol() pullSyncProtocolSpec := pullSyncProtocol.Protocol() - if o.FullNodeMode && !o.BootnodeMode { + if o.NodeMode == FullMode && !o.BootnodeMode { logger.Info("starting in full mode") } else { if chainEnabled { @@ -1153,7 +1173,7 @@ func NewBee( agent *storageincentives.Agent ) - if o.FullNodeMode && !o.BootnodeMode { + if o.NodeMode == FullMode && !o.BootnodeMode { pullerService = puller.New(swarmAddress, stateStore, kad, localStore, pullSyncProtocol, p2ps, logger, puller.Options{}) b.pullerCloser = pullerService @@ -1473,21 +1493,13 @@ func (b *Bee) Shutdown() error { var ErrShutdownInProgress = errors.New("shutdown in progress") -func isChainEnabled(o *Options, swapEndpoint string, logger log.Logger) bool { - chainDisabled := swapEndpoint == "" - lightMode := !o.FullNodeMode - - if lightMode && chainDisabled { - logger.Info("chain backend disabled - starting in ultra-light mode", - "full_node_mode", o.FullNodeMode, - "blockchain-rpc-endpoint", swapEndpoint) +func isChainEnabled(o *Options, logger log.Logger) bool { + if o.NodeMode == UltraLightMode { + logger.Info("chain backend disabled - starting in ultra-light mode") return false } - - logger.Info("chain backend enabled - blockchain functionality available", - "full_node_mode", o.FullNodeMode, - "blockchain-rpc-endpoint", swapEndpoint) - return true // all other modes operate require chain enabled + logger.Info("chain backend enabled - blockchain functionality available", "node_mode", o.NodeMode) + return true } func validatePublicAddress(addr string) error { From b58c43a0135b63c35fadcb6f70189182556992a3 Mon Sep 17 00:00:00 2001 From: Calin Martinconi Date: Tue, 14 Apr 2026 12:17:15 +0300 Subject: [PATCH 2/3] fix: restore legacy mode detection in resolveNodeMode --- .github/workflows/beekeeper.yml | 2 +- cmd/bee/cmd/start.go | 61 ++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/.github/workflows/beekeeper.yml b/.github/workflows/beekeeper.yml index 939d82b4f97..de1f6c1bf22 100644 --- a/.github/workflows/beekeeper.yml +++ b/.github/workflows/beekeeper.yml @@ -19,7 +19,7 @@ env: SETUP_CONTRACT_IMAGE: "ethersphere/bee-localchain" SETUP_CONTRACT_IMAGE_TAG: "0.9.4" BEELOCAL_BRANCH: "main" - BEEKEEPER_BRANCH: "master" + BEEKEEPER_BRANCH: "refactor/node-mode-config" BEEKEEPER_METRICS_ENABLED: false REACHABILITY_OVERRIDE_PUBLIC: true BATCHFACTOR_OVERRIDE_PUBLIC: 2 diff --git a/cmd/bee/cmd/start.go b/cmd/bee/cmd/start.go index 9dc382d8f93..a1be35d0dac 100644 --- a/cmd/bee/cmd/start.go +++ b/cmd/bee/cmd/start.go @@ -342,46 +342,51 @@ func buildBeeNode(ctx context.Context, c *command, cmd *cobra.Command, logger lo } // resolveNodeMode determines the effective node mode from config. -// --node-mode takes precedence; the deprecated --full-node flag is honoured as a fallback. -// It also validates that the required options for each mode are present. +// --node-mode takes precedence and triggers strict per-mode validation. +// The deprecated --full-node flag is honoured as a fallback. +// When neither is set, mode is inferred from blockchain-rpc-endpoint presence +// (legacy behaviour) without strict validation, for backward compatibility. func (c *command) resolveNodeMode(logger log.Logger) (node.NodeMode, error) { rpcEndpoint := c.config.GetString(configKeyBlockchainRpcEndpoint) swapEnable := c.config.GetBool(optionNameSwapEnable) - // Resolve the mode: explicit node-mode wins, then legacy full-node, then default ultra-light. - var mode node.NodeMode if c.config.IsSet(optionNameNodeMode) { - mode = node.NodeMode(c.config.GetString(optionNameNodeMode)) + // Explicit node-mode: validate strictly. + mode := node.NodeMode(c.config.GetString(optionNameNodeMode)) if !mode.IsValid() { return "", fmt.Errorf("invalid node-mode %q: must be one of full, light, ultra-light", mode) } - } else if c.config.GetBool(optionNameFullNode) { - logger.Warning("--full-node is deprecated, use --node-mode=full instead") - mode = node.FullMode - } else { - mode = node.UltraLightMode + switch mode { + case node.FullMode: + if rpcEndpoint == "" { + return "", errors.New("full node requires blockchain-rpc-endpoint to be set") + } + if !swapEnable { + return "", errors.New("full node requires swap-enable to be true") + } + case node.LightMode: + if rpcEndpoint == "" { + return "", errors.New("light node requires blockchain-rpc-endpoint to be set") + } + case node.UltraLightMode: + if swapEnable { + return "", errors.New("ultra-light node cannot have swap-enable set to true") + } + } + return mode, nil } - // Validate mode-specific requirements. - switch mode { - case node.FullMode: - if rpcEndpoint == "" { - return "", errors.New("full node requires blockchain-rpc-endpoint to be set") - } - if !swapEnable { - return "", errors.New("full node requires swap-enable to be true") - } - case node.LightMode: - if rpcEndpoint == "" { - return "", errors.New("light node requires blockchain-rpc-endpoint to be set") - } - case node.UltraLightMode: - if swapEnable { - return "", errors.New("ultra-light node cannot have swap-enable set to true") - } + // Legacy path: node-mode not set, fall back to deprecated flags / old detection. + if c.config.GetBool(optionNameFullNode) { + logger.Warning("--full-node is deprecated, use --node-mode=full instead") + return node.FullMode, nil } - return mode, nil + // Infer light vs ultra-light from RPC endpoint presence (original behaviour). + if rpcEndpoint != "" { + return node.LightMode, nil + } + return node.UltraLightMode, nil } type program struct { From 9d736a05bf7354d94f30f24c41924f423a0d3db0 Mon Sep 17 00:00:00 2001 From: Calin Martinconi Date: Wed, 22 Apr 2026 17:26:35 +0300 Subject: [PATCH 3/3] test: add table-driven tests for resolveNodeMode --- cmd/bee/cmd/resolve_node_mode_test.go | 156 ++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 cmd/bee/cmd/resolve_node_mode_test.go diff --git a/cmd/bee/cmd/resolve_node_mode_test.go b/cmd/bee/cmd/resolve_node_mode_test.go new file mode 100644 index 00000000000..5880a3f57e7 --- /dev/null +++ b/cmd/bee/cmd/resolve_node_mode_test.go @@ -0,0 +1,156 @@ +// Copyright 2026 The Swarm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cmd + +import ( + "strings" + "testing" + + "github.com/ethersphere/bee/v2/pkg/log" + "github.com/ethersphere/bee/v2/pkg/node" + "github.com/spf13/viper" +) + +func TestResolveNodeMode(t *testing.T) { + tests := []struct { + name string + config map[string]any + wantMode node.NodeMode + wantErr string + }{ + // ── Explicit node-mode: strict validation ──────────────────────────────── + { + name: "full mode with rpc and swap succeeds", + config: map[string]any{ + optionNameNodeMode: "full", + configKeyBlockchainRpcEndpoint: "http://localhost:8545", + optionNameSwapEnable: true, + }, + wantMode: node.FullMode, + }, + { + name: "full mode without rpc fails", + config: map[string]any{ + optionNameNodeMode: "full", + optionNameSwapEnable: true, + }, + wantErr: "full node requires blockchain-rpc-endpoint", + }, + { + name: "full mode without swap fails", + config: map[string]any{ + optionNameNodeMode: "full", + configKeyBlockchainRpcEndpoint: "http://localhost:8545", + }, + wantErr: "full node requires swap-enable", + }, + { + name: "light mode with rpc succeeds", + config: map[string]any{ + optionNameNodeMode: "light", + configKeyBlockchainRpcEndpoint: "http://localhost:8545", + }, + wantMode: node.LightMode, + }, + { + name: "light mode without rpc fails", + config: map[string]any{ + optionNameNodeMode: "light", + }, + wantErr: "light node requires blockchain-rpc-endpoint", + }, + { + name: "ultra-light mode succeeds", + config: map[string]any{ + optionNameNodeMode: "ultra-light", + }, + wantMode: node.UltraLightMode, + }, + { + name: "ultra-light mode rejects swap-enable", + config: map[string]any{ + optionNameNodeMode: "ultra-light", + optionNameSwapEnable: true, + }, + wantErr: "ultra-light node cannot have swap-enable", + }, + { + name: "invalid node-mode value fails", + config: map[string]any{ + optionNameNodeMode: "superlight", + }, + wantErr: "invalid node-mode", + }, + + // ── Legacy path: no node-mode set ──────────────────────────────────────── + { + name: "legacy full-node true maps to full mode", + config: map[string]any{ + optionNameFullNode: true, + }, + wantMode: node.FullMode, + }, + { + name: "legacy with rpc endpoint infers light mode", + config: map[string]any{ + configKeyBlockchainRpcEndpoint: "http://localhost:8545", + }, + wantMode: node.LightMode, + }, + { + name: "legacy without rpc endpoint infers ultra-light mode", + config: map[string]any{}, + wantMode: node.UltraLightMode, + }, + { + // Beekeeper's inherited-config scenario: rpc + swap-enable without node-mode. + // Legacy path must NOT apply strict swap validation; this was the CI regression. + name: "legacy with rpc and swap-enable infers light without error", + config: map[string]any{ + configKeyBlockchainRpcEndpoint: "http://localhost:8545", + optionNameSwapEnable: true, + }, + wantMode: node.LightMode, + }, + { + // Same scenario but for ultra-light: no rpc, swap-enable inherited from base. + name: "legacy without rpc but with swap-enable infers ultra-light without error", + config: map[string]any{ + optionNameSwapEnable: true, + }, + wantMode: node.UltraLightMode, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &command{ + config: viper.New(), + logger: log.Noop, + } + for k, v := range tt.config { + c.config.Set(k, v) + } + + gotMode, err := c.resolveNodeMode(c.logger) + + if tt.wantErr != "" { + if err == nil { + t.Fatalf("expected error containing %q, got nil (mode=%q)", tt.wantErr, gotMode) + } + if !strings.Contains(err.Error(), tt.wantErr) { + t.Fatalf("expected error containing %q, got %q", tt.wantErr, err.Error()) + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gotMode != tt.wantMode { + t.Errorf("got mode %q, want %q", gotMode, tt.wantMode) + } + }) + } +}