UNPKG

@node-dlc/messaging

Version:
440 lines (372 loc) 14.5 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ import { expect } from 'chai'; import * as fs from 'fs'; import * as path from 'path'; import { DlcAccept, DlcOffer, DlcSign, MessageType } from '../../lib'; interface DlcSpecsTestData { offer_message?: { message: any; serialized: string; }; accept_message?: { message: any; serialized: string; }; sign_message?: { message: any; serialized: string; }; } interface TestResult { filename: string; messageType: string; success: boolean; error?: string; details?: any; } describe('DLC Ecosystem Compatibility Tests', () => { const dlcSpecsDir = path.join(__dirname, '../../test_vectors/dlcspecs'); const rustDlcDir = path.join(__dirname, '../../test_vectors/rust-dlc'); let dlcSpecsFiles: string[] = []; let rustDlcFiles: string[] = []; before(() => { // Discover all test vector files if (fs.existsSync(dlcSpecsDir)) { dlcSpecsFiles = fs .readdirSync(dlcSpecsDir) .filter((f) => f.endsWith('.json')); } if (fs.existsSync(rustDlcDir)) { rustDlcFiles = fs .readdirSync(rustDlcDir) .filter((f) => f.endsWith('.json')); } }); describe('DLCSpecs Test Vector Compatibility', () => { it('should test all dlcspecs test vectors with version compatibility', () => { const allResults: TestResult[] = []; let oldFormatCount = 0; let newFormatCount = 0; dlcSpecsFiles.forEach((filename) => { const filePath = path.join(dlcSpecsDir, filename); let testData: DlcSpecsTestData; try { testData = JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch (error) { testData = {}; } // Test offer message if present if (testData.offer_message) { const result: TestResult = { filename, messageType: 'offer', success: false, }; try { const inputBuffer = Buffer.from( testData.offer_message.serialized, 'hex', ); const expectedMessage = testData.offer_message.message; // Check format version based on serialization const messageType = inputBuffer.readUInt16BE(0); expect(messageType).to.equal(MessageType.DlcOffer); // Detect old vs new format const nextBytes = inputBuffer.slice(2, 7); const possibleProtocolVersion = nextBytes.readUInt32BE(0); const possibleContractFlags = nextBytes.readUInt8(4); const isNewFormat = possibleProtocolVersion >= 1 && possibleProtocolVersion <= 10 && possibleContractFlags === 0; if (isNewFormat) { newFormatCount++; } else { oldFormatCount++; } const offer = DlcOffer.deserialize(inputBuffer); expect(offer.type).to.equal(MessageType.DlcOffer); if (expectedMessage.protocolVersion) { expect(offer.protocolVersion).to.equal( expectedMessage.protocolVersion, ); } if (expectedMessage.chainHash) { expect(offer.chainHash.toString('hex')).to.equal( expectedMessage.chainHash, ); } if (expectedMessage.temporaryContractId) { expect(offer.temporaryContractId.toString('hex')).to.equal( expectedMessage.temporaryContractId, ); } // Test round-trip serialization const serialized = offer.serialize(); const deserialized = DlcOffer.deserialize(serialized); expect(deserialized.protocolVersion).to.equal( offer.protocolVersion, ); result.success = true; result.details = { protocolVersion: offer.protocolVersion, formatVersion: isNewFormat ? 'new' : 'old', contractInfoType: offer.contractInfo.constructor.name, fundingInputsCount: offer.fundingInputs.length, offerCollateral: Number(offer.offerCollateral), }; } catch (error) { result.error = error.message; } allResults.push(result); } // Test accept message if present if (testData.accept_message) { const result: TestResult = { filename, messageType: 'accept', success: false, }; try { const inputBuffer = Buffer.from( testData.accept_message.serialized, 'hex', ); const expectedMessage = testData.accept_message.message; const accept = DlcAccept.deserialize(inputBuffer); expect(accept.type).to.equal(MessageType.DlcAccept); if (expectedMessage.protocolVersion) { expect(accept.protocolVersion).to.equal( expectedMessage.protocolVersion, ); } if (expectedMessage.temporaryContractId) { expect(accept.temporaryContractId.toString('hex')).to.equal( expectedMessage.temporaryContractId, ); } // Test round-trip const serialized = accept.serialize(); const deserialized = DlcAccept.deserialize(serialized); expect(deserialized.protocolVersion).to.equal( accept.protocolVersion, ); result.success = true; result.details = { protocolVersion: accept.protocolVersion, fundingInputsCount: accept.fundingInputs.length, acceptCollateral: Number(accept.acceptCollateral), hasNegotiationFields: !!accept.negotiationFields, }; } catch (error) { result.error = error.message; } allResults.push(result); } // Test sign message if present if (testData.sign_message) { const result: TestResult = { filename, messageType: 'sign', success: false, }; try { const inputBuffer = Buffer.from( testData.sign_message.serialized, 'hex', ); const expectedMessage = testData.sign_message.message; const sign = DlcSign.deserialize(inputBuffer); expect(sign.type).to.equal(MessageType.DlcSign); if (expectedMessage.protocolVersion) { expect(sign.protocolVersion).to.equal( expectedMessage.protocolVersion, ); } if (expectedMessage.contractId) { expect(sign.contractId.toString('hex')).to.equal( expectedMessage.contractId, ); } // Test round-trip const serialized = sign.serialize(); const deserialized = DlcSign.deserialize(serialized); expect(deserialized.protocolVersion).to.equal(sign.protocolVersion); result.success = true; result.details = { protocolVersion: sign.protocolVersion, cetSignatureCount: sign.cetAdaptorSignatures.sigs.length, hasBatchFunding: !!sign.batchFundingGroups, }; } catch (error) { result.error = error.message; } allResults.push(result); } }); // Generate comprehensive report with version analysis const dlcSpecsSuccessRate = allResults.length > 0 ? allResults.filter((r) => r.success).length / allResults.length : 0; const byMessageType = { offer: allResults.filter((r) => r.messageType === 'offer'), accept: allResults.filter((r) => r.messageType === 'accept'), sign: allResults.filter((r) => r.messageType === 'sign'), }; const failures = allResults.filter((r) => !r.success); const reportLines = [ `DLCSpecs Test Vector Results (With Version Compatibility):`, `Files Processed: ${dlcSpecsFiles.length}`, `Tests Run: ${allResults.length}`, `Success Rate: ${Math.round(dlcSpecsSuccessRate * 100)}% (${ allResults.filter((r) => r.success).length }/${allResults.length})`, '', 'Version Analysis:', ` • Old format (pre-protocol_version): ${oldFormatCount}`, ` • New format (with protocol_version): ${newFormatCount}`, '', 'By Message Type:', ...Object.entries(byMessageType).map(([type, results]) => { const successCount = results.filter((r) => r.success).length; const rate = results.length > 0 ? Math.round((successCount / results.length) * 100) : 0; return ` • ${type}: ${rate}% (${successCount}/${results.length})`; }), ]; if (failures.length > 0) { reportLines.push('', 'Failures:'); failures.forEach((f) => { reportLines.push(` • ${f.filename} (${f.messageType}): ${f.error}`); }); } // Enhanced expectation with version context const expectedMinRate = 0.5; // Expect reasonable compatibility with version detection expect(dlcSpecsSuccessRate).to.be.at.least( expectedMinRate, `DLCSpecs compatibility: ${Math.round( dlcSpecsSuccessRate * 100, )}%. Version Analysis: ${oldFormatCount} old format, ${newFormatCount} new format test vectors. \n\n${reportLines.join( '\n', )}`, ); }); }); describe('Rust-DLC Test Vector Compatibility', () => { it('should test all rust-dlc test vectors comprehensively', () => { const allResults: TestResult[] = []; rustDlcFiles.forEach((filename) => { const filePath = path.join(rustDlcDir, filename); let testData: any; try { testData = JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch (error) { testData = {}; } const result: TestResult = { filename, messageType: 'rust-dlc-validation', success: false, }; try { // Detect message type from filename or structure let messageType = 'unknown'; if (filename.includes('offer')) messageType = 'offer'; else if (filename.includes('accept')) messageType = 'accept'; else if (filename.includes('sign')) messageType = 'sign'; result.messageType = `rust-dlc-${messageType}`; // Universal rust-dlc validations if (testData.protocolVersion !== undefined) { expect(testData.protocolVersion).to.be.a('number'); expect(testData.protocolVersion).to.equal(1); } // Message-specific validations if (messageType === 'offer' || testData.contractInfo) { expect(testData.chainHash).to.be.a('string'); expect(testData.temporaryContractId).to.be.a('string'); expect(testData.contractInfo).to.be.an('object'); expect(testData.fundingPubkey).to.be.a('string'); expect(testData.payoutSpk).to.be.a('string'); if (testData.contractInfo.singleContractInfo) { expect( testData.contractInfo.singleContractInfo.totalCollateral, ).to.be.a('number'); } } if ( messageType === 'accept' || testData.acceptCollateral !== undefined ) { expect(testData.temporaryContractId).to.be.a('string'); expect(testData.acceptCollateral).to.be.a('number'); expect(testData.fundingPubkey).to.be.a('string'); expect(testData.cetAdaptorSignatures).to.be.an('object'); expect( testData.cetAdaptorSignatures.ecdsaAdaptorSignatures, ).to.be.an('array'); } if (messageType === 'sign' || testData.contractId) { expect(testData.contractId).to.be.a('string'); expect(testData.cetAdaptorSignatures).to.be.an('object'); expect(testData.refundSignature).to.be.a('string'); expect(testData.fundingSignatures).to.be.an('object'); } result.success = true; result.details = { detectedType: messageType, protocolVersion: testData.protocolVersion, hasContractInfo: !!testData.contractInfo, hasCetSignatures: !!testData.cetAdaptorSignatures, }; } catch (error) { result.error = error.message; } allResults.push(result); }); // Generate comprehensive report const rustDlcSuccessRate = allResults.length > 0 ? allResults.filter((r) => r.success).length / allResults.length : 0; const failures = allResults.filter((r) => !r.success); const reportLines = [ `Rust-DLC Test Vector Results:`, `Files Processed: ${rustDlcFiles.length}`, `Tests Run: ${allResults.length}`, `Success Rate: ${Math.round(rustDlcSuccessRate * 100)}% (${ allResults.filter((r) => r.success).length }/${allResults.length})`, ]; if (failures.length > 0) { reportLines.push('', 'Failures:'); failures.forEach((f) => { reportLines.push(` • ${f.filename}: ${f.error}`); }); } // We expect high compatibility with rust-dlc expect(rustDlcSuccessRate).to.be.greaterThan( 0.8, `Rust-DLC compatibility too low: ${Math.round( rustDlcSuccessRate * 100, )}%. \n\n${reportLines.join('\n')}`, ); }); }); describe('Overall Ecosystem Compatibility Summary', () => { it('should provide comprehensive ecosystem compatibility metrics with version analysis', () => { expect(dlcSpecsFiles.length).to.be.greaterThan( 0, 'Should have dlcspecs test vectors', ); expect(rustDlcFiles.length).to.be.greaterThan( 0, 'Should have rust-dlc test vectors', ); // Report will be shown in console during test run through assertion messages expect(true).to.be.true; // Always pass, this is just for reporting }); }); });