@dignetwork/chia-block-listener 0.1.15 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.toml CHANGED
@@ -37,6 +37,7 @@ dirs = "5"
37
37
 
38
38
  # Local crates
39
39
  chia-generator-parser = { path = "./crate/chia-generator-parser" }
40
+ dns-discovery = { path = "./crate/dns-discovery" }
40
41
 
41
42
  [build-dependencies]
42
43
  napi-build = "2"
@@ -0,0 +1,291 @@
1
+ # DNS Discovery NAPI Interface
2
+
3
+ A comprehensive Node.js interface for discovering Chia network peers using DNS introducers with proper IPv4/IPv6 support.
4
+
5
+ ## Overview
6
+
7
+ The DNS Discovery NAPI interface exposes the functionality of the isolated `dns-discovery` Rust crate to JavaScript/TypeScript applications. It provides separate IPv4 (A records) and IPv6 (AAAA records) lookups, returning well-structured results that can be used directly with the IPv6-capable peer connection system.
8
+
9
+ ## Key Features
10
+
11
+ - ✅ **Dual Stack Support**: Separate IPv4 and IPv6 peer discovery
12
+ - ✅ **Proper DNS Lookups**: Uses A records for IPv4, AAAA records for IPv6
13
+ - ✅ **Built-in Networks**: Ready-to-use configurations for mainnet and testnet11
14
+ - ✅ **Custom Introducers**: Support for custom DNS introducers
15
+ - ✅ **Type Safety**: Full TypeScript definitions included
16
+ - ✅ **Multiple Interfaces**: Both class-based and functional APIs
17
+ - ✅ **IPv6 URL Formatting**: Automatic bracket formatting for IPv6 addresses
18
+
19
+ ## Installation
20
+
21
+ The DNS discovery interface is included in the main chia-block-listener package:
22
+
23
+ ```javascript
24
+ const {
25
+ DnsDiscoveryClient
26
+ } = require('chia-block-listener');
27
+ ```
28
+
29
+ ## API Reference
30
+
31
+ ### Class-Based Interface
32
+
33
+ #### `DnsDiscoveryClient`
34
+
35
+ Main class for DNS discovery operations:
36
+
37
+ ```javascript
38
+ const client = new DnsDiscoveryClient();
39
+ ```
40
+
41
+ **Methods:**
42
+
43
+ - `discoverMainnetPeers()` → `Promise<DiscoveryResultJS>`
44
+ - `discoverTestnet11Peers()` → `Promise<DiscoveryResultJS>`
45
+ - `discoverPeers(introducers: string[], port: number)` → `Promise<DiscoveryResultJS>`
46
+ - `resolveIpv4(hostname: string)` → `Promise<AddressResult>`
47
+ - `resolveIpv6(hostname: string)` → `Promise<AddressResult>`
48
+ - `resolveBoth(hostname: string, port: number)` → `Promise<DiscoveryResultJS>`
49
+
50
+
51
+
52
+ ## Data Types
53
+
54
+ ### `DiscoveryResultJS`
55
+
56
+ Main result type for peer discovery:
57
+
58
+ ```typescript
59
+ interface DiscoveryResultJS {
60
+ ipv4Peers: PeerAddressJS[]; // IPv4 peer addresses
61
+ ipv6Peers: PeerAddressJS[]; // IPv6 peer addresses
62
+ totalCount: number; // Total peers found
63
+ }
64
+ ```
65
+
66
+ ### `PeerAddressJS`
67
+
68
+ Individual peer address:
69
+
70
+ ```typescript
71
+ interface PeerAddressJS {
72
+ host: string; // IP address as string
73
+ port: number; // Port number
74
+ isIpv6: boolean; // Protocol indicator
75
+ displayAddress: string; // Formatted for display/URLs
76
+ }
77
+ ```
78
+
79
+ ### `AddressResult`
80
+
81
+ Result for individual hostname resolution:
82
+
83
+ ```typescript
84
+ interface AddressResult {
85
+ addresses: string[]; // List of IP addresses
86
+ count: number; // Number of addresses
87
+ }
88
+ ```
89
+
90
+ ## Usage Examples
91
+
92
+ ### Basic Peer Discovery
93
+
94
+ ```javascript
95
+ const { DnsDiscoveryClient } = require('chia-block-listener');
96
+
97
+ async function discoverPeers() {
98
+ const client = new DnsDiscoveryClient();
99
+
100
+ // Discover mainnet peers
101
+ const result = await client.discoverMainnetPeers();
102
+
103
+ console.log(`Found ${result.totalCount} total peers:`);
104
+ console.log(` IPv4: ${result.ipv4Peers.length}`);
105
+ console.log(` IPv6: ${result.ipv6Peers.length}`);
106
+
107
+ // Use with peer connections
108
+ for (const peer of result.ipv4Peers) {
109
+ console.log(`IPv4 peer: ${peer.displayAddress}`);
110
+ // Connect using: peer.host, peer.port
111
+ }
112
+
113
+ for (const peer of result.ipv6Peers) {
114
+ console.log(`IPv6 peer: ${peer.displayAddress}`); // [2001:db8::1]:8444
115
+ // Connect using: peer.host, peer.port
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### Simple Discovery
121
+
122
+ ```javascript
123
+ const { DnsDiscoveryClient } = require('chia-block-listener');
124
+
125
+ // Simple mainnet discovery
126
+ const client = new DnsDiscoveryClient();
127
+ const peers = await client.discoverMainnetPeers();
128
+ console.log(`Found ${peers.ipv4Peers.length + peers.ipv6Peers.length} peers`);
129
+ ```
130
+
131
+ ### Custom Introducers
132
+
133
+ ```javascript
134
+ const client = new DnsDiscoveryClient();
135
+
136
+ // Use custom introducers
137
+ const customIntroducers = [
138
+ 'seeder.dexie.space',
139
+ 'chia.hoffmang.com'
140
+ ];
141
+
142
+ const result = await client.discoverPeers(customIntroducers, 8444);
143
+ console.log(`Custom discovery found ${result.totalCount} peers`);
144
+ ```
145
+
146
+ ### Individual DNS Resolution
147
+
148
+ ```javascript
149
+ const client = new DnsDiscoveryClient();
150
+
151
+ // Resolve specific protocols
152
+ const hostname = 'dns-introducer.chia.net';
153
+
154
+ try {
155
+ const ipv4 = await client.resolveIpv4(hostname);
156
+ console.log(`IPv4 addresses: ${ipv4.addresses.join(', ')}`);
157
+ } catch (error) {
158
+ console.log(`IPv4 resolution failed: ${error.message}`);
159
+ }
160
+
161
+ try {
162
+ const ipv6 = await client.resolveIpv6(hostname);
163
+ console.log(`IPv6 addresses: ${ipv6.addresses.join(', ')}`);
164
+ } catch (error) {
165
+ console.log(`IPv6 resolution failed: ${error.message}`);
166
+ }
167
+
168
+ // Or resolve both at once
169
+ const both = await client.resolveBoth(hostname, 8444);
170
+ console.log(`Combined: ${both.totalCount} addresses`);
171
+ ```
172
+
173
+ ### Integration with Existing Peer Pool
174
+
175
+ ```javascript
176
+ const { ChiaPeerPool, DnsDiscoveryClient } = require('chia-block-listener');
177
+
178
+ async function setupPeerPool() {
179
+ const pool = new ChiaPeerPool();
180
+ const discovery = new DnsDiscoveryClient();
181
+
182
+ // Discover peers
183
+ const peers = await discovery.discoverMainnetPeers();
184
+
185
+ // Add IPv4 peers to pool
186
+ for (const peer of peers.ipv4Peers.slice(0, 5)) {
187
+ await pool.addPeer(peer.host, peer.port, 'mainnet');
188
+ console.log(`Added IPv4 peer: ${peer.displayAddress}`);
189
+ }
190
+
191
+ // Add IPv6 peers to pool
192
+ for (const peer of peers.ipv6Peers.slice(0, 5)) {
193
+ await pool.addPeer(peer.host, peer.port, 'mainnet');
194
+ console.log(`Added IPv6 peer: ${peer.displayAddress}`);
195
+ }
196
+
197
+ return pool;
198
+ }
199
+ ```
200
+
201
+ ### Error Handling
202
+
203
+ ```javascript
204
+ const client = new DnsDiscoveryClient();
205
+
206
+ try {
207
+ const result = await client.discoverMainnetPeers();
208
+ // Handle success
209
+ } catch (error) {
210
+ console.error('Discovery failed:', error.message);
211
+
212
+ // Error types: 'ResolutionFailed', 'NoPeersFound', 'ResolverCreationFailed'
213
+ if (error.message.includes('NoPeersFound')) {
214
+ console.log('No peers found from any introducer');
215
+ }
216
+ }
217
+ ```
218
+
219
+ ### TypeScript Usage
220
+
221
+ ```typescript
222
+ import {
223
+ DnsDiscoveryClient,
224
+ DiscoveryResultJS,
225
+ PeerAddressJS
226
+ } from 'chia-block-listener';
227
+
228
+ async function typedDiscovery(): Promise<void> {
229
+ const client = new DnsDiscoveryClient();
230
+
231
+ const result: DiscoveryResultJS = await client.discoverMainnetPeers();
232
+
233
+ // Type-safe access
234
+ result.ipv4Peers.forEach((peer: PeerAddressJS) => {
235
+ console.log(`IPv4: ${peer.host}:${peer.port}`);
236
+ });
237
+
238
+ result.ipv6Peers.forEach((peer: PeerAddressJS) => {
239
+ console.log(`IPv6: ${peer.displayAddress}`);
240
+ });
241
+ }
242
+ ```
243
+
244
+ ## Performance Considerations
245
+
246
+ - **Caching**: DNS results are not cached; implement your own caching if needed
247
+ - **Concurrency**: All DNS lookups are performed concurrently for maximum speed
248
+ - **Timeout**: DNS queries have built-in timeouts (configured in the Rust crate)
249
+ - **Randomization**: Peer lists are automatically shuffled for load distribution
250
+
251
+ ## Troubleshooting
252
+
253
+ ### Common Issues
254
+
255
+ 1. **No peers found**: Check network connectivity and DNS resolution
256
+ 2. **IPv6 resolution fails**: IPv6 may not be available in all environments
257
+ 3. **Timeout errors**: Network or DNS server issues
258
+
259
+ ### Debug Logging
260
+
261
+ Enable debug logging to see DNS resolution details:
262
+
263
+ ```javascript
264
+ const { initTracing } = require('chia-block-listener');
265
+
266
+ // Initialize tracing for debug output
267
+ initTracing();
268
+ ```
269
+
270
+ ## Comparison with JavaScript Version
271
+
272
+ The Rust-based DNS discovery provides several advantages over the JavaScript version in `coin-monitor.js`:
273
+
274
+ | Feature | JavaScript Version | Rust NAPI Version |
275
+ |---------|-------------------|------------------|
276
+ | **DNS Lookups** | Generic `dns.lookup()` | Explicit A/AAAA records |
277
+ | **IPv6 Support** | Manual detection | Built-in IPv6 handling |
278
+ | **Type Safety** | Runtime checks | Compile-time guarantees |
279
+ | **Performance** | Single-threaded | Concurrent resolution |
280
+ | **Error Handling** | Basic try/catch | Detailed error types |
281
+ | **Address Formatting** | Manual brackets | Automatic formatting |
282
+
283
+ ## Future Enhancements
284
+
285
+ Planned improvements:
286
+
287
+ - [ ] DNS caching with TTL support
288
+ - [ ] Custom DNS server configuration
289
+ - [ ] Peer health checking integration
290
+ - [ ] Metrics and monitoring hooks
291
+ - [ ] IPv6 preference configuration
package/README.md CHANGED
@@ -14,7 +14,7 @@ A high-performance Chia blockchain listener for Node.js, built with Rust and NAP
14
14
  - **Historical Block Access**: Retrieve blocks by height or ranges with automatic load balancing
15
15
  - **Connection Pool**: ChiaPeerPool provides automatic load balancing and rate limiting for historical queries
16
16
  - **Peak Height Tracking**: Monitor blockchain sync progress across all connected peers
17
- - **DNS Peer Discovery**: Automatic peer discovery using Chia network DNS introducers
17
+ - **DNS Peer Discovery**: Automatic peer discovery using Chia network DNS introducers with IPv4/IPv6 support
18
18
  - **Cross-platform Support**: Works on Windows, macOS, and Linux (x64 and ARM64)
19
19
  - **TypeScript Support**: Complete TypeScript definitions with IntelliSense
20
20
 
@@ -249,6 +249,70 @@ Fired when a new highest blockchain peak is discovered.
249
249
 
250
250
  **Callback:** `(event: NewPeakHeightEvent) => void`
251
251
 
252
+ ### DnsDiscoveryClient Class
253
+
254
+ The `DnsDiscoveryClient` provides automatic peer discovery using Chia network DNS introducers with full IPv4 and IPv6 support.
255
+
256
+ #### Constructor
257
+
258
+ ```javascript
259
+ const client = new DnsDiscoveryClient()
260
+ ```
261
+
262
+ Creates a new DNS discovery client instance.
263
+
264
+ #### Methods
265
+
266
+ ##### `discoverMainnetPeers(): Promise<DiscoveryResultJS>`
267
+
268
+ Discovers peers for Chia mainnet using built-in DNS introducers.
269
+
270
+ **Returns:** Promise resolving to discovery results with separate IPv4 and IPv6 peer lists
271
+
272
+ ##### `discoverTestnet11Peers(): Promise<DiscoveryResultJS>`
273
+
274
+ Discovers peers for Chia testnet11 using built-in DNS introducers.
275
+
276
+ **Returns:** Promise resolving to discovery results
277
+
278
+ ##### `discoverPeers(introducers, port): Promise<DiscoveryResultJS>`
279
+
280
+ Discovers peers using custom DNS introducers.
281
+
282
+ **Parameters:**
283
+ - `introducers` (string[]): Array of DNS introducer hostnames
284
+ - `port` (number): Default port for discovered peers
285
+
286
+ **Returns:** Promise resolving to discovery results
287
+
288
+ ##### `resolveIpv4(hostname): Promise<AddressResult>`
289
+
290
+ Resolves IPv4 addresses (A records) for a hostname.
291
+
292
+ **Parameters:**
293
+ - `hostname` (string): Hostname to resolve
294
+
295
+ **Returns:** Promise resolving to IPv4 addresses
296
+
297
+ ##### `resolveIpv6(hostname): Promise<AddressResult>`
298
+
299
+ Resolves IPv6 addresses (AAAA records) for a hostname.
300
+
301
+ **Parameters:**
302
+ - `hostname` (string): Hostname to resolve
303
+
304
+ **Returns:** Promise resolving to IPv6 addresses
305
+
306
+ ##### `resolveBoth(hostname, port): Promise<DiscoveryResultJS>`
307
+
308
+ Resolves both IPv4 and IPv6 addresses for a hostname.
309
+
310
+ **Parameters:**
311
+ - `hostname` (string): Hostname to resolve
312
+ - `port` (number): Port for the peer addresses
313
+
314
+ **Returns:** Promise resolving to discovery results
315
+
252
316
  ### Event Data Types
253
317
 
254
318
  #### `BlockReceivedEvent`
@@ -321,6 +385,36 @@ interface CoinSpend {
321
385
  }
322
386
  ```
323
387
 
388
+ #### `DiscoveryResultJS`
389
+
390
+ ```typescript
391
+ interface DiscoveryResultJS {
392
+ ipv4Peers: PeerAddressJS[] // IPv4 peer addresses
393
+ ipv6Peers: PeerAddressJS[] // IPv6 peer addresses
394
+ totalCount: number // Total peers found
395
+ }
396
+ ```
397
+
398
+ #### `PeerAddressJS`
399
+
400
+ ```typescript
401
+ interface PeerAddressJS {
402
+ host: string // IP address as string
403
+ port: number // Port number
404
+ isIpv6: boolean // Protocol indicator
405
+ displayAddress: string // Formatted for display/URLs
406
+ }
407
+ ```
408
+
409
+ #### `AddressResult`
410
+
411
+ ```typescript
412
+ interface AddressResult {
413
+ addresses: string[] // List of IP addresses
414
+ count: number // Number of addresses
415
+ }
416
+ ```
417
+
324
418
  ## ChiaPeerPool Usage
325
419
 
326
420
  The `ChiaPeerPool` is designed for efficiently retrieving historical blocks with automatic load balancing and intelligent failover across multiple peers. When a peer fails to provide a block or experiences protocol errors, the pool automatically tries alternative peers and removes problematic peers from the pool.
@@ -524,16 +618,159 @@ setInterval(async () => {
524
618
 
525
619
  Both classes can be used together in the same application for different purposes.
526
620
 
621
+ ## DNS Discovery Usage
622
+
623
+ The `DnsDiscoveryClient` enables automatic discovery of Chia network peers using DNS introducers, with full support for both IPv4 and IPv6 addresses.
624
+
625
+ ### Basic DNS Discovery
626
+
627
+ ```javascript
628
+ const { DnsDiscoveryClient, initTracing } = require('@dignetwork/chia-block-listener')
629
+
630
+ async function discoverPeers() {
631
+ // Initialize tracing
632
+ initTracing()
633
+
634
+ // Create DNS discovery client
635
+ const client = new DnsDiscoveryClient()
636
+
637
+ // Discover mainnet peers
638
+ const result = await client.discoverMainnetPeers()
639
+
640
+ console.log(`Found ${result.totalCount} total peers:`)
641
+ console.log(` IPv4 peers: ${result.ipv4Peers.length}`)
642
+ console.log(` IPv6 peers: ${result.ipv6Peers.length}`)
643
+
644
+ // Use with peer connections
645
+ for (const peer of result.ipv4Peers.slice(0, 3)) {
646
+ console.log(`IPv4 peer: ${peer.displayAddress}`)
647
+ // peer.host and peer.port can be used with addPeer()
648
+ }
649
+
650
+ for (const peer of result.ipv6Peers.slice(0, 3)) {
651
+ console.log(`IPv6 peer: ${peer.displayAddress}`) // [2001:db8::1]:8444
652
+ // IPv6 addresses are properly formatted with brackets
653
+ }
654
+ }
655
+
656
+ discoverPeers().catch(console.error)
657
+ ```
658
+
659
+ ### Integration with Peer Pool
660
+
661
+ ```javascript
662
+ const { ChiaPeerPool, DnsDiscoveryClient } = require('@dignetwork/chia-block-listener')
663
+
664
+ async function setupPoolWithDnsDiscovery() {
665
+ const pool = new ChiaPeerPool()
666
+ const discovery = new DnsDiscoveryClient()
667
+
668
+ // Discover peers automatically
669
+ const peers = await discovery.discoverMainnetPeers()
670
+
671
+ // Add discovered peers to pool (both IPv4 and IPv6)
672
+ const allPeers = [...peers.ipv4Peers, ...peers.ipv6Peers]
673
+ for (const peer of allPeers.slice(0, 5)) {
674
+ await pool.addPeer(peer.host, peer.port, 'mainnet')
675
+ console.log(`Added peer: ${peer.displayAddress}`)
676
+ }
677
+
678
+ // Now use the pool for block retrieval
679
+ const block = await pool.getBlockByHeight(5000000)
680
+ console.log(`Retrieved block ${block.height}`)
681
+
682
+ await pool.shutdown()
683
+ }
684
+
685
+ setupPoolWithDnsDiscovery().catch(console.error)
686
+ ```
687
+
688
+ ### Custom DNS Introducers
689
+
690
+ ```javascript
691
+ const client = new DnsDiscoveryClient()
692
+
693
+ // Use custom introducers
694
+ const customIntroducers = [
695
+ 'seeder.dexie.space',
696
+ 'chia.hoffmang.com'
697
+ ]
698
+
699
+ const result = await client.discoverPeers(customIntroducers, 8444)
700
+ console.log(`Found ${result.totalCount} peers from custom introducers`)
701
+ ```
702
+
703
+ ### Individual DNS Resolution
704
+
705
+ ```javascript
706
+ const client = new DnsDiscoveryClient()
707
+ const hostname = 'dns-introducer.chia.net'
708
+
709
+ // Resolve specific protocols
710
+ try {
711
+ const ipv4 = await client.resolveIpv4(hostname)
712
+ console.log(`IPv4 addresses: ${ipv4.addresses.join(', ')}`)
713
+ } catch (error) {
714
+ console.log(`IPv4 resolution failed: ${error.message}`)
715
+ }
716
+
717
+ try {
718
+ const ipv6 = await client.resolveIpv6(hostname)
719
+ console.log(`IPv6 addresses: ${ipv6.addresses.join(', ')}`)
720
+ } catch (error) {
721
+ console.log(`IPv6 resolution failed: ${error.message}`)
722
+ }
723
+
724
+ // Or resolve both at once
725
+ const both = await client.resolveBoth(hostname, 8444)
726
+ console.log(`Combined: ${both.totalCount} addresses`)
727
+ ```
728
+
729
+
730
+
731
+ ### Error Handling
732
+
733
+ ```javascript
734
+ const client = new DnsDiscoveryClient()
735
+
736
+ try {
737
+ const result = await client.discoverMainnetPeers()
738
+ console.log(`Discovery successful: ${result.totalCount} peers`)
739
+ } catch (error) {
740
+ console.error('Discovery failed:', error.message)
741
+
742
+ // Handle different error types
743
+ if (error.message.includes('NoPeersFound')) {
744
+ console.log('No peers found from any introducer')
745
+ } else if (error.message.includes('ResolutionFailed')) {
746
+ console.log('DNS resolution failed')
747
+ }
748
+ }
749
+ ```
750
+
751
+ ### Key Features
752
+
753
+ - **Dual Stack Support**: Separate IPv4 and IPv6 peer lists
754
+ - **Proper DNS Lookups**: Uses A records for IPv4, AAAA records for IPv6
755
+ - **Built-in Networks**: Ready configurations for mainnet and testnet11
756
+ - **Custom Introducers**: Support for any DNS introducers
757
+ - **IPv6 URL Formatting**: Automatic bracket formatting for IPv6 addresses
758
+ - **Type Safety**: Full TypeScript support with detailed type definitions
759
+
527
760
  ## TypeScript Usage
528
761
 
529
762
  ```typescript
530
763
  import {
531
764
  ChiaBlockListener,
532
765
  ChiaPeerPool,
766
+ DnsDiscoveryClient,
533
767
  BlockReceivedEvent,
534
768
  PeerConnectedEvent,
535
769
  PeerDisconnectedEvent,
536
770
  NewPeakHeightEvent,
771
+ DiscoveryResultJS,
772
+ PeerAddressJS,
773
+ AddressResult,
537
774
  CoinRecord,
538
775
  CoinSpend,
539
776
  initTracing,
@@ -617,6 +854,29 @@ async function fetchHistoricalData() {
617
854
  console.log(`Pool has ${peers.length} active peers`)
618
855
  console.log(`Current peak: ${peak || 'No peak yet'}`)
619
856
  }
857
+
858
+ // TypeScript DNS Discovery
859
+ async function typedDnsDiscovery(): Promise<void> {
860
+ const client = new DnsDiscoveryClient()
861
+
862
+ // Type-safe discovery
863
+ const result: DiscoveryResultJS = await client.discoverMainnetPeers()
864
+
865
+ // Access with full type safety
866
+ result.ipv4Peers.forEach((peer: PeerAddressJS) => {
867
+ console.log(`IPv4: ${peer.host}:${peer.port} (${peer.displayAddress})`)
868
+ })
869
+
870
+ result.ipv6Peers.forEach((peer: PeerAddressJS) => {
871
+ console.log(`IPv6: ${peer.displayAddress} (isIpv6: ${peer.isIpv6})`)
872
+ })
873
+
874
+ // Individual resolution with types
875
+ const ipv4Result: AddressResult = await client.resolveIpv4('dns-introducer.chia.net')
876
+ const ipv6Result: AddressResult = await client.resolveIpv6('dns-introducer.chia.net')
877
+
878
+ console.log(`IPv4 count: ${ipv4Result.count}, IPv6 count: ${ipv6Result.count}`)
879
+ }
620
880
  ```
621
881
 
622
882
  ## Advanced Usage
@@ -689,6 +949,8 @@ console.log(eventTypes)
689
949
  // Output: { blockReceived: "blockReceived", peerConnected: "peerConnected", peerDisconnected: "peerDisconnected" }
690
950
  ```
691
951
 
952
+
953
+
692
954
  ## Performance Tips
693
955
 
694
956
  1. **Use specific event handlers**: Only listen for the events you need
@@ -0,0 +1,16 @@
1
+ [package]
2
+ name = "dns-discovery"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [dependencies]
7
+ tokio = { version = "1.0", features = ["full"] }
8
+ trust-dns-resolver = "0.23"
9
+ serde = { version = "1.0", features = ["derive"] }
10
+ thiserror = "1.0"
11
+ tracing = "0.1"
12
+ rand = "0.8"
13
+
14
+ [dev-dependencies]
15
+ tokio-test = "0.4"
16
+ tracing-subscriber = "0.3"