@@ -6,6 +6,17 @@ use crate::context::Context;
66use crate :: error:: RpcError ;
77use crate :: handlers:: { ensure_no_params, params_array, required_str} ;
88
9+ // Local service flags this node advertises:
10+ // - NODE_NETWORK (1 << 0) = 1 — full block serving.
11+ // - NODE_WITNESS (1 << 3) = 8 — segwit data.
12+ // - NODE_COMPACT_FILTERS (1 << 6) = 64 — BIP157 filters.
13+ // Sum = 73 = 0x49.
14+ const LOCAL_SERVICES_FLAGS : u64 = ( 1_u64 << 0 ) | ( 1_u64 << 3 ) | ( 1_u64 << 6 ) ;
15+ const LOCAL_SERVICES_HEX : & str = "0000000000000049" ;
16+ const LOCAL_SERVICES_NAMES : & [ & str ] = & [ "NETWORK" , "WITNESS" , "COMPACT_FILTERS" ] ;
17+
18+ const _: ( ) = assert ! ( LOCAL_SERVICES_FLAGS == 0x49 ) ;
19+
920const DEFAULT_RELAY_FEE_BTC_PER_KVB : f64 = 0.00001 ;
1021const DEFAULT_INCREMENTAL_FEE_BTC_PER_KVB : f64 = 0.00001 ;
1122
@@ -19,8 +30,11 @@ pub(crate) fn getnetworkinfo(ctx: &Arc<Context>, params: &Value) -> Result<Value
1930 "version" : 10000 ,
2031 "subversion" : "/bitcoin-rs:0.1.0/" ,
2132 "protocolversion" : 70016_i64 ,
22- "localservices" : "0000000000000000" ,
23- "localservicesnames" : Vec :: <String >:: new( ) ,
33+ "localservices" : LOCAL_SERVICES_HEX ,
34+ "localservicesnames" : LOCAL_SERVICES_NAMES
35+ . iter( )
36+ . map( |& s| s. to_owned( ) )
37+ . collect:: <Vec <_>>( ) ,
2438 "localrelay" : true ,
2539 "timeoffset" : 0 ,
2640 "networkactive" : true ,
@@ -226,7 +240,7 @@ pub(crate) fn getnettotals(ctx: &Arc<Context>, params: &Value) -> Result<Value,
226240mod tests {
227241 use super :: * ;
228242 use alloc:: sync:: Arc ;
229- use sonic_rs:: JsonValueTrait ;
243+ use sonic_rs:: { JsonContainerTrait as _ , JsonValueTrait } ;
230244
231245 #[ test]
232246 fn getnetworkinfo_reports_zero_connections_on_fresh_context ( ) {
@@ -261,6 +275,34 @@ mod tests {
261275 "expected ~0.00001, got {relayfee}"
262276 ) ;
263277 }
278+
279+ #[ test]
280+ fn getnetworkinfo_localservices_advertises_network_witness_filters ( ) {
281+ let ctx = Arc :: new ( Context :: new ( ) ) ;
282+ let result = getnetworkinfo ( & ctx, & json ! ( null) )
283+ . unwrap_or_else ( |err| panic ! ( "getnetworkinfo failed: {err}" ) ) ;
284+ assert_eq ! (
285+ result. get( "localservices" ) . and_then( |v| v. as_str( ) ) ,
286+ Some ( "0000000000000049" )
287+ ) ;
288+ let names: Vec < String > = result
289+ . get ( "localservicesnames" )
290+ . and_then ( |v| v. as_array ( ) )
291+ . map ( |arr| {
292+ arr. iter ( )
293+ . filter_map ( |n| n. as_str ( ) . map ( str:: to_owned) )
294+ . collect ( )
295+ } )
296+ . unwrap_or_default ( ) ;
297+ assert ! ( names. contains( & "NETWORK" . to_owned( ) ) ) ;
298+ assert ! ( names. contains( & "WITNESS" . to_owned( ) ) ) ;
299+ assert ! ( names. contains( & "COMPACT_FILTERS" . to_owned( ) ) ) ;
300+ }
301+
302+ #[ test]
303+ fn local_services_flags_hex_matches_bitmask ( ) {
304+ assert_eq ! ( format!( "{LOCAL_SERVICES_FLAGS:016x}" ) , LOCAL_SERVICES_HEX ) ;
305+ }
264306}
265307#[ cfg( test) ]
266308mod ping_tests {
0 commit comments