@smartledger/bsv 1.5.6-fix1 → 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/CHANGELOG.md +111 -0
- package/README.md +38 -10
- package/bsv.min.js +8 -8
- package/index.js +10 -0
- package/lib/crypto/ecdsa.js +57 -38
- package/lib/crypto/smartledger_verify.js +42 -11
- package/lib/script/interpreter.js +8 -8
- package/lib/smartminer.js +169 -0
- package/lib/smartutxo.js +200 -0
- package/lib/transaction/transaction.js +39 -0
- package/package.json +29 -4
- package/utilities/README.md +132 -0
- package/utilities/blockchain-state.js +332 -0
- package/utilities/blockchain-state.json +41 -0
- package/utilities/miner-simulator.js +620 -0
- package/utilities/mock-utxo-generator.js +149 -0
- package/utilities/raw-tx-examples.js +213 -0
- package/utilities/success-demo.js +193 -0
- package/utilities/transaction-examples.js +328 -0
- package/utilities/utxo-manager.js +162 -0
- package/utilities/wallet-setup.js +167 -0
- package/utilities/wallet.json +30 -0
- package/utilities/working-signature-demo.js +181 -0
- package/validation_test.js +97 -0
package/package.json
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartledger/bsv",
|
|
3
|
-
"version": "
|
|
4
|
-
"publishConfig": {
|
|
5
|
-
"access": "public"
|
|
6
|
-
},
|
|
3
|
+
"version": "3.0.2",
|
|
7
4
|
"description": "Security-hardened Bitcoin SV library - Complete drop-in replacement for bsv@1.5.6 with zero vulnerabilities",
|
|
8
5
|
"author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
|
|
9
6
|
"homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
|
|
@@ -14,15 +11,38 @@
|
|
|
14
11
|
"scripts": {
|
|
15
12
|
"lint": "standard",
|
|
16
13
|
"test": "standard && mocha",
|
|
14
|
+
"test:signatures": "node validation_test.js",
|
|
17
15
|
"coverage": "nyc --reporter=text npm run test",
|
|
18
16
|
"build-bsv": "webpack index.js --config webpack.config.js",
|
|
19
17
|
"build-ecies": "webpack ecies/index.js --config webpack.subproject.config.js --output-library bsvEcies -o bsv-ecies.min.js",
|
|
20
18
|
"build-message": "webpack message/index.js --config webpack.subproject.config.js --output-library bsvMessage -o bsv-message.min.js",
|
|
21
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",
|
|
22
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",
|
|
23
23
|
"prepublishOnly": "NODE_OPTIONS=\"--openssl-legacy-provider\" npm run build"
|
|
24
24
|
},
|
|
25
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
|
+
],
|
|
26
46
|
"keywords": [
|
|
27
47
|
"bitcoin",
|
|
28
48
|
"bitcoin-sv",
|
|
@@ -35,6 +55,11 @@
|
|
|
35
55
|
"hardened",
|
|
36
56
|
"vulnerability-free",
|
|
37
57
|
"drop-in-replacement",
|
|
58
|
+
"utxo-management",
|
|
59
|
+
"blockchain-simulator",
|
|
60
|
+
"miner-simulator",
|
|
61
|
+
"testing-tools",
|
|
62
|
+
"development-framework",
|
|
38
63
|
"ecies",
|
|
39
64
|
"p2p",
|
|
40
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
|
+
}
|