smartledger-bsv 3.0.1 → 3.1.0

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/index.js CHANGED
@@ -97,5 +97,16 @@ bsv.SmartLedger = {
97
97
  bsv.SmartVerify = require('./lib/crypto/smartledger_verify')
98
98
  bsv.EllipticFixed = require('./lib/crypto/elliptic-fixed')
99
99
 
100
+ // SmartLedger Development & Testing Tools (Node.js only)
101
+ if (typeof window === 'undefined' && typeof require === 'function') {
102
+ try {
103
+ bsv.SmartUTXO = require('./lib/smartutxo')
104
+ bsv.SmartMiner = require('./lib/smartminer')
105
+ bsv.CustomScriptHelper = require('./lib/custom-script-helper')
106
+ } catch (e) {
107
+ // Browser environment - these tools not available
108
+ }
109
+ }
110
+
100
111
  // Internal usage, exposed for testing/advanced tweaking
101
112
  bsv.Transaction.sighash = require('./lib/transaction/sighash')
@@ -23,7 +23,22 @@ ECDSA.prototype.set = function (obj) {
23
23
  this.endian = obj.endian || this.endian // the endianness of hashbuf
24
24
  this.privkey = obj.privkey || this.privkey
25
25
  this.pubkey = obj.pubkey || (this.privkey ? this.privkey.publicKey : this.pubkey)
26
- this.sig = obj.sig || this.sig
26
+
27
+ // === SmartLedger Signature Handling ===
28
+ // Auto-parse DER buffers to Signature objects for compatibility
29
+ if (obj.sig) {
30
+ if (Buffer.isBuffer(obj.sig)) {
31
+ // Parse DER buffer to Signature object
32
+ var Signature = require('./signature')
33
+ this.sig = Signature.fromDER(obj.sig)
34
+ } else {
35
+ // Already a Signature object
36
+ this.sig = obj.sig
37
+ }
38
+ } else {
39
+ this.sig = this.sig
40
+ }
41
+
27
42
  this.k = obj.k || this.k
28
43
  this.verified = obj.verified || this.verified
29
44
  return this
@@ -159,53 +174,57 @@ ECDSA.prototype.sigError = function () {
159
174
 
160
175
  // === SmartLedger Security Patches ===
161
176
  // Apply security validation during cryptographic verification
162
- try {
163
- // Create a copy to avoid mutating original signature
164
- var secureSig = {
165
- r: this.sig.r,
166
- s: this.sig.s
167
- }
168
-
169
- // Apply security patches to the copy
170
- var n = Point.getN()
177
+ var r = this.sig.r
178
+ var s = this.sig.s
179
+ var n = Point.getN()
171
180
 
172
- // Fix 1 & 2: Enhanced range validation (maintains original message for compatibility)
173
- if (secureSig.r.isZero() || secureSig.s.isZero() ||
174
- secureSig.r.gte(n) || secureSig.s.gte(n)) {
181
+ try {
182
+ // Fix 1 & 2: Enhanced range validation
183
+ if (r.isZero() || s.isZero() || r.gte(n) || s.gte(n)) {
175
184
  return 'r and s not in range'
176
185
  }
177
186
 
178
- // Fix 3: Canonicalize s for verification (non-mutating)
187
+ // Fix 3: Handle canonicalization properly
188
+ // For verification, we need to try both the original s and canonical s
189
+ // This handles both pre-canonicalized signatures and non-canonical ones
179
190
  var nh = n.shrn(1) // n/2
180
- if (secureSig.s.gt(nh)) {
181
- secureSig.s = n.sub(secureSig.s)
191
+ var canonicalS = s.gt(nh) ? n.sub(s) : s
192
+
193
+ var e = BN.fromBuffer(this.hashbuf, this.endian ? {
194
+ endian: this.endian
195
+ } : undefined)
196
+
197
+ // Try verification with canonical s
198
+ var sinv = canonicalS.invm(n)
199
+ var u1 = sinv.mul(e).umod(n)
200
+ var u2 = sinv.mul(r).umod(n)
201
+
202
+ var p = Point.getG().mulAdd(u1, this.pubkey.point, u2)
203
+ if (p.isInfinity()) {
204
+ return 'p is infinity'
182
205
  }
183
206
 
184
- // Use secure signature for verification
185
- var r = secureSig.r
186
- var canonicalS = secureSig.s
207
+ if (p.getX().umod(n).cmp(r) !== 0) {
208
+ // If canonical verification failed and s was already canonical,
209
+ // try with the non-canonical version (for backwards compatibility)
210
+ if (s.lte(nh)) {
211
+ var nonCanonicalS = n.sub(s)
212
+ sinv = nonCanonicalS.invm(n)
213
+ u1 = sinv.mul(e).umod(n)
214
+ u2 = sinv.mul(r).umod(n)
215
+
216
+ p = Point.getG().mulAdd(u1, this.pubkey.point, u2)
217
+ if (!p.isInfinity() && p.getX().umod(n).cmp(r) === 0) {
218
+ return false // Verification succeeded with non-canonical s
219
+ }
220
+ }
221
+ return 'Invalid signature'
222
+ } else {
223
+ return false // Verification succeeded with canonical s
224
+ }
187
225
  } catch (error) {
188
226
  return 'Signature security validation failed: ' + error.message
189
227
  }
190
-
191
- var e = BN.fromBuffer(this.hashbuf, this.endian ? {
192
- endian: this.endian
193
- } : undefined)
194
- // Use canonical s for verification
195
- var sinv = canonicalS.invm(n)
196
- var u1 = sinv.mul(e).umod(n)
197
- var u2 = sinv.mul(r).umod(n)
198
-
199
- var p = Point.getG().mulAdd(u1, this.pubkey.point, u2)
200
- if (p.isInfinity()) {
201
- return 'p is infinity'
202
- }
203
-
204
- if (p.getX().umod(n).cmp(r) !== 0) {
205
- return 'Invalid signature'
206
- } else {
207
- return false
208
- }
209
228
  }
210
229
 
211
230
  ECDSA.toLowS = function (s) {
@@ -16,7 +16,7 @@ const nh = n.shrn(1) // n / 2
16
16
  /**
17
17
  * Hardened signature verification with canonicalization
18
18
  * @param {Buffer} msgHash - 32-byte message hash
19
- * @param {Signature} sig - Signature object with r,s components
19
+ * @param {Signature|Buffer} sig - Signature object with r,s components or DER buffer
20
20
  * @param {PublicKey} pubkey - Public key for verification
21
21
  * @returns {boolean} - true if signature is valid and canonical
22
22
  */
@@ -26,13 +26,28 @@ function smartVerify (msgHash, sig, pubkey) {
26
26
  throw new Error('Invalid message hash: must be 32-byte buffer')
27
27
  }
28
28
 
29
- if (!sig || !sig.r || !sig.s) {
29
+ if (!sig) {
30
+ return false
31
+ }
32
+
33
+ // Parse DER buffer to Signature object if needed
34
+ let sigObj = sig
35
+ if (Buffer.isBuffer(sig)) {
36
+ try {
37
+ const Signature = require('./signature')
38
+ sigObj = Signature.fromDER(sig)
39
+ } catch (e) {
40
+ return false
41
+ }
42
+ }
43
+
44
+ if (!sigObj || !sigObj.r || !sigObj.s) {
30
45
  return false
31
46
  }
32
47
 
33
48
  // Ensure r and s are BN instances
34
- const r = BN.isBN(sig.r) ? sig.r : new BN(sig.r)
35
- const s = BN.isBN(sig.s) ? sig.s : new BN(sig.s)
49
+ const r = BN.isBN(sigObj.r) ? sigObj.r : new BN(sigObj.r)
50
+ const s = BN.isBN(sigObj.s) ? sigObj.s : new BN(sigObj.s)
36
51
 
37
52
  // Reject zero values
38
53
  if (r.isZero() || s.isZero()) {
@@ -50,27 +65,43 @@ function smartVerify (msgHash, sig, pubkey) {
50
65
  canonicalS = n.sub(s)
51
66
  }
52
67
 
53
- // Create canonicalized signature object
54
- const canonicalSig = {
68
+ // Create canonicalized signature object for ECDSA verify
69
+ const Signature = require('./signature')
70
+ const canonicalSig = new Signature({
55
71
  r: r,
56
72
  s: canonicalS
57
- }
73
+ })
58
74
 
59
- // Use BSV's original ECDSA verify with canonical signature
75
+ // Use BSV's ECDSA verify with canonical signature object
60
76
  return ECDSA.verify(msgHash, canonicalSig, pubkey)
61
77
  }
62
78
 
63
79
  /**
64
80
  * Check if signature is in canonical form (s <= n/2)
65
- * @param {Object} sig - Signature with r,s components
81
+ * @param {Object|Buffer} sig - Signature with r,s components or DER buffer
66
82
  * @returns {boolean} - true if signature is canonical
67
83
  */
68
84
  function isCanonical (sig) {
69
- if (!sig || !sig.s) {
85
+ if (!sig) {
70
86
  return false
71
87
  }
72
88
 
73
- const s = BN.isBN(sig.s) ? sig.s : new BN(sig.s)
89
+ // Parse DER buffer to Signature object if needed
90
+ let sigObj = sig
91
+ if (Buffer.isBuffer(sig)) {
92
+ try {
93
+ const Signature = require('./signature')
94
+ sigObj = Signature.fromDER(sig)
95
+ } catch (e) {
96
+ return false
97
+ }
98
+ }
99
+
100
+ if (!sigObj || !sigObj.s) {
101
+ return false
102
+ }
103
+
104
+ const s = BN.isBN(sigObj.s) ? sigObj.s : new BN(sigObj.s)
74
105
  return s.lte(nh)
75
106
  }
76
107
 
@@ -0,0 +1,249 @@
1
+ /**
2
+ * SmartLedger BSV Custom Script Helper
3
+ * Simplified API for custom script development
4
+ */
5
+
6
+ const bsv = require('../index.js');
7
+
8
+ class CustomScriptHelper {
9
+
10
+ /**
11
+ * Create a signature for any custom script
12
+ * @param {Transaction} transaction - The transaction object
13
+ * @param {PrivateKey} privateKey - Private key to sign with
14
+ * @param {number} inputIndex - Input index (0 for first input)
15
+ * @param {Script} lockingScript - The locking script being spent
16
+ * @param {number} satoshis - Amount in satoshis
17
+ * @param {number} sighashType - Signature hash type
18
+ * @returns {Buffer} Complete signature with sighash type
19
+ */
20
+ static createSignature(transaction, privateKey, inputIndex, lockingScript, satoshis, sighashType = null) {
21
+ sighashType = sighashType || (bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID);
22
+
23
+ const signature = bsv.Transaction.sighash.sign(
24
+ transaction,
25
+ privateKey,
26
+ sighashType,
27
+ inputIndex,
28
+ lockingScript,
29
+ new bsv.crypto.BN(satoshis)
30
+ );
31
+
32
+ return Buffer.concat([signature.toDER(), Buffer.from([sighashType])]);
33
+ }
34
+
35
+ /**
36
+ * Create a multi-signature locking script
37
+ * @param {number} m - Required signatures
38
+ * @param {PublicKey[]} publicKeys - Array of public keys
39
+ * @returns {Script} Multi-signature locking script
40
+ */
41
+ static createMultisigScript(m, publicKeys) {
42
+ let script = new bsv.Script().add(bsv.Opcode[`OP_${m}`]);
43
+
44
+ for (const pubKey of publicKeys) {
45
+ script = script.add(pubKey.toBuffer());
46
+ }
47
+
48
+ return script
49
+ .add(bsv.Opcode[`OP_${publicKeys.length}`])
50
+ .add(bsv.Opcode.OP_CHECKMULTISIG);
51
+ }
52
+
53
+ /**
54
+ * Create an unlocking script for multi-signature
55
+ * @param {Buffer[]} signatures - Array of signatures
56
+ * @returns {Script} Unlocking script for multisig
57
+ */
58
+ static createMultisigUnlocking(signatures) {
59
+ let script = new bsv.Script().add(bsv.Opcode.OP_0); // CHECKMULTISIG bug
60
+
61
+ for (const sig of signatures) {
62
+ script = script.add(sig);
63
+ }
64
+
65
+ return script;
66
+ }
67
+
68
+ /**
69
+ * Create a time-locked script (CHECKLOCKTIMEVERIFY)
70
+ * @param {number} lockTime - Block height or timestamp
71
+ * @param {Script} baseScript - Base script to execute after time lock
72
+ * @returns {Script} Time-locked script
73
+ */
74
+ static createTimelockScript(lockTime, baseScript) {
75
+ const lockTimeBuffer = Buffer.from(lockTime.toString(16).padStart(8, '0'), 'hex').reverse();
76
+
77
+ return new bsv.Script()
78
+ .add(lockTimeBuffer)
79
+ .add(bsv.Opcode.OP_CHECKLOCKTIMEVERIFY)
80
+ .add(bsv.Opcode.OP_DROP)
81
+ .add(baseScript.toBuffer());
82
+ }
83
+
84
+ /**
85
+ * Create a conditional script (IF/ELSE/ENDIF)
86
+ * @param {Script} ifScript - Script to execute if condition is true
87
+ * @param {Script} elseScript - Script to execute if condition is false
88
+ * @returns {Script} Conditional script
89
+ */
90
+ static createConditionalScript(ifScript, elseScript = null) {
91
+ let script = new bsv.Script()
92
+ .add(bsv.Opcode.OP_IF)
93
+ .add(ifScript.toBuffer());
94
+
95
+ if (elseScript) {
96
+ script = script
97
+ .add(bsv.Opcode.OP_ELSE)
98
+ .add(elseScript.toBuffer());
99
+ }
100
+
101
+ return script.add(bsv.Opcode.OP_ENDIF);
102
+ }
103
+
104
+ /**
105
+ * Create P2PKH script for a public key
106
+ * @param {PublicKey} publicKey - Public key
107
+ * @returns {Script} P2PKH locking script
108
+ */
109
+ static createP2PKHScript(publicKey) {
110
+ return new bsv.Script()
111
+ .add(bsv.Opcode.OP_DUP)
112
+ .add(bsv.Opcode.OP_HASH160)
113
+ .add(publicKey.toAddress().hashBuffer)
114
+ .add(bsv.Opcode.OP_EQUALVERIFY)
115
+ .add(bsv.Opcode.OP_CHECKSIG);
116
+ }
117
+
118
+ /**
119
+ * Create P2PKH unlocking script
120
+ * @param {Buffer} signature - Signature
121
+ * @param {PublicKey} publicKey - Public key
122
+ * @returns {Script} P2PKH unlocking script
123
+ */
124
+ static createP2PKHUnlocking(signature, publicKey) {
125
+ return new bsv.Script()
126
+ .add(signature)
127
+ .add(publicKey.toBuffer());
128
+ }
129
+
130
+ /**
131
+ * Get transaction preimage for covenant scripts
132
+ * @param {Transaction} transaction - The transaction
133
+ * @param {number} inputIndex - Input index
134
+ * @param {Script} lockingScript - Locking script
135
+ * @param {number} satoshis - Amount in satoshis
136
+ * @param {number} sighashType - Signature hash type
137
+ * @returns {Buffer} Transaction preimage
138
+ */
139
+ static getPreimage(transaction, inputIndex, lockingScript, satoshis, sighashType = null) {
140
+ sighashType = sighashType || (bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID);
141
+
142
+ return bsv.Transaction.sighash.sighash(
143
+ transaction,
144
+ sighashType,
145
+ inputIndex,
146
+ lockingScript,
147
+ new bsv.crypto.BN(satoshis)
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Create a simple data push script
153
+ * @param {Buffer|string} data - Data to push
154
+ * @returns {Script} Data push script
155
+ */
156
+ static createDataScript(data) {
157
+ if (typeof data === 'string') {
158
+ data = Buffer.from(data, 'utf8');
159
+ }
160
+ return new bsv.Script().add(data);
161
+ }
162
+
163
+ /**
164
+ * Create OP_RETURN data script
165
+ * @param {Buffer|string} data - Data for OP_RETURN
166
+ * @returns {Script} OP_RETURN script
167
+ */
168
+ static createOpReturnScript(data) {
169
+ if (typeof data === 'string') {
170
+ data = Buffer.from(data, 'utf8');
171
+ }
172
+ return new bsv.Script()
173
+ .add(bsv.Opcode.OP_FALSE)
174
+ .add(bsv.Opcode.OP_RETURN)
175
+ .add(data);
176
+ }
177
+
178
+ /**
179
+ * Validate a transaction with custom scripts
180
+ * @param {Transaction} transaction - Transaction to validate
181
+ * @returns {boolean} True if valid
182
+ */
183
+ static validateTransaction(transaction) {
184
+ try {
185
+ return transaction.verify();
186
+ } catch (error) {
187
+ console.error('Transaction validation error:', error.message);
188
+ return false;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Validate a specific input script
194
+ * @param {Script} unlockingScript - Unlocking script
195
+ * @param {Script} lockingScript - Locking script
196
+ * @param {Transaction} transaction - Transaction
197
+ * @param {number} inputIndex - Input index
198
+ * @returns {boolean} True if script is valid
199
+ */
200
+ static validateScript(unlockingScript, lockingScript, transaction, inputIndex) {
201
+ try {
202
+ const interpreter = new bsv.Script.Interpreter();
203
+ return interpreter.verify(
204
+ unlockingScript,
205
+ lockingScript,
206
+ transaction,
207
+ inputIndex,
208
+ bsv.Script.Interpreter.SCRIPT_VERIFY_P2SH |
209
+ bsv.Script.Interpreter.SCRIPT_VERIFY_STRICTENC |
210
+ bsv.Script.Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID |
211
+ bsv.Script.Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES |
212
+ bsv.Script.Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES
213
+ );
214
+ } catch (error) {
215
+ console.error('Script validation error:', error.message);
216
+ return false;
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Create a transaction with ultra-low fees
222
+ * @param {Object[]} utxos - Array of UTXOs
223
+ * @param {Object[]} outputs - Array of outputs
224
+ * @param {number} feePerKb - Fee per KB (default: 10 sats = 0.01 sats/byte)
225
+ * @returns {Transaction} Transaction with ultra-low fees
226
+ */
227
+ static createLowFeeTransaction(utxos, outputs, feePerKb = 10) {
228
+ let tx = new bsv.Transaction().feePerKb(feePerKb);
229
+
230
+ // Add inputs
231
+ for (const utxo of utxos) {
232
+ tx = tx.from(utxo);
233
+ }
234
+
235
+ // Add outputs
236
+ for (const output of outputs) {
237
+ tx = tx.to(output.address, output.satoshis);
238
+ }
239
+
240
+ return tx;
241
+ }
242
+ }
243
+
244
+ // Common signature hash types
245
+ CustomScriptHelper.SIGHASH_ALL = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID;
246
+ CustomScriptHelper.SIGHASH_NONE = bsv.crypto.Signature.SIGHASH_NONE | bsv.crypto.Signature.SIGHASH_FORKID;
247
+ CustomScriptHelper.SIGHASH_SINGLE = bsv.crypto.Signature.SIGHASH_SINGLE | bsv.crypto.Signature.SIGHASH_FORKID;
248
+
249
+ module.exports = CustomScriptHelper;
@@ -655,19 +655,21 @@ Interpreter.prototype.step = function () {
655
655
  switch (opcode) {
656
656
  case Opcode.OP_2MUL:
657
657
  case Opcode.OP_2DIV:
658
-
659
- // Disabled opcodes.
658
+ // Permanently disabled opcodes.
660
659
  return true
661
660
 
662
661
  case Opcode.OP_INVERT:
663
662
  case Opcode.OP_MUL:
664
663
  case Opcode.OP_LSHIFT:
665
664
  case Opcode.OP_RSHIFT:
666
- // Opcodes that have been reenabled.
665
+ // Magnetic opcodes - still require flag for backwards compatibility
667
666
  if ((self.flags & Interpreter.SCRIPT_ENABLE_MAGNETIC_OPCODES) === 0) {
668
667
  return true
669
668
  }
670
669
  break
670
+
671
+ // Monolith opcodes are now enabled by default in SmartLedger BSV
672
+ // These were activated in May 2018 and are part of standard BSV consensus
671
673
  case Opcode.OP_DIV:
672
674
  case Opcode.OP_MOD:
673
675
  case Opcode.OP_SPLIT:
@@ -677,11 +679,9 @@ Interpreter.prototype.step = function () {
677
679
  case Opcode.OP_XOR:
678
680
  case Opcode.OP_BIN2NUM:
679
681
  case Opcode.OP_NUM2BIN:
680
- // Opcodes that have been reenabled.
681
- if ((self.flags & Interpreter.SCRIPT_ENABLE_MONOLITH_OPCODES) === 0) {
682
- return true
683
- }
684
- break
682
+ // These opcodes are now always enabled - no flag required
683
+ return false
684
+
685
685
  default:
686
686
  break
687
687
  }
@@ -0,0 +1,169 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * SmartLedger Miner Simulator
5
+ * Provides BSV blockchain mining simulation for testing and development
6
+ */
7
+
8
+ /**
9
+ * Comprehensive BSV Miner Simulator for development and testing
10
+ */
11
+ class SmartMiner {
12
+ constructor(bsv, options = {}) {
13
+ this.bsv = bsv
14
+ this.options = {
15
+ difficulty: options.difficulty || 1,
16
+ blockTime: options.blockTime || 10000, // 10 seconds for testing
17
+ validateScripts: options.validateScripts !== false, // default true
18
+ logLevel: options.logLevel || 'info',
19
+ ...options
20
+ }
21
+
22
+ this.currentBlock = {
23
+ height: 0,
24
+ transactions: [],
25
+ timestamp: Date.now()
26
+ }
27
+
28
+ this.mempool = []
29
+ }
30
+
31
+ /**
32
+ * Add a transaction to the mempool for mining
33
+ * @param {Transaction} transaction - BSV transaction object
34
+ * @returns {boolean} - true if accepted, false if rejected
35
+ */
36
+ acceptTransaction(transaction) {
37
+ try {
38
+ // Validate transaction if script validation is enabled
39
+ if (this.options.validateScripts) {
40
+ const isValid = this.validateTransactionSignatures(transaction)
41
+ if (!isValid) {
42
+ this.log('warn', '❌ Transaction rejected: Invalid signatures')
43
+ return false
44
+ }
45
+ }
46
+
47
+ // Add to mempool
48
+ this.mempool.push(transaction)
49
+ this.log('info', `✅ Transaction accepted into mempool: ${transaction.id || 'unknown'}`)
50
+ return true
51
+
52
+ } catch (error) {
53
+ this.log('error', `❌ Transaction rejected: ${error.message}`)
54
+ return false
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Validate transaction signatures using BSV library
60
+ * @param {Transaction} transaction - BSV transaction
61
+ * @returns {boolean} - true if all signatures are valid
62
+ */
63
+ validateTransactionSignatures(transaction) {
64
+ try {
65
+ // Use BSV's built-in transaction verification
66
+ const result = transaction.verify()
67
+ this.log('debug', `📊 Transaction verification result: ${result}`)
68
+ return result === true
69
+ } catch (error) {
70
+ this.log('warn', `⚠️ Signature validation error: ${error.message}`)
71
+ return false
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Mine a new block with transactions from mempool
77
+ * @param {number} maxTransactions - Maximum transactions per block
78
+ * @returns {Object} - Mined block object
79
+ */
80
+ mineBlock(maxTransactions = 10) {
81
+ const transactions = this.mempool.splice(0, maxTransactions)
82
+
83
+ const block = {
84
+ height: this.currentBlock.height + 1,
85
+ timestamp: Date.now(),
86
+ transactions: transactions,
87
+ transactionCount: transactions.length,
88
+ previousBlockHash: this.currentBlock.hash || '0000000000000000000000000000000000000000000000000000000000000000'
89
+ }
90
+
91
+ // Simple block hash simulation
92
+ const blockData = JSON.stringify({
93
+ height: block.height,
94
+ timestamp: block.timestamp,
95
+ previousBlockHash: block.previousBlockHash,
96
+ transactions: transactions.map(tx => tx.id || tx.toString())
97
+ })
98
+
99
+ block.hash = this.bsv.crypto.Hash.sha256(Buffer.from(blockData)).toString('hex')
100
+
101
+ this.currentBlock = block
102
+
103
+ this.log('info', `⛏️ Mined block ${block.height} with ${transactions.length} transactions`)
104
+ this.log('debug', `📦 Block hash: ${block.hash}`)
105
+
106
+ return block
107
+ }
108
+
109
+ /**
110
+ * Get mempool status
111
+ * @returns {Object} - Mempool statistics
112
+ */
113
+ getMempoolStats() {
114
+ return {
115
+ transactionCount: this.mempool.length,
116
+ transactions: this.mempool.map(tx => ({
117
+ id: tx.id || 'unknown',
118
+ size: tx.toBuffer ? tx.toBuffer().length : 0,
119
+ inputs: tx.inputs ? tx.inputs.length : 0,
120
+ outputs: tx.outputs ? tx.outputs.length : 0
121
+ }))
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Get current blockchain status
127
+ * @returns {Object} - Blockchain statistics
128
+ */
129
+ getBlockchainStats() {
130
+ return {
131
+ currentHeight: this.currentBlock.height,
132
+ currentBlockHash: this.currentBlock.hash,
133
+ currentBlockTimestamp: this.currentBlock.timestamp,
134
+ mempoolSize: this.mempool.length,
135
+ difficulty: this.options.difficulty,
136
+ blockTime: this.options.blockTime
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Reset the miner state
142
+ */
143
+ reset() {
144
+ this.currentBlock = {
145
+ height: 0,
146
+ transactions: [],
147
+ timestamp: Date.now()
148
+ }
149
+ this.mempool = []
150
+ this.log('info', '🔄 Miner reset to genesis state')
151
+ }
152
+
153
+ /**
154
+ * Logging utility
155
+ * @param {string} level - Log level
156
+ * @param {string} message - Log message
157
+ */
158
+ log(level, message) {
159
+ const levels = { error: 0, warn: 1, info: 2, debug: 3 }
160
+ const currentLevel = levels[this.options.logLevel] || 2
161
+
162
+ if (levels[level] <= currentLevel) {
163
+ const timestamp = new Date().toISOString()
164
+ console.log(`[${timestamp}] [${level.toUpperCase()}] ${message}`)
165
+ }
166
+ }
167
+ }
168
+
169
+ module.exports = SmartMiner