@dignetwork/chia-block-listener 0.1.6 → 0.1.8

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.
@@ -53,19 +53,20 @@ jobs:
53
53
  settings:
54
54
  - host: macos-latest
55
55
  target: x86_64-apple-darwin
56
- build: npm run build -- --target x86_64-apple-darwin
56
+ build: npm run build -- --target x86_64-apple-darwin && node scripts/post-build.js
57
57
  - host: windows-latest
58
- build: npm run build -- --target x86_64-pc-windows-msvc
58
+ build: npm run build -- --target x86_64-pc-windows-msvc && node scripts/post-build.js
59
59
  target: x86_64-pc-windows-msvc
60
60
  - host: ubuntu-latest
61
61
  target: x86_64-unknown-linux-gnu
62
62
  build: |
63
63
  set -e &&
64
64
  npm run build -- --target x86_64-unknown-linux-gnu &&
65
+ node scripts/post-build.js &&
65
66
  strip *.node
66
67
  - host: macos-latest
67
68
  target: aarch64-apple-darwin
68
- build: npm run build -- --target aarch64-apple-darwin
69
+ build: npm run build -- --target aarch64-apple-darwin && node scripts/post-build.js
69
70
  - host: ubuntu-latest
70
71
  target: aarch64-unknown-linux-gnu
71
72
  setup: |
@@ -74,7 +75,8 @@ jobs:
74
75
  build: |
75
76
  set -e &&
76
77
  export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc &&
77
- npm run build -- --target aarch64-unknown-linux-gnu
78
+ npm run build -- --target aarch64-unknown-linux-gnu &&
79
+ node scripts/post-build.js
78
80
  name: stable - ${{ matrix.settings.target }} - node@22
79
81
  runs-on: ${{ matrix.settings.host }}
80
82
  steps:
@@ -191,7 +193,7 @@ jobs:
191
193
  node:
192
194
  - '20'
193
195
  - '22'
194
- runs-on: ubuntu-latest
196
+ runs-on: ubuntu-24.04
195
197
  steps:
196
198
  - uses: actions/checkout@v4
197
199
  - name: Setup node
@@ -250,18 +252,48 @@ jobs:
250
252
  uses: addnab/docker-run-action@v3
251
253
  with:
252
254
  image: ubuntu:24.04
253
- options: '--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build'
255
+ options: '--platform linux/arm64 -v ${{ github.workspace }}:/workspace -w /workspace'
254
256
  run: |
255
257
  set -e
258
+ export DEBIAN_FRONTEND=noninteractive
256
259
  apt-get update
257
- apt-get install -y curl
258
- curl -fsSL https://deb.nodesource.com/setup_${{ matrix.node }}.x | bash -
259
- apt-get install -y nodejs
260
+ apt-get install -y curl ca-certificates xz-utils
261
+
262
+ # Install Node.js using a different approach - download pre-built binary directly
263
+ NODE_VERSION="${{ matrix.node }}"
264
+ case "$NODE_VERSION" in
265
+ "20")
266
+ FULL_VERSION="20.18.0"
267
+ ;;
268
+ "22")
269
+ FULL_VERSION="22.11.0" # Use slightly older version of 22 for stability
270
+ ;;
271
+ *)
272
+ echo "Unsupported Node version: $NODE_VERSION"
273
+ exit 1
274
+ ;;
275
+ esac
276
+
277
+ # Download and install Node.js binary
278
+ cd /tmp
279
+ curl -fsSL "https://nodejs.org/dist/v${FULL_VERSION}/node-v${FULL_VERSION}-linux-arm64.tar.xz" -o node.tar.xz
280
+ tar -xf node.tar.xz
281
+ cp -r "node-v${FULL_VERSION}-linux-arm64"/* /usr/local/
282
+ rm -rf node.tar.xz "node-v${FULL_VERSION}-linux-arm64"
283
+
284
+ # Return to workspace
285
+ cd /workspace
286
+
287
+ # Verify we're in the right directory and have the required files
288
+ pwd
289
+ ls -la
290
+ echo "Looking for package-lock.json:"
291
+ ls -la package-lock.json || echo "package-lock.json not found"
292
+
260
293
  node --version
261
294
  npm --version
262
295
  npm ci
263
296
  npm test
264
- ls -la
265
297
 
266
298
  publish:
267
299
  name: Publish
package/README.md CHANGED
@@ -1,22 +1,17 @@
1
- # Proof of Work
1
+ # Chia Block Listener
2
2
 
3
- A high-performance Bitcoin-compatible proof of work library for Node.js, built with Rust and NAPI bindings. This library provides efficient mining capabilities using Bitcoin's target-based difficulty system with double SHA-256 hashing.
3
+ A high-performance Chia blockchain listener for Node.js, built with Rust and NAPI bindings. This library provides real-time monitoring of the Chia blockchain with efficient peer connections and block parsing capabilities.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Bitcoin-Compatible**: Uses Bitcoin's target-based difficulty system with double SHA-256 hashing
8
- - **High Performance**: Written in Rust for maximum mining efficiency
9
- - **Asynchronous Mining**: Non-blocking proof of work computation that won't freeze your application
10
- - **Cancellable Operations**: Start mining with ability to cancel anytime using handles
11
- - **Progress Tracking**: Real-time progress monitoring with attempt counts and timing
12
- - **Unlimited Attempts**: Mine until solution is found (unless explicitly limited)
13
- - **Nonce Verification**: Verify that a nonce meets difficulty requirements
14
- - **Standardized Verification**: Consensus-critical verification with algorithm version validation
15
- - **Difficulty Analysis**: Calculate difficulty levels from hash values
16
- - **Security Features**: Tamper-resistant verification with algorithm immutability
17
- - **Cross-platform Support**: Builds for Windows, macOS, and Linux
18
- - **Multiple Architectures**: Supports x64 and ARM64 architectures
19
- - **TypeScript Support**: Full TypeScript definitions included
7
+ - **Real-time Block Monitoring**: Listen for new blocks as they're produced on the Chia network
8
+ - **Peer Management**: Connect to multiple Chia full nodes simultaneously
9
+ - **Efficient Parsing**: Fast extraction of coin spends, additions, and removals from blocks
10
+ - **Event-Driven Architecture**: TypeScript-friendly event system with full type safety
11
+ - **Transaction Analysis**: Parse CLVM puzzles and solutions from coin spends
12
+ - **Historical Block Access**: Retrieve blocks by height or ranges
13
+ - **Cross-platform Support**: Works on Windows, macOS, and Linux (x64 and ARM64)
14
+ - **TypeScript Support**: Complete TypeScript definitions with IntelliSense
20
15
 
21
16
  ## Installation
22
17
 
@@ -27,311 +22,348 @@ npm install @dignetwork/chia-block-listener
27
22
  ## Quick Start
28
23
 
29
24
  ```javascript
30
- const { computeProofOfWorkAsync } = require('@dignetwork/chia-block-listener')
31
-
32
- async function mine() {
33
- const entropySeed = Buffer.from('my_plot_entropy_seed', 'utf-8')
34
- const difficulty = 1.0 // Bitcoin difficulty (1.0 = easiest)
35
-
36
- // Start mining (returns immediately with a handle)
37
- const handle = computeProofOfWorkAsync(entropySeed, difficulty)
38
-
39
- // Set up Ctrl+C handling for cancellation
40
- process.on('SIGINT', () => {
41
- console.log('\nCancelling mining...')
42
- handle.cancel()
43
- process.exit(0)
44
- })
45
-
46
- // Wait for completion
47
- while (!handle.isCompleted() && !handle.hasError()) {
48
- console.log(`Mining... attempts: ${handle.getAttempts()}`)
49
- await new Promise(resolve => setTimeout(resolve, 1000))
25
+ const { ChiaBlockListener, initTracing } = require('@dignetwork/chia-block-listener')
26
+
27
+ // Initialize tracing for debugging (optional)
28
+ initTracing()
29
+
30
+ // Create a new listener instance
31
+ const listener = new ChiaBlockListener()
32
+
33
+ // Listen for block events
34
+ listener.on('blockReceived', (block) => {
35
+ console.log(`New block received: ${block.height}`)
36
+ console.log(`Header hash: ${block.header_hash}`)
37
+ console.log(`Timestamp: ${new Date(block.timestamp * 1000)}`)
38
+ console.log(`Coin additions: ${block.coin_additions.length}`)
39
+ console.log(`Coin removals: ${block.coin_removals.length}`)
40
+ console.log(`Coin spends: ${block.coin_spends.length}`)
41
+ })
42
+
43
+ // Listen for peer connection events
44
+ listener.on('peerConnected', (peer) => {
45
+ console.log(`Connected to peer: ${peer.peerId} (${peer.host}:${peer.port})`)
46
+ })
47
+
48
+ listener.on('peerDisconnected', (peer) => {
49
+ console.log(`Disconnected from peer: ${peer.peerId}`)
50
+ if (peer.message) {
51
+ console.log(`Reason: ${peer.message}`)
50
52
  }
51
-
52
- if (handle.hasError()) {
53
- console.log('Mining failed:', handle.getError())
54
- } else {
55
- const result = handle.getResult()
56
- console.log('Solution found!')
57
- console.log('Nonce:', result.nonce)
58
- console.log('Hash:', result.hash)
59
- console.log('Attempts:', result.attempts)
60
- console.log('Time:', result.time_ms, 'ms')
61
- }
62
- }
63
-
64
- mine().catch(console.error)
53
+ })
54
+
55
+ // Connect to a Chia full node
56
+ const peerId = listener.addPeer('localhost', 8444, 'mainnet')
57
+ console.log(`Added peer: ${peerId}`)
58
+
59
+ // Keep the process running
60
+ process.on('SIGINT', () => {
61
+ console.log('Shutting down...')
62
+ listener.disconnectAllPeers()
63
+ process.exit(0)
64
+ })
65
65
  ```
66
66
 
67
67
  ## API Reference
68
68
 
69
- ### Main Functions
69
+ ### ChiaBlockListener Class
70
70
 
71
- #### `computeProofOfWorkAsync(entropySeed, difficulty, maxAttempts?, logAttempts?, doubleSha?): ProofOfWorkHandle`
71
+ #### Constructor
72
72
 
73
- Computes proof of work asynchronously using Bitcoin's target-based difficulty system. Returns immediately with a handle for cancellation and progress tracking.
73
+ ```javascript
74
+ const listener = new ChiaBlockListener()
75
+ ```
74
76
 
75
- **Parameters:**
76
- - `entropySeed` (Buffer): The entropy seed (plotId) to bind the work to
77
- - `difficulty` (number): Bitcoin-style difficulty level (1.0 = easiest, higher = harder)
78
- - `maxAttempts` (number, optional): Maximum attempts before giving up (default: unlimited)
79
- - `logAttempts` (boolean, optional): Whether to log each hash attempt (default: false)
80
- - `doubleSha` (boolean, optional): Whether to use double SHA-256 like Bitcoin (default: true)
77
+ Creates a new Chia block listener instance.
81
78
 
82
- **Returns:** `ProofOfWorkHandle` for cancellation and progress tracking
79
+ #### Methods
83
80
 
84
- #### `verifyProofOfWork(entropySeed, nonce, difficulty, doubleSha?): boolean`
81
+ ##### `addPeer(host, port, networkId): string`
85
82
 
86
- Verifies that a nonce produces a hash that meets the Bitcoin difficulty target.
83
+ Connects to a Chia full node and starts listening for blocks.
87
84
 
88
85
  **Parameters:**
89
- - `entropySeed` (Buffer): The entropy seed that was used
90
- - `nonce` (number): The nonce to verify
91
- - `difficulty` (number): The required difficulty level
92
- - `doubleSha` (boolean, optional): Whether to use double SHA-256 (default: true)
86
+ - `host` (string): The hostname or IP address of the Chia node
87
+ - `port` (number): The port number (typically 8444 for mainnet)
88
+ - `networkId` (string): The network identifier ('mainnet', 'testnet', etc.)
93
89
 
94
- **Returns:** `true` if the nonce is valid for the given difficulty
90
+ **Returns:** A unique peer ID string for this connection
95
91
 
96
- #### `verifyProofOfWorkStandardized(entropySeed, nonce, difficulty, expectedVersion?, doubleSha?): boolean`
92
+ ##### `disconnectPeer(peerId): boolean`
97
93
 
98
- **CONSENSUS CRITICAL:** Standardized verification with algorithm validation. This function verifies both the proof of work AND the algorithm compatibility.
94
+ Disconnects from a specific peer.
99
95
 
100
96
  **Parameters:**
101
- - `entropySeed` (Buffer): The entropy seed that was used
102
- - `nonce` (number): The nonce to verify
103
- - `difficulty` (number): The required difficulty level
104
- - `expectedVersion` (number, optional): Expected algorithm version (default: current)
105
- - `doubleSha` (boolean, optional): Whether to use double SHA-256 (default: true)
97
+ - `peerId` (string): The peer ID returned by `addPeer()`
106
98
 
107
- **Returns:** `true` if the nonce is valid AND algorithm is correct
99
+ **Returns:** `true` if the peer was successfully disconnected, `false` otherwise
108
100
 
109
- **Security Note:** Use this function for network consensus validation. It validates algorithm version compatibility and prevents tampering.
101
+ ##### `disconnectAllPeers(): void`
110
102
 
111
- ### Utility Functions
103
+ Disconnects from all connected peers.
112
104
 
113
- #### `difficultyToTargetHex(difficulty): string`
105
+ ##### `getConnectedPeers(): string[]`
114
106
 
115
- Convert a Bitcoin-style difficulty to the corresponding target value as hex.
107
+ Returns an array of currently connected peer IDs.
116
108
 
117
- **Parameters:**
118
- - `difficulty` (number): The difficulty level
109
+ ##### `getBlockByHeight(peerId, height): BlockReceivedEvent`
119
110
 
120
- **Returns:** The target as a hex string
111
+ Retrieves a specific block by its height from a connected peer.
121
112
 
122
- #### `hashToDifficulty(hash): number`
113
+ **Parameters:**
114
+ - `peerId` (string): The peer ID to query
115
+ - `height` (number): The block height to retrieve
123
116
 
124
- Calculate the difficulty that a given hash would satisfy.
117
+ **Returns:** A `BlockReceivedEvent` object containing the block data
125
118
 
126
- **Parameters:**
127
- - `hash` (Buffer): The hash to analyze (32 bytes)
119
+ ##### `getBlocksRange(peerId, startHeight, endHeight): BlockReceivedEvent[]`
128
120
 
129
- **Returns:** The difficulty level this hash would satisfy
121
+ Retrieves a range of blocks from a connected peer.
130
122
 
131
- ### Consensus & Security Functions
123
+ **Parameters:**
124
+ - `peerId` (string): The peer ID to query
125
+ - `startHeight` (number): The starting block height (inclusive)
126
+ - `endHeight` (number): The ending block height (inclusive)
132
127
 
133
- #### `getAlgorithmVersion(): number`
128
+ **Returns:** An array of `BlockReceivedEvent` objects
134
129
 
135
- Get the current difficulty algorithm version. This version number is part of the network consensus.
130
+ ### Events
136
131
 
137
- **Returns:** The algorithm version number
132
+ The `ChiaBlockListener` emits the following events:
138
133
 
139
- #### `getAlgorithmSpec(): string`
134
+ #### `blockReceived`
140
135
 
141
- Get the algorithm specification hash. This hash identifies the exact algorithm implementation.
136
+ Fired when a new block is received from any connected peer.
142
137
 
143
- **Returns:** The algorithm specification identifier
138
+ **Callback:** `(event: BlockReceivedEvent) => void`
144
139
 
145
- #### `getAlgorithmParameters(): AlgorithmParameters`
140
+ #### `peerConnected`
146
141
 
147
- Get the standardized difficulty algorithm parameters. These parameters are part of the network consensus.
142
+ Fired when a connection to a peer is established.
148
143
 
149
- **Returns:** Algorithm parameters object containing:
150
- - `version` (number): Algorithm version number
151
- - `specHash` (string): Algorithm specification hash
152
- - `baseZeroBits` (number): Base number of zero bits for difficulty 1.0
153
- - `logMultiplier` (number): Logarithmic multiplier for difficulty scaling
154
- - `maxZeroBits` (number): Maximum allowed zero bits
144
+ **Callback:** `(event: PeerConnectedEvent) => void`
155
145
 
156
- ### ProofOfWorkHandle Methods
146
+ #### `peerDisconnected`
157
147
 
158
- The handle returned by `computeProofOfWorkAsync` provides these methods:
148
+ Fired when a peer connection is lost.
159
149
 
160
- #### `cancel(): void`
161
- Cancels the running proof of work computation.
150
+ **Callback:** `(event: PeerDisconnectedEvent) => void`
162
151
 
163
- #### `isCancelled(): boolean`
164
- Returns `true` if the computation has been cancelled.
152
+ ### Event Data Types
165
153
 
166
- #### `isCompleted(): boolean`
167
- Returns `true` if the computation has found a valid solution.
154
+ #### `BlockReceivedEvent`
168
155
 
169
- #### `hasError(): boolean`
170
- Returns `true` if there was an error (cancelled or max attempts reached).
156
+ ```typescript
157
+ interface BlockReceivedEvent {
158
+ peerId: string // IP address of the peer that sent this block
159
+ height: number // Block height
160
+ weight: string // Block weight as string
161
+ headerHash: string // Block header hash (hex)
162
+ timestamp: number // Block timestamp (Unix time)
163
+ coinAdditions: CoinRecord[] // New coins created in this block
164
+ coinRemovals: CoinRecord[] // Coins spent in this block
165
+ coinSpends: CoinSpend[] // Detailed spend information
166
+ coinCreations: CoinRecord[] // Coins created by puzzles
167
+ hasTransactionsGenerator: boolean // Whether block has a generator
168
+ generatorSize: number // Size of the generator bytecode
169
+ }
170
+ ```
171
171
 
172
- #### `getError(): string | null`
173
- Returns the error message if there was an error, or `null` if no error.
172
+ #### `PeerConnectedEvent`
174
173
 
175
- #### `getResult(): ProofOfWorkResult | null`
176
- Returns the result if computation completed successfully, or `null` if not completed.
174
+ ```typescript
175
+ interface PeerConnectedEvent {
176
+ peerId: string // Peer IP address
177
+ host: string // Peer hostname/IP
178
+ port: number // Peer port number
179
+ }
180
+ ```
177
181
 
178
- #### `getAttempts(): bigint`
179
- Returns the current number of attempts made (approximate).
182
+ #### `PeerDisconnectedEvent`
180
183
 
181
- #### `getProgress(): ProofOfWorkProgress`
182
- Returns detailed progress information (attempts, elapsed time, etc.).
184
+ ```typescript
185
+ interface PeerDisconnectedEvent {
186
+ peerId: string // Peer IP address
187
+ host: string // Peer hostname/IP
188
+ port: number // Peer port number
189
+ message?: string // Optional disconnection reason
190
+ }
191
+ ```
183
192
 
184
- #### `getDifficulty(): number`
185
- Returns the difficulty level for this computation.
193
+ #### `CoinRecord`
186
194
 
187
- ### Result Types
195
+ ```typescript
196
+ interface CoinRecord {
197
+ parentCoinInfo: string // Parent coin ID (hex)
198
+ puzzleHash: string // Puzzle hash (hex)
199
+ amount: string // Coin amount as string
200
+ }
201
+ ```
188
202
 
189
- #### `ProofOfWorkResult`
190
- - `nonce` (bigint): The nonce that was found
191
- - `hash` (string): The resulting hash as hex string
192
- - `attempts` (bigint): Number of attempts made
193
- - `time_ms` (number): Time taken in milliseconds
194
- - `difficulty` (number): The difficulty that was satisfied
195
- - `target` (string): The target that was used (as hex string)
203
+ #### `CoinSpend`
196
204
 
197
- #### `ProofOfWorkProgress`
198
- - `attempts` (bigint): Current number of attempts
199
- - `nonce` (bigint): Current nonce being tested
200
- - `elapsed_ms` (number): Time elapsed in milliseconds
201
- - `attempts_per_second` (number): Estimated attempts per second
205
+ ```typescript
206
+ interface CoinSpend {
207
+ coin: CoinRecord // The coin being spent
208
+ puzzleReveal: string // CLVM puzzle bytecode (hex)
209
+ solution: string // CLVM solution bytecode (hex)
210
+ offset: number // Offset in the generator bytecode
211
+ }
212
+ ```
202
213
 
203
214
  ## TypeScript Usage
204
215
 
205
216
  ```typescript
206
217
  import {
207
- computeProofOfWorkAsync,
208
- verifyProofOfWork,
209
- verifyProofOfWorkStandardized,
210
- getAlgorithmVersion,
211
- getAlgorithmParameters,
212
- hashToDifficulty,
213
- ProofOfWorkResult,
214
- ProofOfWorkHandle,
215
- AlgorithmParameters
218
+ ChiaBlockListener,
219
+ BlockReceivedEvent,
220
+ PeerConnectedEvent,
221
+ PeerDisconnectedEvent,
222
+ CoinRecord,
223
+ CoinSpend,
224
+ initTracing,
225
+ getEventTypes
216
226
  } from '@dignetwork/chia-block-listener'
217
227
 
218
- async function mineWithTypes(): Promise<void> {
219
- const entropySeed = Buffer.from('my_plot_entropy_seed', 'utf-8')
220
- const difficulty = 2.0
228
+ // Initialize tracing for debugging
229
+ initTracing()
230
+
231
+ // Create listener with proper typing
232
+ const listener = new ChiaBlockListener()
233
+
234
+ // Type-safe event handlers
235
+ listener.on('blockReceived', (block: BlockReceivedEvent) => {
236
+ console.log(`Block ${block.height} from peer ${block.peerId}`)
221
237
 
222
- const handle: ProofOfWorkHandle = computeProofOfWorkAsync(entropySeed, difficulty)
238
+ // Process coin additions
239
+ block.coin_additions.forEach((coin: CoinRecord) => {
240
+ console.log(`New coin: ${coin.amount} mojos`)
241
+ })
223
242
 
224
- // Wait for completion with proper typing
225
- const waitForCompletion = async (handle: ProofOfWorkHandle): Promise<ProofOfWorkResult> => {
226
- while (!handle.isCompleted() && !handle.hasError()) {
227
- await new Promise(resolve => setTimeout(resolve, 100))
228
- }
229
-
230
- if (handle.hasError()) {
231
- throw new Error(handle.getError() || 'Unknown error')
232
- }
233
-
234
- const result = handle.getResult()
235
- if (!result) {
236
- throw new Error('No result available')
237
- }
243
+ // Process coin spends
244
+ block.coin_spends.forEach((spend: CoinSpend) => {
245
+ console.log(`Spend: ${spend.coin.amount} mojos`)
246
+ console.log(`Puzzle: ${spend.puzzle_reveal}`)
247
+ console.log(`Solution: ${spend.solution}`)
248
+ })
249
+ })
250
+
251
+ listener.on('peerConnected', (peer: PeerConnectedEvent) => {
252
+ console.log(`Connected: ${peer.peerId} at ${peer.host}:${peer.port}`)
253
+ })
254
+
255
+ listener.on('peerDisconnected', (peer: PeerDisconnectedEvent) => {
256
+ console.log(`Disconnected: ${peer.peerId}`)
257
+ if (peer.message) {
258
+ console.log(`Reason: ${peer.message}`)
259
+ }
260
+ })
261
+
262
+ // Connect to peers
263
+ const mainnetPeer = listener.addPeer('localhost', 8444, 'mainnet')
264
+ const testnetPeer = listener.addPeer('testnet-node.chia.net', 58444, 'testnet')
265
+
266
+ // Get historical blocks
267
+ async function getHistoricalBlocks() {
268
+ try {
269
+ const block = listener.getBlockByHeight(mainnetPeer, 1000000)
270
+ console.log(`Block 1000000 hash: ${block.header_hash}`)
238
271
 
239
- return result
272
+ const blocks = listener.getBlocksRange(mainnetPeer, 1000000, 1000010)
273
+ console.log(`Retrieved ${blocks.length} blocks`)
274
+ } catch (error) {
275
+ console.error('Error getting blocks:', error)
240
276
  }
241
-
242
- const result: ProofOfWorkResult = await waitForCompletion(handle)
243
-
244
- // Standard verification
245
- const isValid: boolean = verifyProofOfWork(
246
- entropySeed,
247
- Number(result.nonce),
248
- difficulty
249
- )
250
-
251
- // Standardized verification (recommended for networks)
252
- const isStandardValid: boolean = verifyProofOfWorkStandardized(
253
- entropySeed,
254
- Number(result.nonce),
255
- difficulty
256
- )
257
-
258
- // Check algorithm parameters
259
- const params: AlgorithmParameters = getAlgorithmParameters()
260
- console.log(`Algorithm version: ${params.version}`)
261
- console.log(`Algorithm spec: ${params.specHash}`)
262
-
263
- console.log('Mining completed, valid:', isValid)
264
- console.log('Consensus valid:', isStandardValid)
265
277
  }
266
- ```
267
278
 
268
- ## Difficulty System
279
+ // Get event type constants
280
+ const eventTypes = getEventTypes()
281
+ console.log('Available events:', eventTypes)
282
+ ```
269
283
 
270
- This library uses Bitcoin's target-based difficulty system:
284
+ ## Advanced Usage
271
285
 
272
- - **Difficulty 1.0**: Easiest level, requires 8 leading zero bits in hash
273
- - **Difficulty 2.0**: Requires 12 leading zero bits
274
- - **Difficulty 4.0**: Requires 16 leading zero bits (2 zero bytes)
275
- - **Higher difficulties**: Exponentially more difficult
286
+ ### Monitoring Specific Transactions
276
287
 
277
- The difficulty directly corresponds to how computationally expensive it is to find a valid nonce.
288
+ ```javascript
289
+ // Monitor all coin spends for a specific puzzle hash
290
+ listener.on('blockReceived', (block) => {
291
+ const targetPuzzleHash = '0x1234...' // Your puzzle hash
292
+
293
+ block.coin_spends.forEach((spend) => {
294
+ if (spend.coin.puzzle_hash === targetPuzzleHash) {
295
+ console.log('Found spend for our puzzle!')
296
+ console.log('Amount:', spend.coin.amount)
297
+ console.log('Solution:', spend.solution)
298
+ }
299
+ })
300
+ })
301
+ ```
278
302
 
279
- ## Security & Consensus
303
+ ### Multiple Network Monitoring
280
304
 
281
- This library implements a **consensus-critical verification system** to prevent tampering and ensure network compatibility.
305
+ ```javascript
306
+ // Monitor both mainnet and testnet
307
+ const mainnetPeer = listener.addPeer('localhost', 8444, 'mainnet')
308
+ const testnetPeer = listener.addPeer('localhost', 58444, 'testnet')
309
+
310
+ listener.on('blockReceived', (block) => {
311
+ if (block.peerId === mainnetPeer) {
312
+ console.log(`Mainnet block ${block.height}`)
313
+ } else if (block.peerId === testnetPeer) {
314
+ console.log(`Testnet block ${block.height}`)
315
+ }
316
+ })
317
+ ```
282
318
 
283
- ### Algorithm Standardization
319
+ ### Connection Management
284
320
 
285
- - **Version 1 Specification**: `DIG_POW_V1_SMOOTH_LOG_DIFFICULTY_2024`
286
- - **Formula**: `zero_bits = 8 + log2(difficulty) * 2`
287
- - **Immutable Parameters**: All difficulty calculation parameters are locked constants
288
- - **Version Validation**: Algorithm version must match across all network participants
321
+ ```javascript
322
+ // Automatic reconnection
323
+ listener.on('peerDisconnected', (peer) => {
324
+ console.log(`Lost connection to ${peer.peerId}, reconnecting...`)
325
+
326
+ // Reconnect after 5 seconds
327
+ setTimeout(() => {
328
+ try {
329
+ listener.addPeer(peer.host, peer.port, 'mainnet')
330
+ console.log('Reconnected successfully')
331
+ } catch (error) {
332
+ console.error('Reconnection failed:', error)
333
+ }
334
+ }, 5000)
335
+ })
336
+ ```
289
337
 
290
- ### Security Guarantees
338
+ ## Utility Functions
291
339
 
292
- 1. **Tamper Detection**: Algorithm spec hash prevents silent modifications
293
- 2. **Version Enforcement**: Mismatched versions are rejected automatically
294
- 3. **Consensus Compliance**: All parameters are immutable constants
295
- 4. **Network Compatibility**: Ensures identical verification across nodes
296
- 5. **Upgrade Safety**: Algorithm changes require coordinated hard forks
340
+ ### `initTracing(): void`
297
341
 
298
- ### Usage for Network Consensus
342
+ Initializes the Rust tracing system for debugging purposes. Call this before creating any `ChiaBlockListener` instances if you want to see debug output.
299
343
 
300
- ```javascript
301
- // For production networks: Always use standardized verification
302
- const isValid = verifyProofOfWorkStandardized(entropySeed, nonce, difficulty)
344
+ ### `getEventTypes(): EventTypes`
303
345
 
304
- // Check algorithm compatibility
305
- const version = getAlgorithmVersion() // Returns: 1
306
- const spec = getAlgorithmSpec() // Returns: "DIG_POW_V1_SMOOTH_LOG_DIFFICULTY_2024"
346
+ Returns an object containing the event type constants:
307
347
 
308
- // Validate all proofs with version checking
309
- function validateNetworkProof(entropySeed, nonce, difficulty) {
310
- return verifyProofOfWorkStandardized(entropySeed, nonce, difficulty, 1)
311
- }
348
+ ```javascript
349
+ const eventTypes = getEventTypes()
350
+ console.log(eventTypes)
351
+ // Output: { blockReceived: "blockReceived", peerConnected: "peerConnected", peerDisconnected: "peerDisconnected" }
312
352
  ```
313
353
 
314
- ### Network Upgrade Process
315
-
316
- To change the difficulty algorithm:
317
- 1. Define new algorithm version (e.g., version 2)
318
- 2. Update consensus parameters and spec hash
319
- 3. Coordinate hard fork across all network participants
320
- 4. Validate version compatibility on peer connections
321
-
322
354
  ## Performance Tips
323
355
 
324
- 1. **Use appropriate difficulty levels**: Start with 1.0-4.0 for testing
325
- 2. **Monitor progress**: Use the handle to track mining progress
326
- 3. **Set reasonable limits**: Use `maxAttempts` for time-critical applications
327
- 4. **Handle cancellation**: Always provide a way to cancel long-running operations
356
+ 1. **Use specific event handlers**: Only listen for the events you need
357
+ 2. **Process blocks efficiently**: Avoid heavy computation in event handlers
358
+ 3. **Manage connections**: Don't create too many peer connections simultaneously
359
+ 4. **Handle errors gracefully**: Always wrap peer operations in try-catch blocks
328
360
 
329
361
  ## Development
330
362
 
331
363
  ### Prerequisites
332
364
 
333
365
  - [Rust](https://rustup.rs/) (latest stable)
334
- - [Node.js](https://nodejs.org/) (16 or later)
366
+ - [Node.js](https://nodejs.org/) (20 or later)
335
367
  - [npm](https://www.npmjs.com/)
336
368
 
337
369
  ### Setup
@@ -353,15 +385,20 @@ npm test
353
385
 
354
386
  ```
355
387
  chia-block-listener/
356
- ├── src/
357
- └── lib.rs # Rust implementation with NAPI bindings
358
- ├── __test__/
359
- └── index.spec.mjs # Test suite
360
- ├── npm/ # Platform-specific native binaries
361
- ├── .github/workflows/ # CI/CD pipeline
362
- ├── Cargo.toml # Rust configuration
363
- ├── package.json # Node.js configuration
364
- └── index.d.ts # TypeScript definitions
388
+ ├── src/ # Rust source code
389
+ ├── lib.rs # Main NAPI bindings
390
+ ├── peer.rs # Peer connection management
391
+ ├── protocol.rs # Chia protocol implementation
392
+ ├── event_emitter.rs # Event system
393
+ │ └── tls.rs # TLS connection handling
394
+ ├── crate/ # Additional Rust crates
395
+ │ └── chia-generator-parser/ # CLVM parser
396
+ ├── __test__/ # Test suite
397
+ ├── npm/ # Platform-specific binaries
398
+ ├── .github/workflows/ # CI/CD pipeline
399
+ ├── Cargo.toml # Rust configuration
400
+ ├── package.json # Node.js configuration
401
+ └── index.d.ts # TypeScript definitions
365
402
  ```
366
403
 
367
404
  ## CI/CD & Publishing
@@ -369,8 +406,8 @@ chia-block-listener/
369
406
  This project uses GitHub Actions for:
370
407
  - Cross-platform builds (Windows, macOS, Linux)
371
408
  - Multiple architectures (x64, ARM64)
372
- - Automated testing
373
- - npm publishing based on commit messages
409
+ - Automated testing on all platforms
410
+ - npm publishing based on git tags
374
411
 
375
412
  ## License
376
413
 
@@ -385,3 +422,10 @@ MIT
385
422
  5. Commit your changes (`git commit -m 'Add some amazing feature'`)
386
423
  6. Push to the branch (`git push origin feature/amazing-feature`)
387
424
  7. Open a Pull Request
425
+
426
+ ## Support
427
+
428
+ For issues and questions:
429
+ - GitHub Issues: [Report bugs or request features](https://github.com/DIG-Network/chia-block-listener/issues)
430
+ - Documentation: Check the TypeScript definitions in `index.d.ts`
431
+ - Examples: See the `examples/` directory for more usage examples
package/index.d.ts CHANGED
@@ -42,8 +42,6 @@ export interface CoinSpend {
42
42
  coin: CoinRecord
43
43
  puzzleReveal: string
44
44
  solution: string
45
- realData: boolean
46
- parsingMethod: string
47
45
  offset: number
48
46
  }
49
47
  export declare function initTracing(): void
@@ -53,21 +51,7 @@ export declare class ChiaBlockListener {
53
51
  disconnectPeer(peerId: string): boolean
54
52
  disconnectAllPeers(): void
55
53
  getConnectedPeers(): Array<string>
56
- // Typed event method overloads
57
-
58
- on(event: 'blockReceived', callback: (event: BlockReceivedEvent) => void): void
59
-
60
- on(event: 'peerConnected', callback: (event: PeerConnectedEvent) => void): void
61
-
62
- on(event: 'peerDisconnected', callback: (event: PeerDisconnectedEvent) => void): void
63
-
64
54
  on(event: string, callback: (...args: any[]) => any): void
65
- off(event: 'blockReceived', callback: (event: BlockReceivedEvent) => void): void
66
-
67
- off(event: 'peerConnected', callback: (event: PeerConnectedEvent) => void): void
68
-
69
- off(event: 'peerDisconnected', callback: (event: PeerDisconnectedEvent) => void): void
70
-
71
55
  off(event: string, callback: (...args: any[]) => any): void
72
56
  getBlockByHeight(peerId: string, height: number): BlockReceivedEvent
73
57
  getBlocksRange(peerId: string, startHeight: number, endHeight: number): Array<BlockReceivedEvent>
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener-darwin-arm64",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/DIG-Network/chia-block-listener"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener-darwin-x64",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/DIG-Network/chia-block-listener"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener-linux-arm64-gnu",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/DIG-Network/chia-block-listener"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener-linux-x64-gnu",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/DIG-Network/chia-block-listener"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener-win32-x64-msvc",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/DIG-Network/chia-block-listener"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dignetwork/chia-block-listener",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "repository": {
@@ -58,10 +58,10 @@
58
58
  },
59
59
  "packageManager": "yarn@1.22.22",
60
60
  "optionalDependencies": {
61
- "@dignetwork/chia-block-listener-win32-x64-msvc": "0.1.6",
62
- "@dignetwork/chia-block-listener-darwin-x64": "0.1.6",
63
- "@dignetwork/chia-block-listener-linux-x64-gnu": "0.1.6",
64
- "@dignetwork/chia-block-listener-darwin-arm64": "0.1.6",
65
- "@dignetwork/chia-block-listener-linux-arm64-gnu": "0.1.6"
61
+ "@dignetwork/chia-block-listener-win32-x64-msvc": "0.1.8",
62
+ "@dignetwork/chia-block-listener-darwin-x64": "0.1.8",
63
+ "@dignetwork/chia-block-listener-linux-x64-gnu": "0.1.8",
64
+ "@dignetwork/chia-block-listener-darwin-arm64": "0.1.8",
65
+ "@dignetwork/chia-block-listener-linux-arm64-gnu": "0.1.8"
66
66
  }
67
67
  }
@@ -3,11 +3,25 @@ const path = require('path');
3
3
 
4
4
  const indexDtsPath = path.join(__dirname, '..', 'index.d.ts');
5
5
 
6
- function addTypedOverloads() {
6
+ function fixFieldNames() {
7
7
  try {
8
8
  // Read the auto-generated index.d.ts file
9
9
  let content = fs.readFileSync(indexDtsPath, 'utf8');
10
10
 
11
+ console.log('✅ Field names should now be camelCase from NAPI js_name attributes');
12
+ return content;
13
+
14
+ } catch (error) {
15
+ console.error('❌ Error fixing field names:', error.message);
16
+ process.exit(1);
17
+ }
18
+ }
19
+
20
+ function addTypedOverloads() {
21
+ try {
22
+ // Read the auto-generated index.d.ts file (or use fixed content from field name correction)
23
+ let content = fixFieldNames();
24
+
11
25
  // Check if typed overloads are already present (avoid duplicates)
12
26
  if (content.includes('Typed event method overloads')) {
13
27
  console.log('✅ Typed event method overloads already present in index.d.ts');
@@ -83,6 +83,7 @@ enum PeerEventType {
83
83
  #[napi(object)]
84
84
  #[derive(Clone)]
85
85
  pub struct PeerConnectedEvent {
86
+ #[napi(js_name = "peerId")]
86
87
  pub peer_id: String,
87
88
  pub host: String,
88
89
  pub port: u32,
@@ -92,6 +93,7 @@ pub struct PeerConnectedEvent {
92
93
  #[napi(object)]
93
94
  #[derive(Clone)]
94
95
  pub struct PeerDisconnectedEvent {
96
+ #[napi(js_name = "peerId")]
95
97
  pub peer_id: String,
96
98
  pub host: String,
97
99
  pub port: u32,
@@ -102,23 +104,33 @@ pub struct PeerDisconnectedEvent {
102
104
  #[napi(object)]
103
105
  #[derive(Clone)]
104
106
  pub struct BlockReceivedEvent {
107
+ #[napi(js_name = "peerId")]
105
108
  pub peer_id: String,
106
109
  pub height: u32,
107
110
  pub weight: String,
111
+ #[napi(js_name = "headerHash")]
108
112
  pub header_hash: String,
109
113
  pub timestamp: u32,
114
+ #[napi(js_name = "coinAdditions")]
110
115
  pub coin_additions: Vec<CoinRecord>,
116
+ #[napi(js_name = "coinRemovals")]
111
117
  pub coin_removals: Vec<CoinRecord>,
118
+ #[napi(js_name = "coinSpends")]
112
119
  pub coin_spends: Vec<CoinSpend>,
120
+ #[napi(js_name = "coinCreations")]
113
121
  pub coin_creations: Vec<CoinRecord>,
122
+ #[napi(js_name = "hasTransactionsGenerator")]
114
123
  pub has_transactions_generator: bool,
124
+ #[napi(js_name = "generatorSize")]
115
125
  pub generator_size: u32,
116
126
  }
117
127
 
118
128
  #[napi(object)]
119
129
  #[derive(Clone)]
120
130
  pub struct CoinRecord {
131
+ #[napi(js_name = "parentCoinInfo")]
121
132
  pub parent_coin_info: String,
133
+ #[napi(js_name = "puzzleHash")]
122
134
  pub puzzle_hash: String,
123
135
  pub amount: String,
124
136
  }
@@ -127,10 +139,9 @@ pub struct CoinRecord {
127
139
  #[derive(Clone)]
128
140
  pub struct CoinSpend {
129
141
  pub coin: CoinRecord,
142
+ #[napi(js_name = "puzzleReveal")]
130
143
  pub puzzle_reveal: String,
131
144
  pub solution: String,
132
- pub real_data: bool,
133
- pub parsing_method: String,
134
145
  pub offset: u32,
135
146
  }
136
147
 
@@ -241,7 +252,7 @@ impl ChiaBlockListener {
241
252
 
242
253
  let peer_id = rt.block_on(async {
243
254
  let mut guard = inner.write().await;
244
- let peer_id = format!("{}:{}", host, port);
255
+ let peer_id = host.clone();
245
256
 
246
257
  guard.peers.insert(
247
258
  peer_id.clone(),
@@ -331,7 +342,7 @@ impl ChiaBlockListener {
331
342
  obj.set_named_property("height", ctx.env.create_uint32(event.height)?)?;
332
343
  obj.set_named_property("weight", ctx.env.create_string(&event.weight)?)?;
333
344
  obj.set_named_property(
334
- "header_hash",
345
+ "headerHash",
335
346
  ctx.env.create_string(&event.header_hash)?,
336
347
  )?;
337
348
  obj.set_named_property("timestamp", ctx.env.create_uint32(event.timestamp)?)?;
@@ -343,11 +354,11 @@ impl ChiaBlockListener {
343
354
  for (i, coin) in event.coin_additions.iter().enumerate() {
344
355
  let mut coin_obj = ctx.env.create_object()?;
345
356
  coin_obj.set_named_property(
346
- "parent_coin_info",
357
+ "parentCoinInfo",
347
358
  ctx.env.create_string(&coin.parent_coin_info)?,
348
359
  )?;
349
360
  coin_obj.set_named_property(
350
- "puzzle_hash",
361
+ "puzzleHash",
351
362
  ctx.env.create_string(&coin.puzzle_hash)?,
352
363
  )?;
353
364
  coin_obj.set_named_property(
@@ -356,7 +367,7 @@ impl ChiaBlockListener {
356
367
  )?;
357
368
  additions_array.set_element(i as u32, coin_obj)?;
358
369
  }
359
- obj.set_named_property("coin_additions", additions_array)?;
370
+ obj.set_named_property("coinAdditions", additions_array)?;
360
371
 
361
372
  // Coin removals array
362
373
  let mut removals_array = ctx
@@ -365,11 +376,11 @@ impl ChiaBlockListener {
365
376
  for (i, coin) in event.coin_removals.iter().enumerate() {
366
377
  let mut coin_obj = ctx.env.create_object()?;
367
378
  coin_obj.set_named_property(
368
- "parent_coin_info",
379
+ "parentCoinInfo",
369
380
  ctx.env.create_string(&coin.parent_coin_info)?,
370
381
  )?;
371
382
  coin_obj.set_named_property(
372
- "puzzle_hash",
383
+ "puzzleHash",
373
384
  ctx.env.create_string(&coin.puzzle_hash)?,
374
385
  )?;
375
386
  coin_obj.set_named_property(
@@ -378,7 +389,7 @@ impl ChiaBlockListener {
378
389
  )?;
379
390
  removals_array.set_element(i as u32, coin_obj)?;
380
391
  }
381
- obj.set_named_property("coin_removals", removals_array)?;
392
+ obj.set_named_property("coinRemovals", removals_array)?;
382
393
 
383
394
  // Coin spends array
384
395
  let mut spends_array =
@@ -389,11 +400,11 @@ impl ChiaBlockListener {
389
400
  // Create coin object
390
401
  let mut coin_obj = ctx.env.create_object()?;
391
402
  coin_obj.set_named_property(
392
- "parent_coin_info",
403
+ "parentCoinInfo",
393
404
  ctx.env.create_string(&spend.coin.parent_coin_info)?,
394
405
  )?;
395
406
  coin_obj.set_named_property(
396
- "puzzle_hash",
407
+ "puzzleHash",
397
408
  ctx.env.create_string(&spend.coin.puzzle_hash)?,
398
409
  )?;
399
410
  coin_obj.set_named_property(
@@ -403,27 +414,20 @@ impl ChiaBlockListener {
403
414
  spend_obj.set_named_property("coin", coin_obj)?;
404
415
 
405
416
  spend_obj.set_named_property(
406
- "puzzle_reveal",
417
+ "puzzleReveal",
407
418
  ctx.env.create_string(&spend.puzzle_reveal)?,
408
419
  )?;
409
420
  spend_obj.set_named_property(
410
421
  "solution",
411
422
  ctx.env.create_string(&spend.solution)?,
412
423
  )?;
413
- spend_obj.set_named_property(
414
- "real_data",
415
- ctx.env.get_boolean(spend.real_data)?,
416
- )?;
417
- spend_obj.set_named_property(
418
- "parsing_method",
419
- ctx.env.create_string(&spend.parsing_method)?,
420
- )?;
424
+
421
425
  spend_obj
422
426
  .set_named_property("offset", ctx.env.create_uint32(spend.offset)?)?;
423
427
 
424
428
  spends_array.set_element(i as u32, spend_obj)?;
425
429
  }
426
- obj.set_named_property("coin_spends", spends_array)?;
430
+ obj.set_named_property("coinSpends", spends_array)?;
427
431
 
428
432
  // Coin creations array
429
433
  let mut creations_array = ctx
@@ -432,25 +436,25 @@ impl ChiaBlockListener {
432
436
  for (i, coin) in event.coin_creations.iter().enumerate() {
433
437
  let mut coin_obj = ctx.env.create_object()?;
434
438
  coin_obj.set_named_property(
435
- "parent_coin_info",
439
+ "parentCoinInfo",
436
440
  ctx.env.create_string(&coin.parent_coin_info)?,
437
441
  )?;
438
442
  coin_obj.set_named_property(
439
- "puzzle_hash",
443
+ "puzzleHash",
440
444
  ctx.env.create_string(&coin.puzzle_hash)?,
441
445
  )?;
442
446
  coin_obj
443
447
  .set_named_property("amount", ctx.env.create_string(&coin.amount)?)?;
444
448
  creations_array.set_element(i as u32, coin_obj)?;
445
449
  }
446
- obj.set_named_property("coin_creations", creations_array)?;
450
+ obj.set_named_property("coinCreations", creations_array)?;
447
451
 
448
452
  obj.set_named_property(
449
- "has_transactions_generator",
453
+ "hasTransactionsGenerator",
450
454
  ctx.env.get_boolean(event.has_transactions_generator)?,
451
455
  )?;
452
456
  obj.set_named_property(
453
- "generator_size",
457
+ "generatorSize",
454
458
  ctx.env.create_uint32(event.generator_size)?,
455
459
  )?;
456
460
 
@@ -734,8 +738,6 @@ impl ChiaBlockListener {
734
738
  },
735
739
  puzzle_reveal: hex::encode(&spend.puzzle_reveal),
736
740
  solution: hex::encode(&spend.solution),
737
- real_data: spend.real_data,
738
- parsing_method: spend.parsing_method.clone(),
739
741
  offset: spend.offset,
740
742
  })
741
743
  .collect(),