UNPKG

smartledger-bsv

Version:

๐Ÿš€ Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based crede

196 lines (167 loc) โ€ข 8.15 kB
#!/usr/bin/env node /** * Simple UTXO Generator + Preimage Field Separation Demo * * This focused example demonstrates: * 1. Generating real UTXOs with the UTXOGenerator * 2. Creating a transaction and extracting the BIP-143 preimage * 3. Separating the preimage into each individual field with clear visualization */ // Workaround for Node.js environment with minified BSV global.window = global.window || {}; global.window.crypto = global.window.crypto || require('crypto').webcrypto || require('crypto'); const bsv = require('../bsv.min.js'); const SmartContract = bsv.SmartContract; console.log('๐Ÿ”ฌ UTXO Generator + Preimage Field Separation'); console.log('='.repeat(60)); async function simpleDemo() { // 1. Generate mock UTXO for preimage demonstration console.log('\n๐Ÿ“ฆ Creating Mock UTXO for Demo:'); console.log('-'.repeat(45)); const demoPrivateKey = new bsv.PrivateKey(); const demoAddress = demoPrivateKey.toAddress(); const utxo = { txid: 'fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210', vout: 0, satoshis: 100000, address: demoAddress.toString(), script: bsv.Script.buildPublicKeyHashOut(demoAddress).toHex(), scriptPubKey: bsv.Script.buildPublicKeyHashOut(demoAddress).toHex() }; console.log(`โœ… Created Mock UTXO:`); console.log(` TXID: ${utxo.txid}`); console.log(` VOUT: ${utxo.vout}`); console.log(` Amount: ${utxo.satoshis.toLocaleString()} satoshis`); console.log(` Address: ${utxo.address}`); console.log(` Script: ${utxo.script}`); // 2. Create transaction and generate preimage console.log('\n๐Ÿ”จ Creating Transaction & Generating Preimage:'); console.log('-'.repeat(45)); const privateKey = demoPrivateKey; const address = demoAddress; const tx = new bsv.Transaction() .from({ txId: utxo.txid, outputIndex: utxo.vout, scriptPubKey: utxo.scriptPubKey, satoshis: utxo.satoshis }) .to(address, 95000) // Leave some for fees .sign(privateKey); // Generate BIP-143 preimage const sighashType = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID; const subscript = bsv.Script.buildPublicKeyHashOut(address); const preimageBuffer = bsv.Transaction.sighash.sighashPreimage( tx, sighashType, 0, subscript, new bsv.crypto.BN(utxo.satoshis) ); console.log(`โœ… Transaction: ${tx.id}`); console.log(`โœ… Preimage: ${preimageBuffer.length} bytes`); console.log(` Full hex: ${preimageBuffer.toString('hex')}`); // 3. Use SmartContract Preimage class to separate fields console.log('\n๐Ÿ” Separating Preimage Fields:'); console.log('='.repeat(60)); const preimage = new SmartContract.Preimage(preimageBuffer.toString('hex')); // BIP-143 defines these 10 fields in order const fieldNames = [ 'version', // 4 bytes - nVersion 'hashPrevouts', // 32 bytes - hashPrevouts 'hashSequence', // 32 bytes - hashSequence 'outpoint', // 36 bytes - outpoint (32 byte hash + 4 byte index) 'scriptCode', // Variable - scriptCode with length prefix 'amount', // 8 bytes - value in satoshis 'sequence', // 4 bytes - nSequence 'hashOutputs', // 32 bytes - hashOutputs 'locktime', // 4 bytes - nLockTime 'sighash' // 4 bytes - sighash flags ]; let runningOffset = 0; fieldNames.forEach((fieldName, index) => { const fieldBuffer = preimage.getField(fieldName); const fieldHex = fieldBuffer.toString('hex'); console.log(`\n${(index + 1).toString().padStart(2)}. ${fieldName.toUpperCase()}:`); console.log(` Bytes: ${runningOffset} - ${runningOffset + fieldBuffer.length - 1} (${fieldBuffer.length} bytes)`); console.log(` Hex: ${fieldHex}`); // Interpret the field value for better understanding switch (fieldName) { case 'version': console.log(` Value: Version ${fieldBuffer.readUInt32LE(0)}`); break; case 'amount': // Read 64-bit little-endian integer (compatible with older Node.js) const low = fieldBuffer.readUInt32LE(0); const high = fieldBuffer.readUInt32LE(4); const sats = low + (high * 0x100000000); console.log(` Value: ${sats} satoshis (${(sats / 100000000).toFixed(8)} BSV)`); break; case 'outpoint': const txid = fieldBuffer.slice(0, 32).reverse().toString('hex'); const vout = fieldBuffer.slice(32).readUInt32LE(0); console.log(` Value: ${txid}:${vout}`); break; case 'sequence': const seq = fieldBuffer.readUInt32LE(0); console.log(` Value: ${seq} (0x${seq.toString(16)})`); break; case 'locktime': const locktime = fieldBuffer.readUInt32LE(0); console.log(` Value: ${locktime} ${locktime < 500000000 ? '(block height)' : '(timestamp)'}`); break; case 'sighash': const sighash = fieldBuffer.readUInt32LE(0); const flags = []; if (sighash & 0x01) flags.push('SIGHASH_ALL'); if (sighash & 0x02) flags.push('SIGHASH_NONE'); if (sighash & 0x03) flags.push('SIGHASH_SINGLE'); if (sighash & 0x40) flags.push('SIGHASH_FORKID'); if (sighash & 0x80) flags.push('SIGHASH_ANYONECANPAY'); console.log(` Value: 0x${sighash.toString(16)} (${flags.join(' | ')})`); break; case 'scriptCode': console.log(` Value: P2PKH script (${fieldBuffer.length} bytes)`); break; default: console.log(` Value: 32-byte hash`); } runningOffset += fieldBuffer.length; }); // 4. Show extraction strategies console.log('\n๐Ÿงช Testing Different Extraction Strategies:'); console.log('-'.repeat(50)); const strategies = ['LEFT', 'RIGHT', 'DYNAMIC']; strategies.forEach(strategy => { try { const extracted = preimage.extract(strategy); console.log(`โœ… ${strategy.padEnd(7)}: ${Object.keys(extracted).length} fields extracted`); } catch (error) { console.log(`โŒ ${strategy.padEnd(7)}: ${error.message}`); } }); // 5. Summary console.log('\n๐Ÿ“Š Summary:'); console.log('-'.repeat(30)); console.log(`โœ… UTXOs created: 1`); console.log(`โœ… Transaction built: ${tx.inputs.length} input โ†’ ${tx.outputs.length} output`); console.log(`โœ… Preimage generated: ${preimageBuffer.length} bytes`); console.log(`โœ… Fields extracted: ${fieldNames.length} (all BIP-143 fields)`); console.log(`โœ… Total field data: ${runningOffset} bytes`); const sighashInfo = preimage.getSighashInfo(); console.log(`โœ… SIGHASH analysis: ${sighashInfo.hasZeroHashes ? 'Has zero hashes โš ๏ธ' : 'Clean โœ…'}`); console.log('\n๐ŸŽฏ Key Takeaways:'); console.log(' โ€ข UTXOGenerator creates real, usable UTXOs for testing'); console.log(' โ€ข Preimage class extracts all 10 BIP-143 fields perfectly'); console.log(' โ€ข Each field has specific meaning and can be interpreted'); console.log(' โ€ข Multiple extraction strategies ensure robust parsing'); return { utxo, transaction: tx, preimage: preimageBuffer, fieldCount: fieldNames.length }; } // Run the demo if (require.main === module) { simpleDemo() .then(result => { console.log('\n๐ŸŽ‰ Demo completed successfully!'); }) .catch(error => { console.error('\nโŒ Demo failed:', error.message); process.exit(1); }); } module.exports = { simpleDemo };