UNPKG

@node-dlc/messaging

Version:
333 lines (287 loc) 12.4 kB
import { expect } from 'chai'; import * as fs from 'fs'; import * as path from 'path'; import { OracleAnnouncement } from '../../lib/messages/OracleAnnouncement'; import { OracleAttestation } from '../../lib/messages/OracleAttestation'; // Load test vectors const testVectorsPath = path.join( __dirname, '../../test_vectors/oracle/oracle_message_test_vectors.json', ); const testVectors = JSON.parse(fs.readFileSync(testVectorsPath, 'utf8')); describe('OracleAttestation', () => { const attestationSig = Buffer.from( '424c11a44c2e522f90bbe4abab6ec1bc8ab44c9b29316ce6e1d0d7d08385a474' + 'de6b75f1da183a2a4f9ad144b48bf1026cee9687221df58f04128db79ca17e2a', 'hex', ); const oraclePubkey = Buffer.from( '1d5dcdba2e64cb116cc0c375a0856298f0058b778f46bfe625ac6576204889e4', 'hex', ); const invalidOraclePubkey = Buffer.from( '5d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9', 'hex', ); describe('serialize', () => { it('serializes', () => { const instance = new OracleAttestation(); instance.eventId = 'BTC-USD-OVER-50K-COINBASE'; instance.oraclePublicKey = oraclePubkey; instance.signatures.push(attestationSig); instance.outcomes.push('NO'); // Test that it serializes without errors (new dlcspecs PR #163 format) const serialized = instance.serialize(); expect(serialized).to.be.instanceof(Buffer); expect(serialized.length).to.be.greaterThan(0); }); }); describe('deserialize', () => { it('deserializes', () => { // Create a test instance and serialize it first for round-trip testing const originalInstance = new OracleAttestation(); originalInstance.eventId = 'BTC-USD-OVER-50K-COINBASE'; originalInstance.oraclePublicKey = oraclePubkey; originalInstance.signatures.push(attestationSig); originalInstance.outcomes.push('NO'); // Serialize and then deserialize to ensure round-trip consistency const serialized = originalInstance.serialize(); const instance = OracleAttestation.deserialize(serialized); expect(Number(instance.length)).to.be.greaterThan(0); // Length is calculated automatically expect(instance.eventId).to.equal('BTC-USD-OVER-50K-COINBASE'); expect(instance.oraclePublicKey).to.deep.equal(oraclePubkey); expect(instance.signatures[0]).to.deep.equal(attestationSig); expect(instance.outcomes[0]).to.equal('NO'); }); }); describe('validate', () => { it('should validate when correct outcome signatures', () => { const instance = new OracleAttestation(); instance.eventId = 'BTC-USD-OVER-50K-COINBASE'; instance.oraclePublicKey = oraclePubkey; instance.signatures.push(attestationSig); instance.outcomes.push('NO'); expect(function () { instance.validate(); }).to.not.throw(Error); }); it('should invalidate when incorrect outcome signatures', () => { const instance = new OracleAttestation(); instance.eventId = 'BTC-USD-OVER-50K-COINBASE'; instance.oraclePublicKey = invalidOraclePubkey; instance.signatures.push(attestationSig); instance.outcomes.push('NO'); expect(function () { instance.validate(); }).to.throw(Error); }); }); /** * Comprehensive Test Vectors * Tests oracle attestations from various implementations and oracle providers */ describe('comprehensive attestation test vectors', () => { describe('Atomic Finance attestation', () => { let announcement: OracleAnnouncement; let instance: OracleAttestation; before(() => { const announcementBuf = Buffer.from( testVectors.atomic.announcement, 'hex', ); announcement = OracleAnnouncement.deserialize(announcementBuf); const attestationBuf = Buffer.from( testVectors.atomic.attestation, 'hex', ); instance = OracleAttestation.deserialize(attestationBuf); }); it('deserializes Atomic oracle attestation', () => { expect(Number(instance.length)).to.be.greaterThan(0); expect(instance.eventId).to.equal(testVectors.atomic.metadata.eventId); expect(instance.oraclePublicKey).to.be.instanceOf(Buffer); expect(instance.oraclePublicKey.length).to.equal(32); expect(instance.signatures).to.be.an('array'); expect(instance.outcomes).to.be.an('array'); expect(instance.signatures.length).to.equal(instance.outcomes.length); }); it('validates Atomic oracle attestation', () => { expect(() => instance.validate()).to.not.throw(); }); it('validates against corresponding announcement', () => { expect(() => instance.validate(announcement)).to.not.throw(); }); it('has correct number of signatures for digit decomposition', () => { expect(instance.signatures).to.have.length(18); // 18-digit binary decomposition expect(instance.outcomes).to.have.length(18); }); it('has binary outcomes (0 or 1)', () => { instance.outcomes.forEach((outcome) => { expect(['0', '1']).to.include(outcome); }); }); it('round-trip serialization works', () => { const serialized = instance.serialize(); const deserialized = OracleAttestation.deserialize(serialized); expect(deserialized.eventId).to.equal(instance.eventId); expect(deserialized.oraclePublicKey).to.deep.equal( instance.oraclePublicKey, ); expect(deserialized.outcomes).to.deep.equal(instance.outcomes); }); }); describe('Lava attestation', () => { let instance: OracleAttestation; before(() => { const announcementBuf = Buffer.from( testVectors.lava.announcement, 'hex', ); OracleAnnouncement.deserialize(announcementBuf); // ensure announcement deserializes const attestationBuf = Buffer.from(testVectors.lava.attestation, 'hex'); instance = OracleAttestation.deserialize(attestationBuf); }); it('deserializes Lava oracle attestation', () => { expect(Number(instance.length)).to.be.greaterThan(0); expect(instance.eventId).to.be.a('string'); expect(instance.oraclePublicKey).to.be.instanceOf(Buffer); expect(instance.oraclePublicKey.length).to.equal(32); expect(instance.signatures).to.be.an('array'); expect(instance.outcomes).to.be.an('array'); expect(instance.signatures.length).to.equal(instance.outcomes.length); }); it('has correct number of signatures for digit decomposition', () => { expect(instance.signatures).to.have.length(18); // 18-digit binary decomposition expect(instance.outcomes).to.have.length(18); }); it('has binary outcomes (0 or 1)', () => { instance.outcomes.forEach((outcome) => { expect(['0', '1']).to.include(outcome); }); }); it('round-trip serialization works', () => { const serialized = instance.serialize(); const deserialized = OracleAttestation.deserialize(serialized); expect(deserialized.eventId).to.equal(instance.eventId); expect(deserialized.oraclePublicKey).to.deep.equal( instance.oraclePublicKey, ); expect(deserialized.outcomes).to.deep.equal(instance.outcomes); }); }); describe('rust-dlc enum oracle', () => { let instance: OracleAttestation; before(() => { const announcementBuf = Buffer.from( testVectors.rust_dlc_enum.announcement, 'hex', ); OracleAnnouncement.deserialize(announcementBuf); // ensure announcement deserializes const attestationBuf = Buffer.from( testVectors.rust_dlc_enum.attestation, 'hex', ); instance = OracleAttestation.deserialize(attestationBuf); }); it('deserializes rust-dlc enum oracle attestation', () => { expect(Number(instance.length)).to.be.greaterThan(0); expect(instance.eventId).to.equal('sports-match-001'); expect(instance.oraclePublicKey).to.be.instanceOf(Buffer); expect(instance.oraclePublicKey.length).to.equal(32); expect(instance.signatures).to.be.an('array'); expect(instance.outcomes).to.be.an('array'); expect(instance.signatures.length).to.equal(instance.outcomes.length); }); it('has single signature for enum event', () => { expect(instance.signatures).to.have.length(1); expect(instance.outcomes).to.have.length(1); }); it('has valid enum outcome', () => { expect(instance.outcomes[0]).to.equal('win'); expect(['win', 'lose', 'draw']).to.include(instance.outcomes[0]); }); it('round-trip serialization works', () => { const serialized = instance.serialize(); const deserialized = OracleAttestation.deserialize(serialized); expect(deserialized.eventId).to.equal(instance.eventId); expect(deserialized.oraclePublicKey).to.deep.equal( instance.oraclePublicKey, ); expect(deserialized.outcomes).to.deep.equal(instance.outcomes); }); }); describe('rust-dlc numeric oracle', () => { let instance: OracleAttestation; before(() => { const attestationBuf = Buffer.from( testVectors.rust_dlc_numeric.attestation, 'hex', ); instance = OracleAttestation.deserialize(attestationBuf); }); it('deserializes rust-dlc numeric oracle attestation', () => { expect(Number(instance.length)).to.be.greaterThan(0); expect(instance.eventId).to.equal('btc-price-test'); expect(instance.oraclePublicKey).to.be.instanceOf(Buffer); expect(instance.oraclePublicKey.length).to.equal(32); expect(instance.signatures).to.be.an('array'); expect(instance.outcomes).to.be.an('array'); expect(instance.signatures.length).to.equal(instance.outcomes.length); }); it('has correct number of signatures for 8-digit decomposition', () => { expect(instance.signatures).to.have.length(8); // 8-digit binary decomposition expect(instance.outcomes).to.have.length(8); }); it('has binary outcomes (0 or 1)', () => { instance.outcomes.forEach((outcome) => { expect(['0', '1']).to.include(outcome); }); }); it('represents number 42 in binary (00101010)', () => { // Outcomes are in little-endian order (LSB first) const expectedBinary = ['0', '1', '0', '1', '0', '1', '0', '0']; expect(instance.outcomes).to.deep.equal(expectedBinary); }); it('round-trip serialization works', () => { const serialized = instance.serialize(); const deserialized = OracleAttestation.deserialize(serialized); expect(deserialized.eventId).to.equal(instance.eventId); expect(deserialized.oraclePublicKey).to.deep.equal( instance.oraclePublicKey, ); expect(deserialized.outcomes).to.deep.equal(instance.outcomes); }); }); describe('cross-validation tests', () => { it('attestations have consistent event IDs with announcements', () => { const testCases = [ { announcement: testVectors.atomic.announcement, attestation: testVectors.atomic.attestation, }, { announcement: testVectors.lava.announcement, attestation: testVectors.lava.attestation, }, { announcement: testVectors.rust_dlc_enum.announcement, attestation: testVectors.rust_dlc_enum.attestation, }, { announcement: testVectors.rust_dlc_numeric.announcement, attestation: testVectors.rust_dlc_numeric.attestation, }, ]; testCases.forEach((testCase) => { const announcement = OracleAnnouncement.deserialize( Buffer.from(testCase.announcement, 'hex'), ); const attestation = OracleAttestation.deserialize( Buffer.from(testCase.attestation, 'hex'), ); expect(attestation.eventId).to.equal(announcement.getEventId()); }); }); }); }); });