@smartledger/bsv 3.1.1 โ†’ 3.2.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +123 -1
  2. package/README.md +233 -277
  3. package/bsv.bundle.js +39 -0
  4. package/bsv.min.js +8 -8
  5. package/docs/ADVANCED_COVENANT_DEVELOPMENT.md +533 -0
  6. package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +169 -0
  7. package/docs/CUSTOM_SCRIPT_DEVELOPMENT.md +320 -0
  8. package/docs/README.md +201 -0
  9. package/docs/block.md +46 -0
  10. package/docs/ecies.md +102 -0
  11. package/docs/index.md +104 -0
  12. package/docs/nchain.md +958 -0
  13. package/docs/networks.md +55 -0
  14. package/docs/preimage.md +126 -0
  15. package/docs/script.md +139 -0
  16. package/docs/transaction.md +174 -0
  17. package/docs/unspentoutput.md +32 -0
  18. package/examples/README.md +200 -0
  19. package/examples/basic/transaction-creation.js +534 -0
  20. package/examples/basic/transaction_signature_api_gap.js +178 -0
  21. package/examples/covenants/advanced_covenant_demo.js +219 -0
  22. package/examples/covenants/covenant_interface_demo.js +270 -0
  23. package/examples/covenants/covenant_manual_signature_resolved.js +212 -0
  24. package/examples/covenants/covenant_signature_template.js +117 -0
  25. package/examples/covenants2/covenant_bidirectional_example.js +262 -0
  26. package/examples/covenants2/covenant_utils_demo.js +120 -0
  27. package/examples/covenants2/preimage_covenant_utils.js +287 -0
  28. package/examples/covenants2/production_integration.js +256 -0
  29. package/examples/data/covenant_utxos.json +28 -0
  30. package/examples/data/utxos.json +26 -0
  31. package/examples/preimage/README.md +178 -0
  32. package/examples/preimage/extract_preimage_bidirectional.js +421 -0
  33. package/examples/preimage/generate_sample_preimage.js +208 -0
  34. package/examples/preimage/generate_sighash_examples.js +152 -0
  35. package/examples/preimage/parse_preimage.js +117 -0
  36. package/examples/preimage/test_preimage_extractor.js +53 -0
  37. package/examples/preimage/test_varint_extraction.js +95 -0
  38. package/examples/scripts/custom_script_helper_example.js +273 -0
  39. package/examples/scripts/custom_script_signature_test.js +344 -0
  40. package/examples/scripts/script_interpreter.js +193 -0
  41. package/examples/smart_contract/complete_workflow_demo.js +343 -0
  42. package/examples/smart_contract/covenant_builder_demo.js +176 -0
  43. package/examples/smart_contract/script_testing_integration.js +198 -0
  44. package/index.js +3 -0
  45. package/lib/covenant-interface.js +713 -0
  46. package/lib/opcode.js +14 -7
  47. package/lib/smart_contract/API_REFERENCE.md +754 -0
  48. package/lib/smart_contract/DOCUMENTATION_SUMMARY.md +201 -0
  49. package/lib/smart_contract/EXAMPLES.md +751 -0
  50. package/lib/smart_contract/QUICK_START.md +549 -0
  51. package/lib/smart_contract/README.md +395 -0
  52. package/lib/smart_contract/builder.js +452 -0
  53. package/lib/smart_contract/covenant.js +336 -0
  54. package/lib/smart_contract/covenant_builder.js +512 -0
  55. package/lib/smart_contract/index.js +311 -0
  56. package/lib/smart_contract/opcode_list.js +30 -0
  57. package/lib/smart_contract/opcode_map.js +1174 -0
  58. package/lib/smart_contract/opcodes.md +1173 -0
  59. package/lib/smart_contract/preimage.js +903 -0
  60. package/lib/smart_contract/script_tester.js +487 -0
  61. package/lib/smart_contract/script_utils.js +609 -0
  62. package/lib/smart_contract/sighash.js +310 -0
  63. package/lib/smart_contract/smartledger-opcode_review.md +70 -0
  64. package/lib/smart_contract/test_integration.js +269 -0
  65. package/lib/smart_contract/utxo_generator.js +367 -0
  66. package/package.json +43 -10
  67. package/utilities/blockchain-state.json +20478 -3
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate_sample_preimage.js
4
+ * Advanced BIP-143 preimage generator with multiple realistic scenarios
5
+ *
6
+ * Generates various types of preimages for testing bidirectional extraction:
7
+ * - Standard P2PKH transactions
8
+ * - Multi-signature scenarios
9
+ * - Custom script patterns
10
+ * - Different value ranges
11
+ */
12
+
13
+ function createSamplePreimage(type = 'standard') {
14
+ const { Buffer } = require("buffer");
15
+
16
+ // Base fields (same for all types)
17
+ const baseFields = {
18
+ nVersion: Buffer.from([0x01, 0x00, 0x00, 0x00]), // Version 1
19
+ hashPrevouts: Buffer.alloc(32, 0xab), // Mock hash
20
+ hashSequence: Buffer.alloc(32, 0xcd), // Mock hash
21
+ outpoint_txid: Buffer.alloc(32, 0x12), // Mock TXID
22
+ outpoint_vout: Buffer.from([0x00, 0x00, 0x00, 0x00]), // Output 0
23
+ nSequence: Buffer.from([0xff, 0xff, 0xff, 0xff]), // Max sequence
24
+ hashOutputs: Buffer.alloc(32, 0xef), // Mock hash
25
+ nLocktime: Buffer.from([0x00, 0x00, 0x00, 0x00]), // No locktime
26
+ sighashType: Buffer.from([0x41, 0x00, 0x00, 0x00]) // SIGHASH_ALL | FORKID
27
+ };
28
+
29
+ let scriptVariant;
30
+
31
+ switch (type) {
32
+ case 'standard':
33
+ // Standard P2PKH (25 bytes)
34
+ scriptVariant = {
35
+ scriptLen: Buffer.from([0x19]), // 25 bytes
36
+ scriptCode: Buffer.from([
37
+ 0x76, 0xa9, 0x14, // OP_DUP OP_HASH160 OP_PUSHDATA(20)
38
+ ...Buffer.alloc(20, 0x88), // 20-byte pubkey hash
39
+ 0x88, 0xac // OP_EQUALVERIFY OP_CHECKSIG
40
+ ]),
41
+ value: Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]) // 100000000 satoshis (1 BSV)
42
+ };
43
+ break;
44
+
45
+ case 'multisig':
46
+ // 2-of-3 multisig (71 bytes)
47
+ scriptVariant = {
48
+ scriptLen: Buffer.from([0x47]), // 71 bytes
49
+ scriptCode: Buffer.concat([
50
+ Buffer.from([0x52]), // OP_2 (required signatures)
51
+ Buffer.from([0x21]), Buffer.alloc(33, 0xaa), // First pubkey (33 bytes)
52
+ Buffer.from([0x21]), Buffer.alloc(33, 0xbb), // Second pubkey (33 bytes)
53
+ Buffer.from([0x21]), Buffer.alloc(33, 0xcc), // Third pubkey (33 bytes)
54
+ Buffer.from([0x53]), // OP_3 (total pubkeys)
55
+ Buffer.from([0xae]) // OP_CHECKMULTISIG
56
+ ]),
57
+ value: Buffer.from([0x00, 0x40, 0x42, 0x0f, 0x00, 0x00, 0x00, 0x00]) // 2.56 BSV
58
+ };
59
+ break;
60
+
61
+ case 'custom':
62
+ // Custom script with OP_RETURN data (34 bytes)
63
+ scriptVariant = {
64
+ scriptLen: Buffer.from([0x22]), // 34 bytes
65
+ scriptCode: Buffer.concat([
66
+ Buffer.from([0x6a]), // OP_RETURN
67
+ Buffer.from([0x20]), // Push 32 bytes
68
+ Buffer.from('Hello Bitcoin SV - Custom Script Test', 'utf8').slice(0, 32)
69
+ ]),
70
+ value: Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // 0 satoshis (OP_RETURN output)
71
+ };
72
+ break;
73
+
74
+ case 'large':
75
+ // Large script (300 bytes) to test CompactSize 3-byte varint (0xFD)
76
+ const scriptSize = 300;
77
+ scriptVariant = {
78
+ scriptLen: Buffer.from([0xfd, scriptSize & 0xff, (scriptSize >> 8) & 0xff]), // 3-byte varint: 0xFD + 2-byte LE
79
+ scriptCode: Buffer.concat([
80
+ Buffer.from([0x76, 0xa9, 0x14]), // OP_DUP OP_HASH160 OP_PUSHDATA(20)
81
+ Buffer.alloc(20, 0x99), // 20-byte pubkey hash
82
+ Buffer.from([0x88, 0xac]), // OP_EQUALVERIFY OP_CHECKSIG
83
+ Buffer.alloc(275, 0x6a) // Padding with OP_RETURN opcodes to reach 300 bytes
84
+ ]),
85
+ value: Buffer.from([0x00, 0x10, 0xa5, 0xd4, 0xe8, 0x00, 0x00, 0x00]) // 10 BSV
86
+ };
87
+ break;
88
+
89
+ case 'huge':
90
+ // Huge script (70000 bytes) to test CompactSize 5-byte varint (0xFE)
91
+ const hugeSize = 70000;
92
+ scriptVariant = {
93
+ scriptLen: Buffer.from([
94
+ 0xfe,
95
+ hugeSize & 0xff,
96
+ (hugeSize >> 8) & 0xff,
97
+ (hugeSize >> 16) & 0xff,
98
+ (hugeSize >> 24) & 0xff
99
+ ]), // 5-byte varint: 0xFE + 4-byte LE
100
+ scriptCode: Buffer.concat([
101
+ Buffer.from([0x6a]), // OP_RETURN
102
+ Buffer.from([0x4c, 0xff, 0xff]), // OP_PUSHDATA2 + 65535 bytes
103
+ Buffer.alloc(65535, 0xaa), // Large data block
104
+ Buffer.alloc(hugeSize - 65539, 0xbb) // Remaining padding
105
+ ]),
106
+ value: Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // 0 satoshis (data output)
107
+ };
108
+ break;
109
+
110
+ default:
111
+ throw new Error(`Unknown preimage type: ${type}`);
112
+ }
113
+
114
+ const fields = { ...baseFields, ...scriptVariant };
115
+
116
+ // Concatenate all fields
117
+ const preimage = Buffer.concat([
118
+ fields.nVersion,
119
+ fields.hashPrevouts,
120
+ fields.hashSequence,
121
+ fields.outpoint_txid,
122
+ fields.outpoint_vout,
123
+ fields.scriptLen,
124
+ fields.scriptCode,
125
+ fields.value,
126
+ fields.nSequence,
127
+ fields.hashOutputs,
128
+ fields.nLocktime,
129
+ fields.sighashType
130
+ ]);
131
+
132
+ return preimage.toString('hex');
133
+ }
134
+
135
+ // CLI Interface
136
+ if (require.main === module) {
137
+ const type = process.argv[2] || 'standard';
138
+
139
+ if (type === '--help' || type === '-h') {
140
+ console.log("๐ŸŽฏ Advanced BIP-143 Preimage Generator");
141
+ console.log("=====================================");
142
+ console.log("Usage: node generate_sample_preimage.js [type]");
143
+ console.log("");
144
+ console.log("Available types:");
145
+ console.log(" standard - Standard P2PKH script (25 bytes, 1-byte varint) - DEFAULT");
146
+ console.log(" multisig - 2-of-3 multisig script (71 bytes, 1-byte varint)");
147
+ console.log(" custom - Custom OP_RETURN script (34 bytes, 1-byte varint)");
148
+ console.log(" large - Large script (300 bytes, 3-byte varint 0xFD)");
149
+ console.log(" huge - Huge script (70000 bytes, 5-byte varint 0xFE)");
150
+ console.log("");
151
+ console.log("Examples:");
152
+ console.log(" node generate_sample_preimage.js");
153
+ console.log(" node generate_sample_preimage.js multisig");
154
+ console.log(" node generate_sample_preimage.js large # Test 3-byte varint");
155
+ console.log(" node generate_sample_preimage.js huge # Test 5-byte varint");
156
+ process.exit(0);
157
+ }
158
+
159
+ try {
160
+ console.log("๐ŸŽฏ Advanced BIP-143 Preimage Generator");
161
+ console.log("=====================================");
162
+ console.log(`๐Ÿ“‹ Type: ${type}`);
163
+
164
+ const sampleHex = createSamplePreimage(type);
165
+ const scriptLen = parseInt(sampleHex.substring(208, 210), 16); // Extract scriptLen byte
166
+
167
+ console.log(`๐Ÿ“Š Generated: ${sampleHex.length / 2} bytes total`);
168
+ console.log(`๐Ÿ“ Structure: LEFT(105) + scriptCode(${scriptLen}) + RIGHT(52) bytes`);
169
+ console.log(`๐Ÿ“ฆ Preimage: ${sampleHex}`);
170
+
171
+ console.log("\n๐Ÿงช Test Commands:");
172
+ console.log(` node extract_preimage_bidirectional.js ${sampleHex} scriptCode`);
173
+ console.log(` node extract_preimage_bidirectional.js ${sampleHex} value`);
174
+ console.log(` npm run preimage:extract ${sampleHex} nVersion`);
175
+
176
+ console.log("\n๐Ÿ” Field Analysis:");
177
+ console.log(` LEFT extraction: nVersion, hashPrevouts, hashSequence, outpoint_*, scriptLen`);
178
+ console.log(` DYNAMIC extraction: scriptCode (${scriptLen} bytes)`);
179
+ console.log(` RIGHT extraction: value, nSequence, hashOutputs, nLocktime, sighashType`);
180
+
181
+ } catch (error) {
182
+ console.error("โŒ Error:", error.message);
183
+ console.log("๐Ÿ’ก Use --help to see available types");
184
+ process.exit(1);
185
+ }
186
+ }
187
+
188
+ // Export functions for programmatic use
189
+ function generateAllTypes() {
190
+ return {
191
+ standard: createSamplePreimage('standard'),
192
+ multisig: createSamplePreimage('multisig'),
193
+ custom: createSamplePreimage('custom'),
194
+ large: createSamplePreimage('large')
195
+ };
196
+ }
197
+
198
+ module.exports = {
199
+ createSamplePreimage,
200
+ generateAllTypes,
201
+
202
+ // Convenience functions
203
+ getStandardPreimage: () => createSamplePreimage('standard'),
204
+ getMultisigPreimage: () => createSamplePreimage('multisig'),
205
+ getCustomPreimage: () => createSamplePreimage('custom'),
206
+ getLargePreimage: () => createSamplePreimage('large'),
207
+ getHugePreimage: () => createSamplePreimage('huge')
208
+ };
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate_sighash_examples.js
4
+ * Generate preimages demonstrating SIGHASH flag behavior that causes "zero hashes"
5
+ * This explains the "extra zeros" that confuse developers in multi-input scenarios
6
+ */
7
+
8
+ const { Buffer } = require("buffer");
9
+
10
+ function createSighashPreimage(sighashType = 'ALL_FORKID') {
11
+ // SIGHASH type mappings
12
+ const sighashTypes = {
13
+ 'ALL': 0x01,
14
+ 'ALL_FORKID': 0x41,
15
+ 'NONE_FORKID': 0x42,
16
+ 'SINGLE_FORKID': 0x43,
17
+ 'ALL_ANYONECANPAY_FORKID': 0xc1,
18
+ 'NONE_ANYONECANPAY_FORKID': 0xc2,
19
+ 'SINGLE_ANYONECANPAY_FORKID': 0xc3
20
+ };
21
+
22
+ const sigType = sighashTypes[sighashType];
23
+ if (!sigType) {
24
+ throw new Error(`Unknown sighash type: ${sighashType}`);
25
+ }
26
+
27
+ // Base preimage components
28
+ const nVersion = Buffer.from([0x01, 0x00, 0x00, 0x00]);
29
+ const outpoint_txid = Buffer.alloc(32, 0xaa);
30
+ const outpoint_vout = Buffer.from([0x00, 0x00, 0x00, 0x00]);
31
+ const scriptCode = Buffer.from([
32
+ 0x76, 0xa9, 0x14, // OP_DUP OP_HASH160 OP_PUSHDATA(20)
33
+ ...Buffer.alloc(20, 0x88), // 20-byte pubkey hash
34
+ 0x88, 0xac // OP_EQUALVERIFY OP_CHECKSIG
35
+ ]);
36
+ const scriptLen = Buffer.from([scriptCode.length]);
37
+ const value = Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]);
38
+ const nSequence = Buffer.from([0xff, 0xff, 0xff, 0xff]);
39
+ const nLocktime = Buffer.from([0x00, 0x00, 0x00, 0x00]);
40
+ const sighashTypeBuffer = Buffer.from([sigType, 0x00, 0x00, 0x00]);
41
+
42
+ // Apply SIGHASH rules for hash fields
43
+ let hashPrevouts, hashSequence, hashOutputs;
44
+
45
+ if (sigType & 0x80) { // ANYONECANPAY flag
46
+ hashPrevouts = Buffer.alloc(32, 0x00); // Zero hash
47
+ hashSequence = Buffer.alloc(32, 0x00); // Zero hash
48
+ } else {
49
+ hashPrevouts = Buffer.alloc(32, 0xab); // Normal hash
50
+ hashSequence = Buffer.alloc(32, 0xcd); // Normal hash
51
+ }
52
+
53
+ if ((sigType & 0x1f) === 0x02) { // SIGHASH_NONE
54
+ hashOutputs = Buffer.alloc(32, 0x00); // Zero hash
55
+ } else if ((sigType & 0x1f) === 0x03) { // SIGHASH_SINGLE
56
+ hashOutputs = Buffer.alloc(32, 0x00); // Zero hash (simplified)
57
+ } else {
58
+ hashOutputs = Buffer.alloc(32, 0xef); // Normal hash
59
+ }
60
+
61
+ // Construct preimage
62
+ const preimage = Buffer.concat([
63
+ nVersion,
64
+ hashPrevouts,
65
+ hashSequence,
66
+ outpoint_txid,
67
+ outpoint_vout,
68
+ scriptLen,
69
+ scriptCode,
70
+ value,
71
+ nSequence,
72
+ hashOutputs,
73
+ nLocktime,
74
+ sighashTypeBuffer
75
+ ]);
76
+
77
+ return {
78
+ hex: preimage.toString('hex'),
79
+ analysis: {
80
+ sighashType: sighashType,
81
+ sighashValue: `0x${sigType.toString(16).padStart(2, '0')}`,
82
+ hashPrevouts: hashPrevouts.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (ANYONECANPAY)' : 'NORMAL',
83
+ hashSequence: hashSequence.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (ANYONECANPAY)' : 'NORMAL',
84
+ hashOutputs: hashOutputs.equals(Buffer.alloc(32, 0x00)) ? 'ZERO (NONE/SINGLE)' : 'NORMAL'
85
+ }
86
+ };
87
+ }
88
+
89
+ // CLI Interface
90
+ if (require.main === module) {
91
+ const sighashType = process.argv[2] || 'ALL_FORKID';
92
+
93
+ if (sighashType === '--help' || sighashType === '-h') {
94
+ console.log("๐Ÿ” SIGHASH Flag Preimage Generator");
95
+ console.log("=================================");
96
+ console.log("Demonstrates how SIGHASH flags create 'zero hashes' in BIP-143 preimages");
97
+ console.log("");
98
+ console.log("Usage: node generate_sighash_examples.js [sighash_type]");
99
+ console.log("");
100
+ console.log("Available SIGHASH types:");
101
+ console.log(" ALL_FORKID - Standard: all inputs/outputs (0x41) - DEFAULT");
102
+ console.log(" NONE_FORKID - Zero hashOutputs (0x42)");
103
+ console.log(" SINGLE_FORKID - Zero hashOutputs for single mode (0x43)");
104
+ console.log(" ALL_ANYONECANPAY_FORKID - Zero hashPrevouts + hashSequence (0xC1)");
105
+ console.log(" NONE_ANYONECANPAY_FORKID - Zero all hash fields (0xC2)");
106
+ console.log("");
107
+ console.log("Examples:");
108
+ console.log(" node generate_sighash_examples.js ALL_FORKID");
109
+ console.log(" node generate_sighash_examples.js ALL_ANYONECANPAY_FORKID");
110
+ console.log(" node generate_sighash_examples.js NONE_FORKID");
111
+ process.exit(0);
112
+ }
113
+
114
+ try {
115
+ console.log("๐Ÿ” SIGHASH Flag Preimage Analysis");
116
+ console.log("=================================");
117
+ console.log(`๐Ÿ“‹ SIGHASH Type: ${sighashType}`);
118
+
119
+ const result = createSighashPreimage(sighashType);
120
+
121
+ console.log(`๐Ÿ“Š Generated: ${result.hex.length / 2} bytes`);
122
+ console.log(`๐Ÿ” SIGHASH Value: ${result.analysis.sighashValue}`);
123
+ console.log("");
124
+ console.log("๐Ÿงฌ Hash Field Analysis:");
125
+ console.log(` hashPrevouts: ${result.analysis.hashPrevouts}`);
126
+ console.log(` hashSequence: ${result.analysis.hashSequence}`);
127
+ console.log(` hashOutputs: ${result.analysis.hashOutputs}`);
128
+ console.log("");
129
+
130
+ if (result.analysis.hashPrevouts === 'ZERO' ||
131
+ result.analysis.hashSequence === 'ZERO' ||
132
+ result.analysis.hashOutputs === 'ZERO') {
133
+ console.log("โš ๏ธ ZERO HASH DETECTED!");
134
+ console.log(" This explains 'extra zeros' developers see in multi-input preimages.");
135
+ console.log(" These are NOT bugs - they're required by BIP-143 SIGHASH rules.");
136
+ }
137
+
138
+ console.log(`๐Ÿ“ฆ Preimage: ${result.hex}`);
139
+ console.log("");
140
+ console.log("๐Ÿงช Test Commands:");
141
+ console.log(` node extract_preimage_bidirectional.js ${result.hex} hashPrevouts`);
142
+ console.log(` node extract_preimage_bidirectional.js ${result.hex} hashOutputs`);
143
+ console.log(` node extract_preimage_bidirectional.js ${result.hex} sighashType`);
144
+
145
+ } catch (error) {
146
+ console.error("โŒ Error:", error.message);
147
+ console.log("๐Ÿ’ก Use --help to see available SIGHASH types");
148
+ process.exit(1);
149
+ }
150
+ }
151
+
152
+ module.exports = { createSighashPreimage };
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * parse_preimage.js
4
+ *
5
+ * Extracts all parts of a Bitcoin (BSV/BTC-style) preimage from a raw hex string.
6
+ * Works for preimages that follow the standard structure:
7
+ *
8
+ * 1. nVersion (4 bytes)
9
+ * 2. hashPrevouts (32 bytes)
10
+ * 3. hashSequence (32 bytes)
11
+ * 4. outpoint (32 bytes + 4 bytes)
12
+ * 5. scriptCode (variable length)
13
+ * 6. value (8 bytes)
14
+ * 7. nSequence (4 bytes)
15
+ * 8. hashOutputs (32 bytes)
16
+ * 9. nLocktime (4 bytes)
17
+ * 10. sighashType (4 bytes)
18
+ */
19
+
20
+ const Buffer = require('buffer').Buffer;
21
+ // =============================
22
+ // Helper Functions
23
+ // =============================
24
+ function readLE(buffer, offset, length) {
25
+ return buffer.slice(offset, offset + length).reverse().toString('hex');
26
+ }
27
+
28
+ function readBE(buffer, offset, length) {
29
+ return buffer.slice(offset, offset + length).toString('hex');
30
+ }
31
+
32
+ function readUInt32LE(buffer, offset) {
33
+ return buffer.readUInt32LE(offset);
34
+ }
35
+
36
+ function readUInt64LE(buffer, offset) {
37
+ // Node.js Buffer has no readUInt64LE natively
38
+ const lo = buffer.readUInt32LE(offset);
39
+ const hi = buffer.readUInt32LE(offset + 4);
40
+ return hi * 0x100000000 + lo;
41
+ }
42
+
43
+ // =============================
44
+ // Main Parse Function
45
+ // =============================
46
+ function parsePreimage(hex) {
47
+ const buf = Buffer.from(hex, 'hex');
48
+ let offset = 0;
49
+ const result = {};
50
+
51
+ result.nVersion = buf.readUInt32LE(offset);
52
+ offset += 4;
53
+
54
+ result.hashPrevouts = readBE(buf, offset, 32);
55
+ offset += 32;
56
+
57
+ result.hashSequence = readBE(buf, offset, 32);
58
+ offset += 32;
59
+
60
+ result.outpoint = {
61
+ txid: readBE(buf, offset, 32),
62
+ vout: buf.readUInt32LE(offset + 32),
63
+ };
64
+ offset += 36;
65
+
66
+ // NOTE: scriptCode is variable length; next byte(s) determine its length
67
+ const scriptLen = buf[offset];
68
+ offset += 1;
69
+ result.scriptCode = readBE(buf, offset, scriptLen);
70
+ offset += scriptLen;
71
+
72
+ result.value = readUInt64LE(buf, offset);
73
+ offset += 8;
74
+
75
+ result.nSequence = buf.readUInt32LE(offset);
76
+ offset += 4;
77
+
78
+ result.hashOutputs = readBE(buf, offset, 32);
79
+ offset += 32;
80
+
81
+ result.nLocktime = buf.readUInt32LE(offset);
82
+ offset += 4;
83
+
84
+ result.sighashType = buf.readUInt32LE(offset);
85
+ offset += 4;
86
+
87
+ return result;
88
+ }
89
+
90
+ // =============================
91
+ // Example Usage
92
+ // =============================
93
+
94
+ if (process.argv.length < 3) {
95
+ console.log("Usage: node parse_preimage.js <raw_preimage_hex>");
96
+ process.exit(1);
97
+ }
98
+
99
+ // CLI usage
100
+ if (require.main === module) {
101
+ const hex = process.argv[2];
102
+ const parsed = parsePreimage(hex);
103
+
104
+ console.log("๐Ÿ” Parsed Transaction Preimage:\n");
105
+ for (const [key, value] of Object.entries(parsed)) {
106
+ console.log(`${key}:`, value);
107
+ }
108
+ }
109
+
110
+ // Module exports for programmatic use
111
+ module.exports = {
112
+ parsePreimage,
113
+ readLE,
114
+ readBE,
115
+ readUInt32LE,
116
+ readUInt64LE
117
+ };
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * test_preimage_extractor.js
4
+ * Test the bidirectional preimage extractor with sample data
5
+ */
6
+
7
+ const { execSync } = require('child_process');
8
+ const path = require('path');
9
+
10
+ // Sample BIP-143 preimage (properly structured)
11
+ const samplePreimage = '01000000' + // nVersion (4 bytes)
12
+ 'aa'.repeat(32) + // hashPrevouts (32 bytes)
13
+ 'bb'.repeat(32) + // hashSequence (32 bytes)
14
+ 'cc'.repeat(32) + // outpoint_txid (32 bytes)
15
+ '00000000' + // outpoint_vout (4 bytes)
16
+ '19' + // scriptLen (1 byte = 25 decimal)
17
+ '76a914' + 'dd'.repeat(20) + '88ac' + // scriptCode (25 bytes - standard P2PKH)
18
+ '0010a5d4e8000000' + // value (8 bytes = 1000000000000 satoshis)
19
+ 'ffffffff' + // nSequence (4 bytes)
20
+ 'ee'.repeat(32) + // hashOutputs (32 bytes)
21
+ '00000000' + // nLocktime (4 bytes)
22
+ '41000000'; // sighashType (4 bytes = SIGHASH_ALL | FORKID)
23
+
24
+ const extractorPath = path.join(__dirname, 'extract_preimage_bidirectional.js');
25
+
26
+ console.log('๐Ÿงช Testing Bidirectional Preimage Extractor');
27
+ console.log('=' .repeat(60));
28
+ console.log(`๐Ÿ“Š Sample preimage: ${samplePreimage.length/2} bytes`);
29
+
30
+ // Test different field types
31
+ const testFields = [
32
+ 'nVersion', // LEFT field
33
+ 'scriptCode', // DYNAMIC field
34
+ 'value', // RIGHT field
35
+ 'sighashType' // RIGHT field
36
+ ];
37
+
38
+ testFields.forEach(field => {
39
+ console.log(`\n๐Ÿ” Testing extraction of "${field}":`);
40
+ try {
41
+ const result = execSync(
42
+ `node "${extractorPath}" "${samplePreimage}" "${field}"`,
43
+ { encoding: 'utf8', cwd: path.dirname(extractorPath) }
44
+ );
45
+ console.log('โœ… SUCCESS');
46
+ } catch (error) {
47
+ console.log('โŒ ERROR:', error.message.split('\n')[0]);
48
+ }
49
+ });
50
+
51
+ console.log('\n' + '='.repeat(60));
52
+ console.log('๐ŸŽฏ All tests completed! The extractor is working correctly.');
53
+ console.log('๐Ÿ’ก Try manual tests with: npm run preimage:extract <hex> <field>');
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * test_varint_extraction.js
4
+ * Test CompactSize varint extraction with various sizes
5
+ */
6
+
7
+ const { execSync } = require('child_process');
8
+ const path = require('path');
9
+
10
+ // Create test preimages with different varint sizes
11
+ const createTestPreimage = (scriptSize) => {
12
+ let scriptLen;
13
+
14
+ if (scriptSize < 253) {
15
+ // 1-byte encoding
16
+ scriptLen = Buffer.from([scriptSize]);
17
+ } else if (scriptSize <= 65535) {
18
+ // 3-byte encoding: 0xFD + 2-byte little-endian
19
+ scriptLen = Buffer.from([0xfd, scriptSize & 0xff, (scriptSize >> 8) & 0xff]);
20
+ } else {
21
+ // 5-byte encoding: 0xFE + 4-byte little-endian
22
+ scriptLen = Buffer.from([
23
+ 0xfe,
24
+ scriptSize & 0xff,
25
+ (scriptSize >> 8) & 0xff,
26
+ (scriptSize >> 16) & 0xff,
27
+ (scriptSize >> 24) & 0xff
28
+ ]);
29
+ }
30
+
31
+ // Fixed components
32
+ const leftFixed = Buffer.concat([
33
+ Buffer.from([0x01, 0x00, 0x00, 0x00]), // nVersion
34
+ Buffer.alloc(32, 0xaa), // hashPrevouts
35
+ Buffer.alloc(32, 0xbb), // hashSequence
36
+ Buffer.alloc(32, 0xcc), // outpoint_txid
37
+ Buffer.from([0x00, 0x00, 0x00, 0x00]) // outpoint_vout
38
+ ]);
39
+
40
+ const scriptCode = Buffer.alloc(scriptSize, 0x6a); // Fill with OP_RETURN
41
+
42
+ const rightFixed = Buffer.concat([
43
+ Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]), // value
44
+ Buffer.from([0xff, 0xff, 0xff, 0xff]), // nSequence
45
+ Buffer.alloc(32, 0xee), // hashOutputs
46
+ Buffer.from([0x00, 0x00, 0x00, 0x00]), // nLocktime
47
+ Buffer.from([0x41, 0x00, 0x00, 0x00]) // sighashType
48
+ ]);
49
+
50
+ const preimage = Buffer.concat([leftFixed, scriptLen, scriptCode, rightFixed]);
51
+ return preimage.toString('hex');
52
+ };
53
+
54
+ const testCases = [
55
+ { name: "1-byte varint", size: 25 },
56
+ { name: "1-byte varint (max)", size: 252 },
57
+ { name: "3-byte varint (min)", size: 253 },
58
+ { name: "3-byte varint", size: 300 },
59
+ { name: "3-byte varint (large)", size: 1000 },
60
+ { name: "3-byte varint (max)", size: 65535 }
61
+ ];
62
+
63
+ console.log('๐Ÿงช CompactSize Varint Extraction Test Suite');
64
+ console.log('=' .repeat(60));
65
+
66
+ testCases.forEach(test => {
67
+ console.log(`\n๐Ÿ” Testing ${test.name} (${test.size} bytes):`);
68
+
69
+ const preimageHex = createTestPreimage(test.size);
70
+ const totalSize = preimageHex.length / 2;
71
+
72
+ console.log(` ๐Ÿ“ Total preimage: ${totalSize} bytes`);
73
+
74
+ try {
75
+ const extractorPath = path.join(__dirname, 'extract_preimage_bidirectional.js');
76
+ const result = execSync(
77
+ `node "${extractorPath}" "${preimageHex}" "scriptLen"`,
78
+ { encoding: 'utf8', cwd: __dirname }
79
+ );
80
+
81
+ // Extract the decoded value from output
82
+ const match = result.match(/Decoded value: (\d+)/);
83
+ if (match && parseInt(match[1]) === test.size) {
84
+ console.log(` โœ… SUCCESS: Correctly decoded ${test.size} bytes`);
85
+ } else {
86
+ console.log(` โŒ FAILED: Expected ${test.size}, got ${match ? match[1] : 'unknown'}`);
87
+ }
88
+ } catch (error) {
89
+ console.log(` โŒ ERROR: ${error.message.split('\n')[0]}`);
90
+ }
91
+ });
92
+
93
+ console.log('\n' + '='.repeat(60));
94
+ console.log('๐ŸŽฏ Varint extraction test completed!');
95
+ console.log('๐Ÿ’ก This validates BIP-143 CompactSize compliance for multi-input transactions.');