Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/komodo_coin_updates/example/seed_nodes_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ void main() async {
try {
// Fetch seed nodes from the remote source
print('Fetching seed nodes from remote source...');
final seedNodes = await SeedNodeUpdater.fetchSeedNodes();
final (seedNodes: seedNodes, netId: netId) =
await SeedNodeUpdater.fetchSeedNodes();

print('Found ${seedNodes.length} seed nodes:');
print('Found ${seedNodes.length} seed nodes on netid $netId:');
for (final node in seedNodes) {
print(' - ${node.name}: ${node.host}');
if (node.contact.isNotEmpty && node.contact.first.email.isNotEmpty) {
Expand Down
17 changes: 14 additions & 3 deletions packages/komodo_coin_updates/lib/src/seed_node_updater.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:komodo_defi_types/komodo_defi_type_utils.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart';

/// Service responsible for fetching and managing seed nodes from remote sources.
///
///
/// This service handles the downloading and parsing of seed node configurations
/// from the Komodo Platform repository.
class SeedNodeUpdater {
Expand All @@ -15,7 +15,9 @@ class SeedNodeUpdater {
/// Returns a list of [SeedNode] objects that can be used for P2P networking.
///
/// Throws an exception if the seed nodes cannot be fetched or parsed.
static Future<List<SeedNode>> fetchSeedNodes() async {
static Future<({List<SeedNode> seedNodes, int netId})> fetchSeedNodes({
bool filterForWeb = kIsWeb,
}) async {
const seedNodesUrl =
'https://komodoplatform.github.io/coins/seed-nodes.json';

Expand All @@ -29,7 +31,16 @@ class SeedNodeUpdater {
}

final seedNodesJson = jsonListFromString(response.body);
return SeedNode.fromJsonList(seedNodesJson);
var seedNodes = SeedNode.fromJsonList(seedNodesJson);

// Filter nodes to the configured netId
seedNodes = seedNodes.where((e) => e.netId == kDefaultNetId).toList();

if (filterForWeb && kIsWeb) {
seedNodes = seedNodes.where((e) => e.wss).toList();
}

return (seedNodes: seedNodes, netId: kDefaultNetId);
} catch (e) {
debugPrint('Error fetching seed nodes: $e');
throw Exception('Failed to fetch or process seed nodes: $e');
Expand Down
6 changes: 6 additions & 0 deletions packages/komodo_coin_updates/test/seed_node_updater_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ void main() {
SeedNode(
name: 'seed-node-1',
host: 'seed01.kmdefi.net',
type: 'domain',
wss: true,
netId: 8762,
contact: [SeedNodeContact(email: '')],
),
SeedNode(
name: 'seed-node-2',
host: 'seed02.kmdefi.net',
type: 'domain',
wss: true,
netId: 8762,
contact: [SeedNodeContact(email: '')],
),
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:komodo_coins/komodo_coins.dart';
import 'package:komodo_defi_framework/src/config/seed_node_validator.dart';
import 'package:komodo_defi_framework/src/services/seed_node_service.dart'
show SeedNodeService;
import 'package:komodo_defi_types/komodo_defi_types.dart';
import 'package:komodo_defi_types/komodo_defi_type_utils.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
Expand Down Expand Up @@ -82,7 +83,7 @@ class KdfStartupConfig {
int? hdAccountId,
bool allowWeakPassword = false,
int rpcPort = 7783,
int netid = 8762,
int netid = kDefaultNetId,
String gui = 'komodo-defi-flutter-auth',
bool https = false,
bool rpcLocalOnly = true,
Expand Down Expand Up @@ -168,6 +169,11 @@ class KdfStartupConfig {
}) async {
final (String? home, String? dbDir) = await _getAndSetupUserHome();

final (
seedNodes: seeds,
netId: netId,
) = await SeedNodeService.fetchSeedNodes();

return KdfStartupConfig._(
walletName: null,
walletPassword: null,
Expand All @@ -176,7 +182,7 @@ class KdfStartupConfig {
userHome: home,
dbDir: dbDir,
allowWeakPassword: true,
netid: 8762,
netid: netId,
gui: 'komodo-defi-flutter-auth',
coins: await _fetchCoinsData(),
https: false,
Expand All @@ -187,7 +193,7 @@ class KdfStartupConfig {
allowRegistrations: false,
enableHd: false,
disableP2p: false,
seedNodes: await SeedNodeService.fetchSeedNodes(),
seedNodes: seeds,
iAmSeed: false,
isBootstrapNode: false,
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
import 'package:komodo_coin_updates/komodo_coin_updates.dart';
import 'package:flutter/foundation.dart';
import 'package:komodo_defi_framework/src/config/kdf_logging_config.dart';
import 'package:komodo_defi_framework/src/config/seed_node_validator.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart';

/// Service class responsible for fetching and managing seed nodes.
///
/// This class follows the Single Responsibility Principle by focusing
///
/// This class follows the Single Responsibility Principle by focusing
/// solely on seed node acquisition and management.
class SeedNodeService {
/// Fetches seed nodes from the remote configuration with fallback to defaults.
///
/// This method attempts to fetch the latest seed nodes from the Komodo Platform
/// repository and converts them to the string format expected by the KDF startup
/// This method attempts to fetch the latest seed nodes from the Komodo Platform
/// repository and converts them to the string format expected by the KDF startup
/// configuration.
///
/// Returns a list of seed node host addresses. If fetching fails, returns
/// the hardcoded default seed nodes as a fallback.
static Future<List<String>> fetchSeedNodes() async {
static Future<({List<String> seedNodes, int netId})> fetchSeedNodes({
bool filterForWeb = kIsWeb,
}) async {
try {
final seedNodes = await SeedNodeUpdater.fetchSeedNodes();
return SeedNodeUpdater.seedNodesToStringList(seedNodes);
final (
seedNodes: nodes,
netId: netId,
) = await SeedNodeUpdater.fetchSeedNodes(filterForWeb: filterForWeb);

return (
seedNodes: SeedNodeUpdater.seedNodesToStringList(nodes),
netId: netId,
);
} catch (e) {
if (KdfLoggingConfig.verboseLogging) {
print('WARN Failed to fetch seed nodes from remote: $e');
print('WARN Falling back to default seed nodes');
}
return getDefaultSeedNodes();
return (
seedNodes: getDefaultSeedNodes(),
netId: kDefaultNetId,
);
}
}

Expand Down Expand Up @@ -63,7 +77,8 @@ class SeedNodeService {

// Fetch remote seed nodes or use defaults
if (fetchRemote) {
return await fetchSeedNodes();
final result = await fetchSeedNodes();
return result.seedNodes;
} else {
return getDefaultSeedNodes();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ extension KdfExtensions on KdfAuthService {
}

// Fetch seed nodes using the dedicated service
final seedNodes = await SeedNodeService.fetchSeedNodes();
final (seedNodes: seedNodes, netId: netId) =
await SeedNodeService.fetchSeedNodes();

return KdfStartupConfig.generateWithDefaults(
walletName: walletName,
Expand All @@ -190,6 +191,7 @@ extension KdfExtensions on KdfAuthService {
enableHd: hdEnabled,
allowWeakPassword: allowWeakPassword,
seedNodes: seedNodes,
netid: netId,
);
}
}
2 changes: 2 additions & 0 deletions packages/komodo_defi_types/komodo_defi_constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'package:komodo_defi_types/komodo_defi_types.dart' show kDefaultNetId;

2 changes: 2 additions & 0 deletions packages/komodo_defi_types/lib/komodo_defi_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
/// More dartdocs go here.
library;

export 'src/constants.dart';

export 'src/api/api_client.dart';
export 'src/assets/asset.dart';
export 'src/assets/asset_id.dart';
Expand Down
5 changes: 5 additions & 0 deletions packages/komodo_defi_types/lib/src/constants.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Shared constants used across the Komodo DeFi SDK packages.
library komodo_defi_types.constants;

/// Default network identifier used by seed nodes and framework configuration.
const int kDefaultNetId = 8762;
26 changes: 24 additions & 2 deletions packages/komodo_defi_types/lib/src/seed_node/seed_node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ class SeedNode {
const SeedNode({
required this.name,
required this.host,
required this.type,
required this.wss,
required this.netId,
required this.contact,
});

Expand All @@ -17,11 +20,23 @@ class SeedNode {
/// Contact information for the seed node
final List<SeedNodeContact> contact;

/// The connection type of the seed node (e.g. domain or ip)
final String type;

/// Whether the seed node supports secure websockets
final bool wss;

/// The network identifier for the seed node
final int netId;

/// Creates a [SeedNode] from a JSON map.
factory SeedNode.fromJson(JsonMap json) {
return SeedNode(
name: json.value<String>('name'),
host: json.value<String>('host'),
type: json.value<String>('type'),
wss: json.value<bool>('wss'),
netId: json.value<int>('netid'),
contact: json
.value<List<dynamic>>('contact')
.cast<JsonMap>()
Expand All @@ -35,6 +50,9 @@ class SeedNode {
return {
'name': name,
'host': host,
'type': type,
'wss': wss,
'netid': netId,
'contact': contact.map((c) => c.toJson()).toList(),
};
}
Expand All @@ -50,14 +68,18 @@ class SeedNode {
return other is SeedNode &&
other.name == name &&
other.host == host &&
other.type == type &&
other.wss == wss &&
other.netId == netId &&
_listEquals(other.contact, contact);
}

@override
int get hashCode => Object.hash(name, host, contact);
int get hashCode => Object.hash(name, host, type, wss, netId, Object.hashAll(contact));

@override
String toString() => 'SeedNode(name: $name, host: $host, contact: $contact)';
String toString() =>
'SeedNode(name: $name, host: $host, type: $type, wss: $wss, netId: $netId, contact: $contact)';

/// Helper method to compare lists
bool _listEquals<T>(List<T>? a, List<T>? b) {
Expand Down
2 changes: 2 additions & 0 deletions packages/komodo_defi_types/lib/src/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export 'auth/kdf_user.dart';
export 'coin/coin.dart';
export 'coin_classes/coin_subclasses.dart';
export 'coin_classes/protocol_class.dart';
export 'constants.dart';
export 'cryptography/mnemonic.dart';
export 'exceptions/http_exceptions.dart';
export 'exported_rpc_types.dart';
Expand All @@ -45,6 +46,7 @@ export 'public_key/pubkey.dart';
export 'public_key/pubkey_strategy.dart';
export 'public_key/token_balance_map.dart';
export 'public_key/wallet_balance.dart';
export 'seed_node/seed_node.dart';
export 'transactions/asset_transaction_history_id.dart';
export 'transactions/balance_changes.dart';
export 'transactions/fee_info.dart';
Expand Down
21 changes: 21 additions & 0 deletions packages/komodo_defi_types/test/seed_node_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ void main() {
final json = {
'name': 'seed-node-1',
'host': 'seed01.kmdefi.net',
'type': 'domain',
'wss': true,
'netid': 8762,
'contact': [
{'email': 'admin@example.com'}
]
Expand All @@ -24,6 +27,9 @@ void main() {
final seedNode = SeedNode(
name: 'seed-node-2',
host: 'seed02.kmdefi.net',
type: 'domain',
wss: true,
netId: 8762,
contact: [
SeedNodeContact(email: 'test@example.com'),
],
Expand All @@ -44,13 +50,19 @@ void main() {
{
'name': 'seed-node-1',
'host': 'seed01.kmdefi.net',
'type': 'domain',
'wss': true,
'netid': 8762,
'contact': [
{'email': ''}
]
},
{
'name': 'seed-node-2',
'host': 'seed02.kmdefi.net',
'type': 'domain',
'wss': true,
'netid': 8762,
'contact': [
{'email': ''}
]
Expand All @@ -70,18 +82,27 @@ void main() {
final seedNode1 = SeedNode(
name: 'test',
host: 'example.com',
type: 'domain',
wss: true,
netId: 8762,
contact: [SeedNodeContact(email: 'test@example.com')],
);

final seedNode2 = SeedNode(
name: 'test',
host: 'example.com',
type: 'domain',
wss: true,
netId: 8762,
contact: [SeedNodeContact(email: 'test@example.com')],
);

final seedNode3 = SeedNode(
name: 'different',
host: 'example.com',
type: 'domain',
wss: true,
netId: 8762,
contact: [SeedNodeContact(email: 'test@example.com')],
);

Expand Down
Loading