@@ -170,6 +170,28 @@ pub struct ConfigFile {
170170 pub __path : Option < String > , // Only used for config file reloads
171171 pub burnchain : Option < BurnchainConfigFile > ,
172172 pub node : Option < NodeConfigFile > ,
173+ /// Represents an initial STX balance allocation for an address at genesis
174+ /// for testing purposes.
175+ ///
176+ /// This struct is used to define pre-allocated STX balances that are credited to
177+ /// specific addresses when the Stacks node first initializes its chainstate. These balances
178+ /// are included in the genesis block and are immediately available for spending.
179+ ///
180+ /// **Configuration:**
181+ /// Configured as a list `[[ustx_balance]]` in TOML.
182+ ///
183+ /// Example TOML entry:
184+ /// ```toml
185+ /// [[ustx_balance]]
186+ /// address = "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2"
187+ /// amount = 10000000000000000
188+ /// ```
189+ ///
190+ /// This is intended strictly for testing purposes.
191+ /// Attempting to specify initial balances if [`BurnchainConfig::mode`] is "mainnet" will
192+ /// result in an invalid config error.
193+ ///
194+ /// Default: `None`
173195 pub ustx_balance : Option < Vec < InitialBalanceFile > > ,
174196 /// Deprecated: use `ustx_balance` instead
175197 pub mstx_balance : Option < Vec < InitialBalanceFile > > ,
@@ -2468,13 +2490,24 @@ impl Default for NodeConfig {
24682490impl NodeConfig {
24692491 /// Get a SocketAddr for this node's RPC endpoint which uses the loopback address
24702492 pub fn get_rpc_loopback ( & self ) -> Option < SocketAddr > {
2471- let rpc_port = SocketAddr :: from_str ( & self . rpc_bind )
2472- . map_err ( |e| {
2493+ let rpc_port = self . rpc_bind_addr ( ) ?. port ( ) ;
2494+ Some ( SocketAddr :: new ( Ipv4Addr :: LOCALHOST . into ( ) , rpc_port) )
2495+ }
2496+
2497+ pub fn rpc_bind_addr ( & self ) -> Option < SocketAddr > {
2498+ SocketAddr :: from_str ( & self . rpc_bind )
2499+ . inspect_err ( |e| {
24732500 error ! ( "Could not parse node.rpc_bind configuration setting as SocketAddr: {e}" ) ;
24742501 } )
2475- . ok ( ) ?
2476- . port ( ) ;
2477- Some ( SocketAddr :: new ( Ipv4Addr :: LOCALHOST . into ( ) , rpc_port) )
2502+ . ok ( )
2503+ }
2504+
2505+ pub fn p2p_bind_addr ( & self ) -> Option < SocketAddr > {
2506+ SocketAddr :: from_str ( & self . p2p_bind )
2507+ . inspect_err ( |e| {
2508+ error ! ( "Could not parse node.rpc_bind configuration setting as SocketAddr: {e}" ) ;
2509+ } )
2510+ . ok ( )
24782511 }
24792512
24802513 pub fn add_signers_stackerdbs ( & mut self , is_mainnet : bool ) {
@@ -3784,12 +3817,97 @@ impl NodeConfigFile {
37843817#[ derive( Clone , Deserialize , Default , Debug ) ]
37853818#[ serde( deny_unknown_fields) ]
37863819pub struct FeeEstimationConfigFile {
3820+ /// Specifies the name of the cost estimator to use.
3821+ /// This controls how the node estimates computational costs for transactions.
3822+ ///
3823+ /// Accepted values:
3824+ /// - `"NaivePessimistic"`: The only currently supported cost estimator. This estimator
3825+ /// tracks the highest observed costs for each operation type and uses the average
3826+ /// of the top 10 values as its estimate, providing a conservative approach to
3827+ /// cost estimation.
3828+ ///
3829+ /// If not specified, or if [`FeeEstimationConfigFile::disabled`] is `true`,
3830+ /// the node will use the default cost estimator.
3831+ ///
3832+ /// Default: `"NaivePessimistic"`
37873833 pub cost_estimator : Option < String > ,
3834+ /// Specifies the name of the fee estimator to use.
3835+ /// This controls how the node calculates appropriate transaction fees based on costs.
3836+ ///
3837+ /// Accepted values:
3838+ /// - `"ScalarFeeRate"`: Simple multiplier-based fee estimation that uses percentiles
3839+ /// (5th, 50th, and 95th) of observed fee rates from recent blocks.
3840+ /// - `"FuzzedWeightedMedianFeeRate"`: Fee estimation that adds controlled randomness
3841+ /// to a weighted median rate calculator. This helps prevent fee optimization attacks
3842+ /// by adding unpredictability to fee estimates while still maintaining accuracy.
3843+ ///
3844+ /// If not specified, or if [`FeeEstimationConfigFile::disabled`] is `true`,
3845+ /// the node will use the default fee estimator.
3846+ ///
3847+ /// Default: `"ScalarFeeRate"`
37883848 pub fee_estimator : Option < String > ,
3849+ /// Specifies the name of the cost metric to use.
3850+ /// This controls how the node measures and compares transaction costs.
3851+ ///
3852+ /// Accepted values:
3853+ /// - `"ProportionDotProduct"`: The only currently supported cost metric. This metric
3854+ /// computes a weighted sum of cost dimensions (runtime, read/write counts, etc.)
3855+ /// proportional to how much of the block limit they consume.
3856+ ///
3857+ /// If not specified, or if [`FeeEstimationConfigFile::disabled`] is `true`,
3858+ /// the node will use the default cost metric.
3859+ ///
3860+ /// Default: `"ProportionDotProduct"`
37893861 pub cost_metric : Option < String > ,
3862+ /// If `true`, all fee and cost estimation features are disabled.
3863+ /// The node will use unit estimators and metrics, which effectively
3864+ /// provide no actual estimation capabilities.
3865+ ///
3866+ /// When disabled, the node will:
3867+ /// 1. Not track historical transaction costs or fee rates
3868+ /// 2. Return simple unit values for costs for any transaction, regardless of its actual complexity
3869+ /// 3. Be unable to provide meaningful fee estimates for API requests (always returns an error)
3870+ /// 4. Consider only raw transaction fees (not fees per cost unit) when assembling blocks
3871+ ///
3872+ /// This setting takes precedence over individual estimator/metric configurations.
3873+ /// When `true`, the values for [`FeeEstimationConfigFile::cost_estimator`],
3874+ /// [`FeeEstimationConfigFile::fee_estimator`], and [`FeeEstimationConfigFile::cost_metric`]
3875+ /// are ignored and treated as `None`.
3876+ ///
3877+ /// Default: `false`
37903878 pub disabled : Option < bool > ,
3879+ /// If `true`, errors encountered during cost or fee estimation will be logged.
3880+ /// This can help diagnose issues with the fee estimation subsystem.
3881+ ///
3882+ /// Default: `false`
37913883 pub log_error : Option < bool > ,
3884+ /// Specifies the fraction of random noise to add if using the `FuzzedWeightedMedianFeeRate` fee estimator.
3885+ /// This value should be in the range [0, 1], representing a percentage of the base fee rate.
3886+ ///
3887+ /// For example, with a value of 0.1 (10%), fee rate estimates will have random noise added
3888+ /// within the range of ±10% of the original estimate. This randomization makes it difficult
3889+ /// for users to precisely optimize their fees while still providing reasonable estimates.
3890+ ///
3891+ /// This setting is only relevant when [`FeeEstimationConfigFile::fee_estimator`] is set to
3892+ /// `"FuzzedWeightedMedianFeeRate"`. It controls how much randomness is introduced in the
3893+ /// fee estimation process to prevent fee optimization attacks.
3894+ ///
3895+ /// Default: `0.1` (10%)
37923896 pub fee_rate_fuzzer_fraction : Option < f64 > ,
3897+ /// Specifies the window size for the [`WeightedMedianFeeRateEstimator`].
3898+ /// This determines how many historical fee rate data points are considered
3899+ /// when calculating the median fee rate.
3900+ ///
3901+ /// The window size controls how quickly the fee estimator responds to changing
3902+ /// network conditions. A smaller window size (e.g., 5) makes the estimator more
3903+ /// responsive to recent fee rate changes but potentially more volatile. A larger
3904+ /// window size (e.g., 10) produces more stable estimates but may be slower to
3905+ /// adapt to rapid network changes.
3906+ ///
3907+ /// This setting is primarily relevant when [`FeeEstimationConfigFile::fee_estimator`] is set to
3908+ /// `"FuzzedWeightedMedianFeeRate"`, as it's used by the underlying [`WeightedMedianFeeRateEstimator`].
3909+ ///
3910+ /// Default: `5`
37933911 pub fee_rate_window_size : Option < u64 > ,
37943912}
37953913
@@ -4047,9 +4165,118 @@ impl AtlasConfigFile {
40474165#[ derive( Clone , Deserialize , Default , Debug , Hash , PartialEq , Eq , PartialOrd ) ]
40484166#[ serde( deny_unknown_fields) ]
40494167pub struct EventObserverConfigFile {
4168+ /// URL endpoint (hostname and port) where event notifications will be sent via HTTP POST requests.
4169+ ///
4170+ /// The node will automatically prepend `http://` to this endpoint and append the
4171+ /// specific event path (e.g., `/new_block`, `/new_mempool_tx`).
4172+ /// Therefore, this value should be specified as `hostname:port` (e.g., "localhost:3700").
4173+ ///
4174+ /// **Do NOT include the `http://` scheme in this configuration value.**
4175+ ///
4176+ /// This should point to a service capable of receiving and processing Stacks event data.
4177+ ///
4178+ /// Default: No default. This field is required.
40504179 pub endpoint : String ,
4180+ /// List of event types that this observer is configured to receive.
4181+ ///
4182+ /// For a more detailed documentation check the event-dispatcher docs in the `/docs` folder.
4183+ ///
4184+ /// Each string in the list specifies an event category or a specific event to subscribe to.
4185+ /// For an observer to receive any notifications, this list must contain at least one valid key.
4186+ /// Providing an invalid string that doesn't match any of the valid formats below will cause
4187+ /// the node to panic on startup when parsing the configuration.
4188+ ///
4189+ /// All observers, regardless of their `events_keys` configuration, implicitly receive
4190+ /// payloads on the `/attachments/new` endpoint.
4191+ ///
4192+ /// **Valid Event Keys:**
4193+ ///
4194+ /// - `"*"`: Subscribes to a broad set of common events.
4195+ /// - **Events delivered to:**
4196+ /// - `/new_block`: For blocks containing transactions that generate STX, FT, NFT, or smart contract events.
4197+ /// - `/new_microblocks`: For all new microblock streams. **Note:** Only until epoch 2.5.
4198+ /// - `/new_mempool_tx`: For new mempool transactions.
4199+ /// - `/drop_mempool_tx`: For dropped mempool transactions.
4200+ /// - `/new_burn_block`: For new burnchain blocks.
4201+ /// - **Note:** This key does NOT by itself subscribe to `/stackerdb_chunks` or `/proposal_response`.
4202+ ///
4203+ /// - `"stx"`: Subscribes to STX token operation events (transfer, mint, burn, lock).
4204+ /// - **Events delivered to:** `/new_block`, `/new_microblocks`.
4205+ /// - **Payload details:** The "events" array in the delivered payloads will be filtered to include only STX-related events.
4206+ ///
4207+ /// - `"memtx"`: Subscribes to new and dropped mempool transaction events.
4208+ /// - **Events delivered to:** `/new_mempool_tx`, `/drop_mempool_tx`.
4209+ ///
4210+ /// - `"burn_blocks"`: Subscribes to new burnchain block events.
4211+ /// - **Events delivered to:** `/new_burn_block`.
4212+ ///
4213+ /// - `"microblocks"`: Subscribes to new microblock stream events.
4214+ /// - **Events delivered to:** `/new_microblocks`.
4215+ /// - **Payload details:**
4216+ /// - The "transactions" field will contain all transactions from the microblocks.
4217+ /// - The "events" field will contain STX, FT, NFT, or specific smart contract events
4218+ /// *only if* this observer is also subscribed to those more specific event types
4219+ /// (e.g., via `"stx"`, `"*"`, a specific contract event key, or a specific asset identifier key).
4220+ /// - **Note:** Only until epoch 2.5.
4221+ ///
4222+ /// - `"stackerdb"`: Subscribes to StackerDB chunk update events.
4223+ /// - **Events delivered to:** `/stackerdb_chunks`.
4224+ ///
4225+ /// - `"block_proposal"`: Subscribes to block proposal response events (for Nakamoto consensus).
4226+ /// - **Events delivered to:** `/proposal_response`.
4227+ ///
4228+ /// - **Smart Contract Event**: Subscribes to a specific smart contract event.
4229+ /// - **Format:** `"{contract_address}.{contract_name}::{event_name}"`
4230+ /// (e.g., `ST0000000000000000000000000000000000000000.my-contract::my-custom-event`)
4231+ /// - **Events delivered to:** `/new_block`, `/new_microblocks`.
4232+ /// - **Payload details:** The "events" array in the delivered payloads will be filtered for this specific event.
4233+ ///
4234+ /// - **Asset Identifier for FT/NFT Events**: Subscribes to events (mint, burn, transfer) for a specific Fungible Token (FT) or Non-Fungible Token (NFT).
4235+ /// - **Format:** `"{contract_address}.{contract_name}.{asset_name}"`
4236+ /// (e.g., for an FT: `ST0000000000000000000000000000000000000000.my-ft-contract.my-fungible-token`)
4237+ /// - **Events delivered to:** `/new_block`, `/new_microblocks`.
4238+ /// - **Payload details:** The "events" array in the delivered payloads will be filtered for events related to the specified asset.
4239+ ///
4240+ /// **Configuration:**
4241+ ///
4242+ /// ```toml
4243+ /// # Example events_keys in TOML configuration:
4244+ /// events_keys = [
4245+ /// "burn_blocks",
4246+ /// "memtx",
4247+ /// "ST0000000000000000000000000000000000000000.my-contract::my-custom-event", # Smart contract event
4248+ /// "ST0000000000000000000000000000000000000000.token-contract.my-ft" # Fungible token asset event
4249+ /// ]
4250+ /// ```
4251+ ///
4252+ /// Default: No default. This field is required.
40514253 pub events_keys : Vec < String > ,
4254+ /// Maximum duration (in milliseconds) to wait for the observer endpoint to respond.
4255+ ///
4256+ /// When the node sends an event notification to this observer, it will wait at most this long
4257+ /// for a successful HTTP response (status code 200) before considering the request timed out.
4258+ /// If a timeout occurs and retries are enabled (see [`EventObserverConfig::disable_retries`]),
4259+ /// the request will be attempted again according to the retry strategy.
4260+ ///
4261+ /// Default: `1_000` ms (1 second).
40524262 pub timeout_ms : Option < u64 > ,
4263+ /// Controls whether the node should retry sending event notifications if delivery fails or times out.
4264+ ///
4265+ /// - If `false` (default): The node will attempt to deliver event notifications persistently.
4266+ /// If an attempt fails (due to network error, timeout, or a non-200 HTTP response), the event
4267+ /// payload is saved and retried indefinitely. This ensures that all events will eventually be
4268+ /// delivered. However, this can cause the node's block processing to stall if an observer is
4269+ /// down, or indefinitely fails to process the event.
4270+ ///
4271+ /// - If `true`: The node will make only a single attempt to deliver each event notification.
4272+ /// If this single attempt fails for any reason, the event is discarded, and no further retries
4273+ /// will be made for that specific event.
4274+ ///
4275+ /// **Warning:** Setting this to `true` can lead to missed events if the observer endpoint is
4276+ /// temporarily unavailable or experiences issues. This setting should only be used for observers
4277+ /// where completeness of the event history is not critical.
4278+ ///
4279+ /// Default: `false` (retries are enabled).
40534280 pub disable_retries : Option < bool > ,
40544281}
40554282
@@ -4152,7 +4379,15 @@ pub struct InitialBalance {
41524379#[ derive( Clone , Deserialize , Default , Debug ) ]
41534380#[ serde( deny_unknown_fields) ]
41544381pub struct InitialBalanceFile {
4382+ /// The Stacks address to receive the initial STX balance.
4383+ /// Must be a valid "non-mainnet" Stacks address (e.g., "ST2QKZ4FKHAH1NQKYKYAYZPY440FEPK7GZ1R5HBP2").
4384+ ///
4385+ /// Default: No default. This field is required.
41554386 pub address : String ,
4387+ /// The amount of microSTX to allocate to the address at node startup.
4388+ /// 1 STX = 1_000_000 microSTX.
4389+ ///
4390+ /// Default: No default. This field is required.
41564391 pub amount : u64 ,
41574392}
41584393
0 commit comments