smartledger-bsv 3.0.0 → 3.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smartledger-bsv",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "Security-hardened Bitcoin SV library - Complete drop-in replacement for bsv@1.5.6 with zero vulnerabilities",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
@@ -11,15 +11,38 @@
11
11
  "scripts": {
12
12
  "lint": "standard",
13
13
  "test": "standard && mocha",
14
+ "test:signatures": "node validation_test.js",
14
15
  "coverage": "nyc --reporter=text npm run test",
15
16
  "build-bsv": "webpack index.js --config webpack.config.js",
16
17
  "build-ecies": "webpack ecies/index.js --config webpack.subproject.config.js --output-library bsvEcies -o bsv-ecies.min.js",
17
18
  "build-message": "webpack message/index.js --config webpack.subproject.config.js --output-library bsvMessage -o bsv-message.min.js",
18
19
  "build-mnemonic": "webpack mnemonic/index.js --config webpack.subproject.config.js --output-library bsvMnemonic -o bsv-mnemonic.min.js",
20
+ "build-bundle": "webpack bundle-entry.js --config webpack.bundle.config.js",
19
21
  "build": "npm run build-bsv && npm run build-ecies && npm run build-message && npm run build-mnemonic",
22
+ "build-all": "npm run build && npm run build-bundle",
20
23
  "prepublishOnly": "NODE_OPTIONS=\"--openssl-legacy-provider\" npm run build"
21
24
  },
22
25
  "unpkg": "bsv.min.js",
26
+ "jsdelivr": "bsv.min.js",
27
+ "cdn": "bsv.min.js",
28
+ "files": [
29
+ "index.js",
30
+ "lib/",
31
+ "utilities/",
32
+ "ecies/",
33
+ "message/",
34
+ "mnemonic/",
35
+ "bsv.min.js",
36
+ "bsv-ecies.min.js",
37
+ "bsv-message.min.js",
38
+ "bsv-mnemonic.min.js",
39
+ "bsv.d.ts",
40
+ "validation_test.js",
41
+ "LICENSE",
42
+ "README.md",
43
+ "SECURITY.md",
44
+ "CHANGELOG.md"
45
+ ],
23
46
  "keywords": [
24
47
  "bitcoin",
25
48
  "bitcoin-sv",
@@ -32,6 +55,11 @@
32
55
  "hardened",
33
56
  "vulnerability-free",
34
57
  "drop-in-replacement",
58
+ "utxo-management",
59
+ "blockchain-simulator",
60
+ "miner-simulator",
61
+ "testing-tools",
62
+ "development-framework",
35
63
  "ecies",
36
64
  "p2p",
37
65
  "payment",
@@ -0,0 +1,132 @@
1
+ # BSV Development Utilities
2
+
3
+ This folder contains utilities for BSV blockchain development and testing, including a complete blockchain miner simulation system for validating transactions and managing UTXO sets.
4
+
5
+ ## Files Overview
6
+
7
+ ### Core Utilities
8
+
9
+ - **`mock-utxo-generator.js`** - Generates mock UTXOs for testing and development
10
+ - Creates realistic mock transaction IDs
11
+ - Builds P2PKH script hex for addresses
12
+ - Generates properly formatted UTXO objects
13
+
14
+ - **`wallet-setup.js`** - Sets up consistent test wallet environments
15
+ - Creates deterministic test wallets with private keys and addresses
16
+ - Generates initial mock UTXOs
17
+ - Saves configuration to `wallet.json`
18
+
19
+ - **`utxo-manager.js`** - Manages UTXO state and transaction tracking
20
+ - Tracks spent and available UTXOs
21
+ - Updates wallet state after transactions
22
+ - Calculates available balance
23
+ - Maintains transaction history
24
+
25
+ ### Blockchain Simulation
26
+
27
+ - **`blockchain-state.js`** - Global blockchain state manager
28
+ - Manages multiple wallet UTXO sets
29
+ - Tracks spent and available UTXOs globally
30
+ - Maintains blockchain metadata (block height, total value)
31
+ - Supports wallet registration and UTXO validation
32
+
33
+ - **`miner-simulator.js`** - Complete miner simulation system
34
+ - Accepts broadcast transactions
35
+ - Validates inputs against global UTXO set
36
+ - Verifies transaction signatures
37
+ - Checks transaction balance (inputs ≥ outputs + fees)
38
+ - Processes valid transactions and rejects invalid ones
39
+ - Updates blockchain state after successful transactions
40
+
41
+ - **`transaction-examples.js`** - Complete transaction flow demonstrations
42
+ - Simple P2PKH payments
43
+ - Transaction chaining
44
+ - Multi-output transactions
45
+ - Full broadcast → validate → process workflow
46
+
47
+ ### Configuration
48
+
49
+ - **`wallet.json`** - Persistent wallet state and UTXO tracking
50
+ - Wallet credentials (private key, address)
51
+ - Current UTXO set
52
+ - Spent UTXO history
53
+ - Transaction metadata
54
+
55
+ - **`blockchain-state.json`** - Global blockchain database
56
+ - All wallet addresses and UTXO sets
57
+ - Global UTXO set (keyed by "txid:vout")
58
+ - Spent UTXO history
59
+ - Transaction processing history
60
+ - Blockchain metadata (block height, etc.)
61
+
62
+ ## Usage
63
+
64
+ ### Quick Start
65
+
66
+ 1. **Initialize a test wallet:**
67
+ ```bash
68
+ node wallet-setup.js
69
+ ```
70
+
71
+ 2. **Import wallet into blockchain state:**
72
+ ```bash
73
+ node blockchain-state.js import
74
+ ```
75
+
76
+ 3. **Run transaction examples:**
77
+ ```bash
78
+ node transaction-examples.js # Run all examples
79
+ node transaction-examples.js 1 # Run single payment example
80
+ ```
81
+
82
+ 4. **Check blockchain state:**
83
+ ```bash
84
+ node blockchain-state.js # Show blockchain stats
85
+ node miner-simulator.js # Show miner/mempool status
86
+ node utxo-manager.js # Show wallet UTXOs
87
+ ```
88
+
89
+ ### Transaction Flow
90
+
91
+ The complete transaction flow demonstrates real blockchain behavior:
92
+
93
+ ```javascript
94
+ // 1. Create transaction
95
+ const tx = new bsv.Transaction()
96
+ .from(utxo)
97
+ .to(recipientAddress, amount)
98
+ .change(senderAddress)
99
+ .fee(1000)
100
+ .sign(privateKey);
101
+
102
+ // 2. Broadcast to miner
103
+ const result = acceptTransaction(tx);
104
+
105
+ // 3. Miner validates:
106
+ // - UTXOs exist and unspent
107
+ // - Signatures are valid
108
+ // - Transaction balance is correct
109
+ // - No double spending
110
+
111
+ // 4. If valid: Update global UTXO set
112
+ // 5. If invalid: Reject with error details
113
+ ```
114
+
115
+ ### Advanced Usage
116
+
117
+ - **Multiple wallets:** Each wallet can be registered independently
118
+ - **Transaction validation:** Full BSV-compatible signature and balance checking
119
+ - **Double-spend prevention:** UTXOs tracked globally to prevent reuse
120
+ - **Block simulation:** Each processed transaction increments block height
121
+
122
+ ## Dependencies
123
+
124
+ These utilities require the BSV library from the parent directory (`../index.js`).
125
+
126
+ ## Purpose
127
+
128
+ These utilities provide a consistent testing environment for BSV development, particularly useful for:
129
+ - Transaction creation and verification testing
130
+ - UTXO management in multi-transaction scenarios
131
+ - Consistent test wallet environments
132
+ - Mock blockchain data generation
@@ -0,0 +1,332 @@
1
+ /**
2
+ * 🌐 BSV Blockchain State Manager
3
+ *
4
+ * Simulates a global blockchain state with multiple wallets and UTXO tracking.
5
+ * Acts as the "blockchain database" for our miner simulator.
6
+ */
7
+
8
+ // Browser-compatible imports
9
+ let bsv, fs, path, BLOCKCHAIN_STATE_PATH;
10
+
11
+ // Only require Node.js modules in Node.js environment
12
+ if (typeof window === 'undefined' && typeof require === 'function') {
13
+ try {
14
+ bsv = require('../index.js');
15
+ fs = require('fs');
16
+ path = require('path');
17
+ BLOCKCHAIN_STATE_PATH = path.join(__dirname, 'blockchain-state.json');
18
+ } catch (e) {
19
+ console.warn('BlockchainState: Running in browser mode - persistence disabled');
20
+ }
21
+ } else {
22
+ // In browser, try to get bsv from global scope or fallback
23
+ bsv = (typeof window !== 'undefined' && window.bsv) || require('../index.js');
24
+ }
25
+
26
+ /**
27
+ * Initialize empty blockchain state
28
+ */
29
+ function initializeBlockchainState() {
30
+ return {
31
+ metadata: {
32
+ createdAt: new Date().toISOString(),
33
+ lastUpdated: new Date().toISOString(),
34
+ totalWallets: 0,
35
+ totalUTXOs: 0,
36
+ totalValue: 0,
37
+ blockHeight: 0
38
+ },
39
+ wallets: {}, // keyed by address
40
+ globalUTXOSet: {}, // keyed by "txid:vout"
41
+ spentUTXOs: {}, // keyed by "txid:vout"
42
+ transactionHistory: []
43
+ };
44
+ }
45
+
46
+ /**
47
+ * Load blockchain state from file
48
+ */
49
+ function loadBlockchainState() {
50
+ try {
51
+ // In browser, use localStorage or return initial state
52
+ if (!fs || !BLOCKCHAIN_STATE_PATH) {
53
+ return initializeBlockchainState();
54
+ }
55
+
56
+ if (!fs.existsSync(BLOCKCHAIN_STATE_PATH)) {
57
+ console.log('🆕 Creating new blockchain state...');
58
+ const initialState = initializeBlockchainState();
59
+ saveBlockchainState(initialState);
60
+ return initialState;
61
+ }
62
+
63
+ const state = JSON.parse(fs.readFileSync(BLOCKCHAIN_STATE_PATH, 'utf8'));
64
+ console.log('📖 Loaded existing blockchain state');
65
+ return state;
66
+ } catch (error) {
67
+ console.error('❌ Error loading blockchain state:', error.message);
68
+ return initializeBlockchainState();
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Save blockchain state to file
74
+ */
75
+ function saveBlockchainState(state) {
76
+ try {
77
+ state.metadata.lastUpdated = new Date().toISOString();
78
+
79
+ // Only save to file in Node.js environment
80
+ if (fs && BLOCKCHAIN_STATE_PATH) {
81
+ fs.writeFileSync(BLOCKCHAIN_STATE_PATH, JSON.stringify(state, null, 2));
82
+ console.log('💾 Blockchain state saved');
83
+ }
84
+ } catch (error) {
85
+ console.error('❌ Error saving blockchain state:', error.message);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Register a new wallet in the blockchain state
91
+ */
92
+ function registerWallet(walletAddress, walletData) {
93
+ console.log(`📝 Registering wallet: ${walletAddress}`);
94
+
95
+ const state = loadBlockchainState();
96
+
97
+ if (state.wallets[walletAddress]) {
98
+ console.log('ℹ️ Wallet already exists, updating...');
99
+ }
100
+
101
+ state.wallets[walletAddress] = {
102
+ address: walletAddress,
103
+ registeredAt: walletData.registeredAt || new Date().toISOString(),
104
+ utxos: walletData.utxos || [],
105
+ totalValue: 0
106
+ };
107
+
108
+ // Add UTXOs to global set
109
+ if (walletData.utxos) {
110
+ walletData.utxos.forEach(utxo => {
111
+ const utxoKey = `${utxo.txid}:${utxo.vout}`;
112
+ state.globalUTXOSet[utxoKey] = {
113
+ ...utxo,
114
+ ownerAddress: walletAddress
115
+ };
116
+ });
117
+ }
118
+
119
+ // Update metadata
120
+ state.metadata.totalWallets = Object.keys(state.wallets).length;
121
+ updateBlockchainMetadata(state);
122
+
123
+ saveBlockchainState(state);
124
+
125
+ console.log(`✅ Wallet registered: ${walletAddress}`);
126
+ return state;
127
+ }
128
+
129
+ /**
130
+ * Get UTXO by key (txid:vout)
131
+ */
132
+ function getUTXO(txid, vout) {
133
+ const state = loadBlockchainState();
134
+ const utxoKey = `${txid}:${vout}`;
135
+
136
+ if (state.spentUTXOs[utxoKey]) {
137
+ return { exists: false, spent: true, utxo: state.spentUTXOs[utxoKey] };
138
+ }
139
+
140
+ if (state.globalUTXOSet[utxoKey]) {
141
+ return { exists: true, spent: false, utxo: state.globalUTXOSet[utxoKey] };
142
+ }
143
+
144
+ return { exists: false, spent: false, utxo: null };
145
+ }
146
+
147
+ /**
148
+ * Check if UTXO exists and is unspent
149
+ */
150
+ function isUTXOAvailable(txid, vout) {
151
+ const result = getUTXO(txid, vout);
152
+ return result.exists && !result.spent;
153
+ }
154
+
155
+ /**
156
+ * Spend a UTXO (move from available to spent)
157
+ */
158
+ function spendUTXO(txid, vout, spentInTx) {
159
+ const state = loadBlockchainState();
160
+ const utxoKey = `${txid}:${vout}`;
161
+
162
+ if (!state.globalUTXOSet[utxoKey]) {
163
+ throw new Error(`UTXO ${utxoKey} does not exist`);
164
+ }
165
+
166
+ if (state.spentUTXOs[utxoKey]) {
167
+ throw new Error(`UTXO ${utxoKey} already spent`);
168
+ }
169
+
170
+ // Move UTXO from available to spent
171
+ const utxo = state.globalUTXOSet[utxoKey];
172
+ state.spentUTXOs[utxoKey] = {
173
+ ...utxo,
174
+ spentInTx,
175
+ spentAt: new Date().toISOString()
176
+ };
177
+
178
+ delete state.globalUTXOSet[utxoKey];
179
+
180
+ // Update wallet's UTXO list
181
+ const wallet = state.wallets[utxo.ownerAddress];
182
+ if (wallet) {
183
+ wallet.utxos = wallet.utxos.filter(u => !(u.txid === txid && u.vout === vout));
184
+ }
185
+
186
+ updateBlockchainMetadata(state);
187
+ saveBlockchainState(state);
188
+ console.log(`❌ UTXO spent: ${utxoKey} in tx ${spentInTx}`);
189
+ }
190
+
191
+ /**
192
+ * Add new UTXO to the global set
193
+ */
194
+ function addUTXO(utxo, ownerAddress) {
195
+ const state = loadBlockchainState();
196
+ const utxoKey = `${utxo.txid}:${utxo.vout}`;
197
+
198
+ // Check if UTXO already exists
199
+ if (state.globalUTXOSet[utxoKey]) {
200
+ console.log(`⚠️ UTXO ${utxoKey} already exists, skipping`);
201
+ return;
202
+ }
203
+
204
+ state.globalUTXOSet[utxoKey] = {
205
+ ...utxo,
206
+ ownerAddress,
207
+ createdAt: new Date().toISOString()
208
+ };
209
+
210
+ // Add to wallet's UTXO list
211
+ if (!state.wallets[ownerAddress]) {
212
+ state.wallets[ownerAddress] = {
213
+ address: ownerAddress,
214
+ registeredAt: new Date().toISOString(),
215
+ utxos: [],
216
+ totalValue: 0
217
+ };
218
+ }
219
+
220
+ // Check if UTXO already exists in wallet's list
221
+ const exists = state.wallets[ownerAddress].utxos.some(existingUTXO =>
222
+ existingUTXO.txid === utxo.txid && existingUTXO.vout === utxo.vout
223
+ );
224
+
225
+ if (!exists) {
226
+ state.wallets[ownerAddress].utxos.push(utxo);
227
+ }
228
+
229
+ updateBlockchainMetadata(state);
230
+ saveBlockchainState(state);
231
+
232
+ console.log(`✅ UTXO added: ${utxoKey} for ${ownerAddress}`);
233
+ }
234
+
235
+ /**
236
+ * Update blockchain metadata
237
+ */
238
+ function updateBlockchainMetadata(state) {
239
+ const totalUTXOs = Object.keys(state.globalUTXOSet).length;
240
+ const totalValue = Object.values(state.globalUTXOSet)
241
+ .reduce((sum, utxo) => sum + utxo.satoshis, 0);
242
+
243
+ state.metadata.totalUTXOs = totalUTXOs;
244
+ state.metadata.totalValue = totalValue;
245
+
246
+ // Update wallet totals
247
+ Object.values(state.wallets).forEach(wallet => {
248
+ wallet.totalValue = wallet.utxos.reduce((sum, utxo) => sum + utxo.satoshis, 0);
249
+ });
250
+ }
251
+
252
+ /**
253
+ * Get blockchain statistics
254
+ */
255
+ function getBlockchainStats() {
256
+ const state = loadBlockchainState();
257
+
258
+ console.log('🌐 Blockchain State Statistics:');
259
+ console.log('═══════════════════════════════════════════');
260
+ console.log(`📊 Total Wallets: ${state.metadata.totalWallets}`);
261
+ console.log(`💰 Total UTXOs: ${state.metadata.totalUTXOs}`);
262
+ console.log(`💎 Total Value: ${state.metadata.totalValue} satoshis`);
263
+ console.log(`🏗️ Block Height: ${state.metadata.blockHeight}`);
264
+ console.log(`🕐 Last Updated: ${state.metadata.lastUpdated}\n`);
265
+
266
+ if (Object.keys(state.wallets).length > 0) {
267
+ console.log('👛 Registered Wallets:');
268
+ Object.entries(state.wallets).forEach(([address, wallet]) => {
269
+ console.log(` ${address}: ${wallet.utxos.length} UTXOs, ${wallet.totalValue} sats`);
270
+ });
271
+ }
272
+
273
+ return state;
274
+ }
275
+
276
+ /**
277
+ * Import existing wallet from wallet.json
278
+ */
279
+ function importWalletFromFile() {
280
+ const walletPath = path.join(__dirname, 'wallet.json');
281
+
282
+ if (!fs.existsSync(walletPath)) {
283
+ console.log('❌ No wallet.json found to import');
284
+ return false;
285
+ }
286
+
287
+ try {
288
+ const walletData = JSON.parse(fs.readFileSync(walletPath, 'utf8'));
289
+
290
+ console.log('📥 Importing wallet from wallet.json...');
291
+
292
+ const walletInfo = {
293
+ registeredAt: new Date().toISOString(),
294
+ utxos: walletData.availableUTXOs || [walletData.utxo]
295
+ };
296
+
297
+ registerWallet(walletData.wallet.address, walletInfo);
298
+
299
+ console.log('✅ Wallet imported successfully');
300
+ return true;
301
+ } catch (error) {
302
+ console.error('❌ Error importing wallet:', error.message);
303
+ return false;
304
+ }
305
+ }
306
+
307
+ // If called directly, show stats or import wallet
308
+ if (require.main === module) {
309
+ const args = process.argv.slice(2);
310
+
311
+ if (args[0] === 'import') {
312
+ importWalletFromFile();
313
+ } else if (args[0] === 'init') {
314
+ const state = initializeBlockchainState();
315
+ saveBlockchainState(state);
316
+ console.log('🆕 Initialized new blockchain state');
317
+ }
318
+
319
+ getBlockchainStats();
320
+ }
321
+
322
+ module.exports = {
323
+ loadBlockchainState,
324
+ saveBlockchainState,
325
+ registerWallet,
326
+ getUTXO,
327
+ isUTXOAvailable,
328
+ spendUTXO,
329
+ addUTXO,
330
+ getBlockchainStats,
331
+ importWalletFromFile
332
+ };
@@ -0,0 +1,41 @@
1
+ {
2
+ "metadata": {
3
+ "createdAt": "2025-10-19T16:31:36.266Z",
4
+ "lastUpdated": "2025-10-19T16:31:36.893Z",
5
+ "totalWallets": 0,
6
+ "totalUTXOs": 1,
7
+ "totalValue": 43425,
8
+ "blockHeight": 0
9
+ },
10
+ "wallets": {
11
+ "11gECtvDapMj5ZuwpvnP6Wv9MTRGxnFRs": {
12
+ "address": "11gECtvDapMj5ZuwpvnP6Wv9MTRGxnFRs",
13
+ "registeredAt": "2025-10-19T16:31:36.893Z",
14
+ "utxos": [
15
+ {
16
+ "txid": "44c099bee41c7ffe853e4310e413781e1f543f554bafb9e46cad44f89ce3447e",
17
+ "vout": 1,
18
+ "address": "11gECtvDapMj5ZuwpvnP6Wv9MTRGxnFRs",
19
+ "satoshis": 43425,
20
+ "script": "76a9140020bee080cfdeb430cf723d952dc88b6bb7424188ac",
21
+ "height": 0
22
+ }
23
+ ],
24
+ "totalValue": 43425
25
+ }
26
+ },
27
+ "globalUTXOSet": {
28
+ "44c099bee41c7ffe853e4310e413781e1f543f554bafb9e46cad44f89ce3447e:1": {
29
+ "txid": "44c099bee41c7ffe853e4310e413781e1f543f554bafb9e46cad44f89ce3447e",
30
+ "vout": 1,
31
+ "address": "11gECtvDapMj5ZuwpvnP6Wv9MTRGxnFRs",
32
+ "satoshis": 43425,
33
+ "script": "76a9140020bee080cfdeb430cf723d952dc88b6bb7424188ac",
34
+ "height": 0,
35
+ "ownerAddress": "11gECtvDapMj5ZuwpvnP6Wv9MTRGxnFRs",
36
+ "createdAt": "2025-10-19T16:31:36.893Z"
37
+ }
38
+ },
39
+ "spentUTXOs": {},
40
+ "transactionHistory": []
41
+ }