-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Dlc close messagetype * update test info * stub more fields in tests * add validations and update tests * update comment * remove random comment
- Loading branch information
1 parent
8e3f2e0
commit 4b9d1d0
Showing
3 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
130 changes: 130 additions & 0 deletions
130
packages/messaging/__tests__/messages/DlcCloseV0.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
import { expect } from 'chai'; | ||
|
||
import { DlcClose, DlcCloseV0 } from '../../lib/messages/DlcClose'; | ||
import { FundingInputV0 } from '../../lib/messages/FundingInput'; | ||
import { MessageType } from '../../lib/MessageType'; | ||
|
||
describe('DlcClose', () => { | ||
let instance: DlcCloseV0; | ||
|
||
const type = Buffer.from('cbca', 'hex'); | ||
|
||
const contractId = Buffer.from( | ||
'c1c79e1e9e2fa2840b2514902ea244f39eb3001a4037a52ea43c797d4f841269', | ||
'hex', | ||
); | ||
|
||
const closeSignature = Buffer.from( | ||
'7c8ad6de287b62a1ed1d74ed9116a5158abc7f97376d201caa88e0f9daad68fcda4c271cc003512e768f403a57e5242bd1f6aa1750d7f3597598094a43b1c7bb', | ||
'hex', | ||
); | ||
|
||
const offerPayoutSatoshis = Buffer.from('0000000005f5e100', 'hex'); | ||
const acceptPayoutSatoshis = Buffer.from('0000000005f5e100', 'hex'); | ||
|
||
const fundingInputsLen = Buffer.from('0001', 'hex'); | ||
const fundingInputV0 = Buffer.from( | ||
'fda714' + // type funding_input_v0 | ||
'3f' + // length | ||
'000000000000dae8' + // input_serial_id | ||
'0029' + // prevtx_len | ||
'02000000000100c2eb0b000000001600149ea3bf2d6eb9c2ffa35e36f41e117403ed7fafe900000000' + // prevtx | ||
'00000000' + // prevtx_vout | ||
'ffffffff' + // sequence | ||
'006b' + // max_witness_len | ||
'0000', // redeem_script_len | ||
'hex', | ||
); | ||
|
||
const dlcCloseHex = Buffer.concat([ | ||
type, | ||
contractId, | ||
closeSignature, | ||
offerPayoutSatoshis, | ||
acceptPayoutSatoshis, | ||
fundingInputsLen, | ||
fundingInputV0, | ||
]); | ||
|
||
beforeEach(() => { | ||
instance = new DlcCloseV0(); | ||
instance.contractId = contractId; | ||
instance.closeSignature = closeSignature; | ||
instance.offerPayoutSatoshis = BigInt(100000000); | ||
instance.acceptPayoutSatoshis = BigInt(100000000); | ||
instance.fundingInputs = [FundingInputV0.deserialize(fundingInputV0)]; | ||
}); | ||
|
||
describe('deserialize', () => { | ||
it('should throw if incorrect type', () => { | ||
instance.type = 0x123; | ||
expect(function () { | ||
DlcClose.deserialize(instance.serialize()); | ||
}).to.throw(Error); | ||
}); | ||
|
||
it('has correct type', () => { | ||
expect(DlcClose.deserialize(instance.serialize()).type).to.equal( | ||
instance.type, | ||
); | ||
}); | ||
}); | ||
|
||
describe('DlcCloseV0', () => { | ||
describe('serialize', () => { | ||
it('serializes', () => { | ||
expect(instance.serialize().toString('hex')).to.equal( | ||
dlcCloseHex.toString('hex'), | ||
); | ||
}); | ||
}); | ||
|
||
describe('deserialize', () => { | ||
it('deserializes', () => { | ||
const instance = DlcCloseV0.deserialize(dlcCloseHex); | ||
expect(instance.contractId).to.deep.equal(contractId); | ||
expect(instance.closeSignature).to.deep.equal(closeSignature); | ||
expect(Number(instance.offerPayoutSatoshis)).to.equal(100000000); | ||
expect(Number(instance.acceptPayoutSatoshis)).to.equal(100000000); | ||
expect(instance.fundingInputs[0].serialize().toString('hex')).to.equal( | ||
fundingInputV0.toString('hex'), | ||
); | ||
}); | ||
|
||
it('has correct type', () => { | ||
expect(DlcCloseV0.deserialize(dlcCloseHex).type).to.equal( | ||
MessageType.DlcCloseV0, | ||
); | ||
}); | ||
}); | ||
|
||
describe('toJSON', () => { | ||
it('convert to JSON', async () => { | ||
const json = instance.toJSON(); | ||
expect(json.contractId).to.equal(contractId.toString('hex')); | ||
expect(json.closeSignature).to.equal(closeSignature.toString('hex')); | ||
expect(json.fundingInputs[0].prevTx).to.equal( | ||
instance.fundingInputs[0].prevTx.serialize().toString('hex'), | ||
); | ||
}); | ||
}); | ||
|
||
describe('validate', () => { | ||
it('should throw if inputSerialIds arent unique', () => { | ||
instance.fundingInputs = [ | ||
FundingInputV0.deserialize(fundingInputV0), | ||
FundingInputV0.deserialize(fundingInputV0), | ||
]; | ||
expect(function () { | ||
instance.validate(); | ||
}).to.throw(Error); | ||
}); | ||
it('should ensure funding inputs are segwit', () => { | ||
instance.fundingInputs = [FundingInputV0.deserialize(fundingInputV0)]; | ||
expect(function () { | ||
instance.validate(); | ||
}).to.throw(Error); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { BufferReader, BufferWriter } from '@node-lightning/bufio'; | ||
|
||
import { MessageType } from '../MessageType'; | ||
import { getTlv } from '../serialize/getTlv'; | ||
import { IDlcMessage } from './DlcMessage'; | ||
import { FundingInputV0, IFundingInputV0JSON } from './FundingInput'; | ||
|
||
export abstract class DlcClose { | ||
public static deserialize(buf: Buffer): DlcCloseV0 { | ||
const reader = new BufferReader(buf); | ||
|
||
const type = Number(reader.readUInt16BE()); | ||
|
||
switch (type) { | ||
case MessageType.DlcCloseV0: | ||
return DlcCloseV0.deserialize(buf); | ||
default: | ||
throw new Error(`DLC Close message type must be DlcCloseV0`); // This is a temporary measure while protocol is being developed | ||
} | ||
} | ||
|
||
public abstract type: number; | ||
|
||
public abstract toJSON(): IDlcCloseV0JSON; | ||
|
||
public abstract serialize(): Buffer; | ||
} | ||
|
||
/** | ||
* DlcClose message contains information about a node and indicates its | ||
* desire to close an existing contract. | ||
*/ | ||
export class DlcCloseV0 extends DlcClose implements IDlcMessage { | ||
public static type = MessageType.DlcCloseV0; | ||
|
||
/** | ||
* Deserializes an close_dlc_v0 message | ||
* @param buf | ||
*/ | ||
public static deserialize(buf: Buffer): DlcCloseV0 { | ||
const instance = new DlcCloseV0(); | ||
const reader = new BufferReader(buf); | ||
|
||
reader.readUInt16BE(); // read type | ||
instance.contractId = reader.readBytes(32); | ||
instance.closeSignature = reader.readBytes(64); | ||
instance.offerPayoutSatoshis = reader.readUInt64BE(); | ||
instance.acceptPayoutSatoshis = reader.readUInt64BE(); | ||
const fundingInputsLen = reader.readUInt16BE(); | ||
for (let i = 0; i < fundingInputsLen; i++) { | ||
instance.fundingInputs.push(FundingInputV0.deserialize(getTlv(reader))); | ||
} | ||
|
||
return instance; | ||
} | ||
|
||
/** | ||
* The type for close_dlc_v0 message. close_dlc_v0 = 52170 // TODO | ||
*/ | ||
public type = DlcCloseV0.type; | ||
|
||
public contractId: Buffer; | ||
|
||
public closeSignature: Buffer; | ||
|
||
public offerPayoutSatoshis: bigint; | ||
|
||
public acceptPayoutSatoshis: bigint; | ||
|
||
public fundingInputs: FundingInputV0[] = []; | ||
|
||
/** | ||
* Serializes the close_dlc_v0 message into a Buffer | ||
*/ | ||
public serialize(): Buffer { | ||
const writer = new BufferWriter(); | ||
writer.writeUInt16BE(this.type); | ||
writer.writeBytes(this.contractId); | ||
writer.writeBytes(this.closeSignature); | ||
writer.writeUInt64BE(this.offerPayoutSatoshis); | ||
writer.writeUInt64BE(this.acceptPayoutSatoshis); | ||
writer.writeUInt16BE(this.fundingInputs.length); | ||
|
||
for (const fundingInput of this.fundingInputs) { | ||
writer.writeBytes(fundingInput.serialize()); | ||
} | ||
|
||
return writer.toBuffer(); | ||
} | ||
|
||
/** | ||
* Validates correctness of all fields | ||
* @throws Will throw an error if validation fails | ||
*/ | ||
public validate(): void { | ||
// Type is set automatically in class | ||
|
||
// Ensure input serial ids are unique | ||
const inputSerialIds = this.fundingInputs.map( | ||
(input: FundingInputV0) => input.inputSerialId, | ||
); | ||
|
||
if (new Set(inputSerialIds).size !== inputSerialIds.length) { | ||
throw new Error('inputSerialIds must be unique'); | ||
} | ||
|
||
// Ensure funding inputs are segwit | ||
this.fundingInputs.forEach((input: FundingInputV0) => input.validate()); | ||
} | ||
|
||
/** | ||
* Converts dlc_close_v0 to JSON | ||
*/ | ||
public toJSON(): IDlcCloseV0JSON { | ||
return { | ||
type: this.type, | ||
contractId: this.contractId.toString('hex'), | ||
closeSignature: this.closeSignature.toString('hex'), | ||
offerPayoutSatoshis: Number(this.offerPayoutSatoshis), | ||
acceptPayoutSatoshis: Number(this.acceptPayoutSatoshis), | ||
fundingInputs: this.fundingInputs.map((input) => input.toJSON()), | ||
}; | ||
} | ||
} | ||
|
||
export interface IDlcCloseV0JSON { | ||
type: number; | ||
contractId: string; | ||
closeSignature: string; | ||
offerPayoutSatoshis: number; | ||
acceptPayoutSatoshis: number; | ||
fundingInputs: IFundingInputV0JSON[]; | ||
} |