@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/index.js CHANGED
@@ -97,5 +97,15 @@ 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
+ } catch (e) {
106
+ // Browser environment - these tools not available
107
+ }
108
+ }
109
+
100
110
  // Internal usage, exposed for testing/advanced tweaking
101
111
  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
 
@@ -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
@@ -0,0 +1,200 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * SmartLedger UTXO Management System
5
+ * Provides blockchain state management and UTXO tracking for testing and development
6
+ */
7
+
8
+ // Browser-compatible imports
9
+ let fs, path, crypto, blockchainState
10
+
11
+ // Only require Node.js modules in Node.js environment
12
+ if (typeof window === 'undefined' && typeof require === 'function') {
13
+ try {
14
+ fs = require('fs')
15
+ path = require('path')
16
+ crypto = require('crypto')
17
+ blockchainState = require('../utilities/blockchain-state')
18
+ } catch (e) {
19
+ // Fallback for environments where these modules aren't available
20
+ console.warn('SmartUTXO: Running in browser mode - some features may be limited')
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Comprehensive UTXO Management System for BSV development
26
+ */
27
+ class SmartUTXOManager {
28
+ constructor(options = {}) {
29
+ this.options = options || {}
30
+
31
+ // Initialize blockchain state - this creates the file if needed
32
+ this.loadState()
33
+ }
34
+
35
+ /**
36
+ * Load blockchain state from file (initializes if needed)
37
+ */
38
+ loadState() {
39
+ try {
40
+ const state = blockchainState.loadBlockchainState()
41
+ return state
42
+ } catch (error) {
43
+ console.log('⚠️ Could not load blockchain state:', error.message)
44
+ return null
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Save blockchain state to file
50
+ */
51
+ saveState() {
52
+ try {
53
+ const state = blockchainState.loadBlockchainState()
54
+ blockchainState.saveBlockchainState(state)
55
+ const utxoCount = Object.keys(state.globalUTXOSet || {}).length
56
+ console.log(`💾 Saved blockchain state with ${utxoCount} UTXOs`)
57
+ } catch (error) {
58
+ console.log('⚠️ Could not save blockchain state:', error.message)
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Get all UTXOs for a given address
64
+ * @param {string} address - Bitcoin address
65
+ * @returns {Array} Array of UTXO objects
66
+ */
67
+ getUTXOsForAddress(address) {
68
+ try {
69
+ const state = blockchainState.loadBlockchainState()
70
+
71
+ // Check if wallet exists
72
+ if (!state.wallets || !state.wallets[address]) {
73
+ return []
74
+ }
75
+
76
+ // Return the wallet's UTXOs
77
+ return state.wallets[address].utxos || []
78
+ } catch (error) {
79
+ console.log('⚠️ Error getting UTXOs:', error.message)
80
+ return []
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Add a new UTXO to the system
86
+ * @param {Object} utxo - UTXO object {txid, vout, address, satoshis, script}
87
+ */
88
+ addUTXO(utxo) {
89
+ try {
90
+ // Use the correct API: addUTXO(utxo, ownerAddress)
91
+ blockchainState.addUTXO(utxo, utxo.address)
92
+ } catch (error) {
93
+ console.log('⚠️ Error adding UTXO:', error.message)
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Spend UTXOs (remove from available set)
99
+ * @param {Array} inputs - Array of input objects {txid, vout}
100
+ * @param {string} spentInTx - Optional transaction ID where UTXO was spent
101
+ */
102
+ spendUTXOs(inputs, spentInTx = 'manual-spend') {
103
+ try {
104
+ for (const input of inputs) {
105
+ // Use the correct API: spendUTXO(txid, vout, spentInTx)
106
+ blockchainState.spendUTXO(input.txid, input.vout, spentInTx)
107
+ }
108
+ } catch (error) {
109
+ console.log('⚠️ Error spending UTXOs:', error.message)
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Create mock UTXOs for testing
115
+ * @param {string} address - Target address
116
+ * @param {number} count - Number of UTXOs to create
117
+ * @param {number} satoshis - Satoshis per UTXO
118
+ * @returns {Array} Array of created UTXOs
119
+ */
120
+ createMockUTXOs(address, count = 5, satoshis = 100000) {
121
+ const mockUTXOs = []
122
+
123
+ for (let i = 0; i < count; i++) {
124
+ const txid = crypto.randomBytes(32).toString('hex')
125
+ const vout = i
126
+ const script = `76a914${crypto.randomBytes(20).toString('hex')}88ac` // Mock P2PKH script
127
+
128
+ const utxo = {
129
+ txid,
130
+ vout,
131
+ address,
132
+ satoshis,
133
+ script
134
+ }
135
+
136
+ mockUTXOs.push(utxo)
137
+ }
138
+
139
+ return mockUTXOs
140
+ }
141
+
142
+ /**
143
+ * Get total balance for an address
144
+ * @param {string} address - Bitcoin address
145
+ * @returns {number} Total satoshis
146
+ */
147
+ getBalance(address) {
148
+ try {
149
+ const state = blockchainState.loadBlockchainState()
150
+
151
+ // Check if wallet exists
152
+ if (!state.wallets || !state.wallets[address]) {
153
+ return 0
154
+ }
155
+
156
+ // Return the wallet's total value
157
+ return state.wallets[address].totalValue || 0
158
+ } catch (error) {
159
+ console.log('⚠️ Error getting balance:', error.message)
160
+ return 0
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Get blockchain statistics
166
+ * @returns {Object} Stats object
167
+ */
168
+ getStats() {
169
+ try {
170
+ const state = blockchainState.getBlockchainStats() // This returns the full state
171
+ return {
172
+ totalUTXOs: state.metadata.totalUTXOs,
173
+ totalValue: state.metadata.totalValue,
174
+ totalWallets: state.metadata.totalWallets,
175
+ blockHeight: state.metadata.blockHeight,
176
+ lastUpdated: state.metadata.lastUpdated
177
+ }
178
+ } catch (error) {
179
+ console.log('⚠️ Error getting stats:', error.message)
180
+ return { totalUTXOs: 0, totalValue: 0, totalWallets: 0, blockHeight: 0 }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Reset blockchain state
186
+ */
187
+ reset() {
188
+ try {
189
+ const statePath = path.join(__dirname, '../utilities/blockchain-state.json')
190
+ if (fs.existsSync(statePath)) {
191
+ fs.unlinkSync(statePath)
192
+ console.log('🔄 Blockchain state reset')
193
+ }
194
+ } catch (error) {
195
+ console.log('⚠️ Could not reset blockchain state:', error.message)
196
+ }
197
+ }
198
+ }
199
+
200
+ module.exports = SmartUTXOManager
@@ -24,6 +24,10 @@ var Output = require('./output')
24
24
  var Script = require('../script')
25
25
  var PrivateKey = require('../privatekey')
26
26
  var BN = require('../crypto/bn')
27
+ var Interpreter = require('../script/interpreter')
28
+
29
+ // By default, we sign with sighash_forkid
30
+ var DEFAULT_SIGN_FLAGS = Interpreter.SCRIPT_ENABLE_SIGHASH_FORKID
27
31
 
28
32
  /**
29
33
  * Represents a transaction, a set of inputs and outputs to change ownership of tokens
@@ -1205,4 +1209,39 @@ Transaction.prototype.isCoinbase = function () {
1205
1209
  return (this.inputs.length === 1 && this.inputs[0].isNull())
1206
1210
  }
1207
1211
 
1212
+ /**
1213
+ * Calculate the signature hash for an input
1214
+ *
1215
+ * @param {number} inputIndex - The index of the input to sign
1216
+ * @param {number} sighashType - The signature hash type (optional, defaults to ALL|FORKID)
1217
+ * @param {Script} subscript - The subscript to use (optional, derived from input)
1218
+ * @param {BN} satoshisBN - The amount in satoshis for this input (optional, derived from input)
1219
+ * @param {number} flags - Script verification flags (optional)
1220
+ * @return {Buffer} The signature hash for this input
1221
+ */
1222
+ Transaction.prototype.sighash = function (inputIndex, sighashType, subscript, satoshisBN, flags) {
1223
+ sighashType = sighashType || (Signature.SIGHASH_ALL | Signature.SIGHASH_FORKID)
1224
+
1225
+ // Get the input we're signing for
1226
+ var input = this.inputs[inputIndex]
1227
+ if (!input) {
1228
+ throw new Error('Input index ' + inputIndex + ' does not exist')
1229
+ }
1230
+
1231
+ // If subscript not provided, derive it from the input
1232
+ if (!subscript && input.output) {
1233
+ subscript = input.output.script
1234
+ }
1235
+
1236
+ // If satoshisBN not provided, derive it from the input
1237
+ if (!satoshisBN && input.output) {
1238
+ satoshisBN = new BN(input.output.satoshis)
1239
+ }
1240
+
1241
+ // Use default flags if not provided
1242
+ flags = flags || DEFAULT_SIGN_FLAGS
1243
+
1244
+ return Sighash.sighash(this, sighashType, inputIndex, subscript, satoshisBN, flags)
1245
+ }
1246
+
1208
1247
  module.exports = Transaction