UNPKG

@btc-vision/transaction

Version:

OPNet transaction library allows you to create and sign transactions for the OPNet network.

458 lines (358 loc) 18.2 kB
import { describe, expect, it } from 'vitest'; import { Address, BinaryReader, BinaryWriter, ExtendedAddressMap } from '../src/opnet.js'; describe('BinaryReader/BinaryWriter', () => { // Helper to create an Address with both MLDSA and tweaked keys const createFullAddress = (mldsaValue: bigint, tweakedValue: bigint): Address => { return Address.fromBigInt(mldsaValue, tweakedValue); }; describe('Signed Integer Methods', () => { describe('i8', () => { it('should write and read positive i8', () => { const writer = new BinaryWriter(); writer.writeI8(127); writer.writeI8(0); writer.writeI8(1); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI8()).toBe(127); expect(reader.readI8()).toBe(0); expect(reader.readI8()).toBe(1); }); it('should write and read negative i8', () => { const writer = new BinaryWriter(); writer.writeI8(-128); writer.writeI8(-1); writer.writeI8(-50); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI8()).toBe(-128); expect(reader.readI8()).toBe(-1); expect(reader.readI8()).toBe(-50); }); it('should throw on out of range i8', () => { const writer = new BinaryWriter(); expect(() => writer.writeI8(128)).toThrow(); expect(() => writer.writeI8(-129)).toThrow(); }); }); describe('i16', () => { it('should write and read positive i16 big-endian', () => { const writer = new BinaryWriter(); writer.writeI16(32767); writer.writeI16(256); writer.writeI16(0); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI16()).toBe(32767); expect(reader.readI16()).toBe(256); expect(reader.readI16()).toBe(0); }); it('should write and read negative i16 big-endian', () => { const writer = new BinaryWriter(); writer.writeI16(-32768); writer.writeI16(-1); writer.writeI16(-256); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI16()).toBe(-32768); expect(reader.readI16()).toBe(-1); expect(reader.readI16()).toBe(-256); }); it('should write and read i16 little-endian', () => { const writer = new BinaryWriter(); writer.writeI16(12345, false); writer.writeI16(-12345, false); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI16(false)).toBe(12345); expect(reader.readI16(false)).toBe(-12345); }); it('should throw on out of range i16', () => { const writer = new BinaryWriter(); expect(() => writer.writeI16(32768)).toThrow(); expect(() => writer.writeI16(-32769)).toThrow(); }); }); describe('i32', () => { it('should write and read positive i32 big-endian', () => { const writer = new BinaryWriter(); writer.writeI32(2147483647); writer.writeI32(65536); writer.writeI32(0); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI32()).toBe(2147483647); expect(reader.readI32()).toBe(65536); expect(reader.readI32()).toBe(0); }); it('should write and read negative i32 big-endian', () => { const writer = new BinaryWriter(); writer.writeI32(-2147483648); writer.writeI32(-1); writer.writeI32(-65536); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI32()).toBe(-2147483648); expect(reader.readI32()).toBe(-1); expect(reader.readI32()).toBe(-65536); }); it('should write and read i32 little-endian', () => { const writer = new BinaryWriter(); writer.writeI32(123456789, false); writer.writeI32(-123456789, false); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI32(false)).toBe(123456789); expect(reader.readI32(false)).toBe(-123456789); }); it('should throw on out of range i32', () => { const writer = new BinaryWriter(); expect(() => writer.writeI32(2147483648)).toThrow(); expect(() => writer.writeI32(-2147483649)).toThrow(); }); }); describe('i64', () => { it('should write and read positive i64 big-endian', () => { const writer = new BinaryWriter(); writer.writeI64(9223372036854775807n); writer.writeI64(4294967296n); writer.writeI64(0n); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI64()).toBe(9223372036854775807n); expect(reader.readI64()).toBe(4294967296n); expect(reader.readI64()).toBe(0n); }); it('should write and read negative i64 big-endian', () => { const writer = new BinaryWriter(); writer.writeI64(-9223372036854775808n); writer.writeI64(-1n); writer.writeI64(-4294967296n); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI64()).toBe(-9223372036854775808n); expect(reader.readI64()).toBe(-1n); expect(reader.readI64()).toBe(-4294967296n); }); it('should write and read i64 little-endian', () => { const writer = new BinaryWriter(); writer.writeI64(1234567890123456789n, false); writer.writeI64(-1234567890123456789n, false); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI64(false)).toBe(1234567890123456789n); expect(reader.readI64(false)).toBe(-1234567890123456789n); }); it('should throw on out of range i64', () => { const writer = new BinaryWriter(); expect(() => writer.writeI64(9223372036854775808n)).toThrow(); expect(() => writer.writeI64(-9223372036854775809n)).toThrow(); }); }); }); describe('Extended Address Methods', () => { describe('readExtendedAddress / writeExtendedAddress', () => { it('should write and read extended address', () => { const writer = new BinaryWriter(); const address = createFullAddress(123n, 456n); writer.writeExtendedAddress(address); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddress(); expect(result.toBigInt()).toBe(123n); expect(result.tweakedToBigInt()).toBe(456n); }); it('should write and read multiple extended addresses', () => { const writer = new BinaryWriter(); const addr1 = createFullAddress(100n, 200n); const addr2 = createFullAddress(300n, 400n); const addr3 = createFullAddress(500n, 600n); writer.writeExtendedAddress(addr1); writer.writeExtendedAddress(addr2); writer.writeExtendedAddress(addr3); const reader = new BinaryReader(writer.getBuffer()); const result1 = reader.readExtendedAddress(); expect(result1.toBigInt()).toBe(100n); expect(result1.tweakedToBigInt()).toBe(200n); const result2 = reader.readExtendedAddress(); expect(result2.toBigInt()).toBe(300n); expect(result2.tweakedToBigInt()).toBe(400n); const result3 = reader.readExtendedAddress(); expect(result3.toBigInt()).toBe(500n); expect(result3.tweakedToBigInt()).toBe(600n); }); it('should handle zero addresses', () => { const writer = new BinaryWriter(); const address = createFullAddress(0n, 0n); writer.writeExtendedAddress(address); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddress(); expect(result.toBigInt()).toBe(0n); expect(result.tweakedToBigInt()).toBe(0n); }); it('should handle max value addresses', () => { const writer = new BinaryWriter(); const maxValue = 2n ** 256n - 1n; const address = createFullAddress(maxValue, maxValue); writer.writeExtendedAddress(address); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddress(); expect(result.toBigInt()).toBe(maxValue); expect(result.tweakedToBigInt()).toBe(maxValue); }); }); describe('readExtendedAddressArray / writeExtendedAddressArray', () => { it('should write and read empty array', () => { const writer = new BinaryWriter(); writer.writeExtendedAddressArray([]); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressArray(); expect(result).toEqual([]); }); it('should write and read array of extended addresses', () => { const writer = new BinaryWriter(); const addresses = [ createFullAddress(1n, 2n), createFullAddress(3n, 4n), createFullAddress(5n, 6n), ]; writer.writeExtendedAddressArray(addresses); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressArray(); expect(result.length).toBe(3); expect((result[0] as Address).toBigInt()).toBe(1n); expect((result[0] as Address).tweakedToBigInt()).toBe(2n); expect((result[1] as Address).toBigInt()).toBe(3n); expect((result[1] as Address).tweakedToBigInt()).toBe(4n); expect((result[2] as Address).toBigInt()).toBe(5n); expect((result[2] as Address).tweakedToBigInt()).toBe(6n); }); it('should handle large arrays', () => { const writer = new BinaryWriter(); const addresses: Address[] = []; for (let i = 0; i < 100; i++) { addresses.push(createFullAddress(BigInt(i), BigInt(i * 2))); } writer.writeExtendedAddressArray(addresses); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressArray(); expect(result.length).toBe(100); for (let i = 0; i < 100; i++) { expect((result[i] as Address).toBigInt()).toBe(BigInt(i)); expect((result[i] as Address).tweakedToBigInt()).toBe(BigInt(i * 2)); } }); }); }); describe('ExtendedAddressMapU256 Methods', () => { describe('readExtendedAddressMapU256 / writeExtendedAddressMapU256', () => { it('should write and read empty map', () => { const writer = new BinaryWriter(); const map = new ExtendedAddressMap<bigint>(); writer.writeExtendedAddressMapU256(map); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressMapU256(); expect(result.size).toBe(0); }); it('should write and read map with entries', () => { const writer = new BinaryWriter(); const map = new ExtendedAddressMap<bigint>(); const addr1 = createFullAddress(100n, 200n); const addr2 = createFullAddress(300n, 400n); map.set(addr1, 1000n); map.set(addr2, 2000n); writer.writeExtendedAddressMapU256(map); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressMapU256(); expect(result.size).toBe(2); }); it('should handle large u256 values', () => { const writer = new BinaryWriter(); const map = new ExtendedAddressMap<bigint>(); const addr = createFullAddress(1n, 2n); const largeValue = 2n ** 256n - 1n; map.set(addr, largeValue); writer.writeExtendedAddressMapU256(map); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readExtendedAddressMapU256(); expect(result.size).toBe(1); }); }); }); describe('Schnorr Signature Methods', () => { describe('readSchnorrSignature / writeSchnorrSignature', () => { it('should write and read Schnorr signature', () => { const writer = new BinaryWriter(); const address = createFullAddress(12345n, 67890n); const signature = new Uint8Array(64); for (let i = 0; i < 64; i++) { signature[i] = i; } writer.writeSchnorrSignature(address, signature); const reader = new BinaryReader(writer.getBuffer()); const result = reader.readSchnorrSignature(); expect(result.address.toBigInt()).toBe(12345n); expect(result.address.tweakedToBigInt()).toBe(67890n); expect(result.signature.length).toBe(64); for (let i = 0; i < 64; i++) { expect(result.signature[i]).toBe(i); } }); it('should throw on invalid signature length', () => { const writer = new BinaryWriter(); const address = createFullAddress(1n, 2n); const invalidSignature = new Uint8Array(32); // Should be 64 expect(() => writer.writeSchnorrSignature(address, invalidSignature)).toThrow(); }); it('should handle multiple signatures', () => { const writer = new BinaryWriter(); const sig1 = new Uint8Array(64).fill(1); const sig2 = new Uint8Array(64).fill(2); writer.writeSchnorrSignature(createFullAddress(1n, 2n), sig1); writer.writeSchnorrSignature(createFullAddress(3n, 4n), sig2); const reader = new BinaryReader(writer.getBuffer()); const result1 = reader.readSchnorrSignature(); expect(result1.address.toBigInt()).toBe(1n); expect(result1.signature[0]).toBe(1); const result2 = reader.readSchnorrSignature(); expect(result2.address.toBigInt()).toBe(3n); expect(result2.signature[0]).toBe(2); }); }); }); describe('Mixed Operations', () => { it('should handle mixed data types in sequence', () => { const writer = new BinaryWriter(); // Write various types writer.writeI8(-50); writer.writeI16(-1000); writer.writeI32(-100000); writer.writeI64(-10000000000n); writer.writeExtendedAddress(createFullAddress(111n, 222n)); writer.writeU256(999n); const reader = new BinaryReader(writer.getBuffer()); expect(reader.readI8()).toBe(-50); expect(reader.readI16()).toBe(-1000); expect(reader.readI32()).toBe(-100000); expect(reader.readI64()).toBe(-10000000000n); const addr = reader.readExtendedAddress(); expect(addr.toBigInt()).toBe(111n); expect(addr.tweakedToBigInt()).toBe(222n); expect(reader.readU256()).toBe(999n); }); it('should correctly track buffer position', () => { const writer = new BinaryWriter(); writer.writeI8(1); writer.writeI16(2); writer.writeI32(3); writer.writeI64(4n); writer.writeExtendedAddress(createFullAddress(5n, 6n)); const buffer = writer.getBuffer(); // i8: 1 byte, i16: 2 bytes, i32: 4 bytes, i64: 8 bytes, extended address: 64 bytes expect(buffer.length).toBe(1 + 2 + 4 + 8 + 64); }); }); describe('Error Handling', () => { it('should throw when reading beyond buffer', () => { const writer = new BinaryWriter(); writer.writeI8(1); const reader = new BinaryReader(writer.getBuffer()); reader.readI8(); expect(() => reader.readI8()).toThrow(); }); it('should throw when reading extended address from insufficient buffer', () => { const writer = new BinaryWriter(); writer.writeU256(1n); // Only 32 bytes const reader = new BinaryReader(writer.getBuffer()); expect(() => reader.readExtendedAddress()).toThrow(); }); }); });