diff --git a/index.js b/index.js index f6defd8..538833f 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,19 @@ const MIME_APPLICATION_OCTET_STREAM = 0 const MIME_TEXT_PLAIN_UTF8 = 1 const MIME_APPLICATION_JSON = 2 +function typeToString (type) { + switch (type) { + case TYPE_ACK: return 'TYPE_ACK' + case TYPE_RESPONSE: return 'TYPE_RESPONSE' + case TYPE_ERROR: return 'TYPE_ERROR' + case TYPE_PREPARE: return 'TYPE_PREPARE' + case TYPE_FULFILL: return 'TYPE_FULFILL' + case TYPE_REJECT: return 'TYPE_REJECT' + case TYPE_MESSAGE: return 'TYPE_MESSAGE' + default: throw new Error('Unrecognized clp packet type') + } +} + const HIGH_WORD_MULTIPLIER = 0x100000000 const GENERALIZED_TIME_REGEX = /^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}\.[0-9]{3}Z)$/ @@ -73,7 +86,7 @@ function readGeneralizedTime (reader) { return new Date(date) } -function maybeSerializeIlpError(error) { +function maybeSerializeIlpError (error) { if (Buffer.isBuffer(error)) { return error } @@ -94,29 +107,6 @@ function readIlpError (reader) { return deserializeIlpError(Buffer.concat([ type, length, contents ])) } -function writeEnvelope (type, requestId, contents) { - const writer = new Writer() - writer.writeUInt8(type) - writer.writeUInt32(requestId) - writer.writeVarOctetString(contents) - - return writer.getBuffer() -} - -function readEnvelope (envelope) { - const reader = Reader.from(envelope) - - const type = reader.readUInt8() - const requestId = reader.readUInt32() - const data = reader.readVarOctetString() - - return { - type, - requestId, - data - } -} - function writeProtocolData (writer, protocolData) { if (!Array.isArray(protocolData)) { throw new Error('protocolData must be an array') @@ -155,179 +145,142 @@ function readProtocolData (reader) { return protocolData } -function serializeAck (requestId, protocolData) { - const writer = new Writer() - writeProtocolData(writer, protocolData) +function writeError (writer, data) { + const ilpPacket = maybeSerializeIlpError(data.rejectionReason) + writer.write(ilpPacket) + writeProtocolData(writer, data.protocolData) +} - return writeEnvelope(TYPE_ACK, requestId, writer.getBuffer()) +function writePrepare (writer, data) { + const transferIdBuffer = Buffer.from(data.transferId.replace(/-/g, ''), 'hex') + const amountAsPair = stringToTwoNumbers(data.amount) + const executionConditionBuffer = Buffer.from(data.executionCondition, 'base64') + const expiresAtBuffer = toGeneralizedTimeBuffer(data.expiresAt) + writer.write(transferIdBuffer) + writer.writeUInt64(amountAsPair) + writer.write(executionConditionBuffer) + writer.writeVarOctetString(expiresAtBuffer) + writeProtocolData(writer, data.protocolData) } -function deserializeAck (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) +function writeFulfill (writer, data) { + const transferIdBuffer = Buffer.from(data.transferId.replace(/-/g, ''), 'hex') + const fulfillmentBuffer = Buffer.from(data.fulfillment, 'base64') + writer.write(transferIdBuffer) + writer.write(fulfillmentBuffer) + writeProtocolData(writer, data.protocolData) +} - const protocolData = readProtocolData(reader) - return { requestId, protocolData } +function writeReject (writer, data) { + const transferIdBuffer = Buffer.from(data.transferId.replace(/-/g, ''), 'hex') + const rejectionReasonBuffer = maybeSerializeIlpError(data.rejectionReason) + writer.write(transferIdBuffer) + writer.write(rejectionReasonBuffer) + writeProtocolData(writer, data.protocolData) } -function serializeResponse (requestId, protocolData) { +function serialize (obj) { const writer = new Writer() - writeProtocolData(writer, protocolData) + switch (obj.type) { + case TYPE_ACK: + case TYPE_RESPONSE: + case TYPE_MESSAGE: + writeProtocolData(writer, obj.data) // see https://github.com/interledger/rfcs/issues/284 + break - return writeEnvelope(TYPE_RESPONSE, requestId, writer.getBuffer()) -} + case TYPE_ERROR: + writeError(writer, obj.data) + break -function deserializeResponse (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) + case TYPE_PREPARE: + writePrepare(writer, obj.data) + break - const protocolData = readProtocolData(reader) - return { requestId, protocolData } -} + case TYPE_FULFILL: + writeFulfill(writer, obj.data) + break -function serializeError ({ rejectionReason }, requestId, protocolData) { - const writer = new Writer() - const ilpPacket = maybeSerializeIlpError(rejectionReason) - writer.write(ilpPacket) - writeProtocolData(writer, protocolData) + case TYPE_REJECT: + writeReject(writer, obj.data) + break - return writeEnvelope(TYPE_ERROR, requestId, writer.getBuffer()) + default: + throw new Error('Unrecognized type') + } + + const envelopeWriter = new Writer() + envelopeWriter.writeUInt8(obj.type) + envelopeWriter.writeUInt32(obj.requestId) + envelopeWriter.writeVarOctetString(writer.getBuffer()) + return envelopeWriter.getBuffer() } -function deserializeError (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) +function readError (reader) { const rejectionReason = readIlpError(reader) const protocolData = readProtocolData(reader) - return { requestId, rejectionReason, protocolData } + return { rejectionReason, protocolData } } -function serializePrepare ({ transferId, amount, executionCondition, expiresAt }, requestId, protocolData) { - const transferIdBuffer = Buffer.from(transferId.replace(/-/g, ''), 'hex') - const amountAsPair = stringToTwoNumbers(amount) - const executionConditionBuffer = Buffer.from(executionCondition, 'base64') - const expiresAtBuffer = toGeneralizedTimeBuffer(expiresAt) - const writer = new Writer() - - writer.write(transferIdBuffer) - writer.writeUInt64(amountAsPair) - writer.write(executionConditionBuffer) - writer.writeVarOctetString(expiresAtBuffer) - writeProtocolData(writer, protocolData) - - return writeEnvelope(TYPE_PREPARE, requestId, writer.getBuffer()) -} - -function deserializePrepare (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) - +function readPrepare (reader) { const transferId = uuidParse.unparse(reader.read(16)) - const amount =twoNumbersToString(reader.readUInt64()) + const amount = twoNumbersToString(reader.readUInt64()) const executionCondition = base64url(reader.read(32)) const expiresAt = readGeneralizedTime(reader) const protocolData = readProtocolData(reader) - - return { requestId, transferId, amount, executionCondition, expiresAt, protocolData } -} - -function serializeFulfill ({ transferId, fulfillment }, requestId, protocolData) { - const transferIdBuffer = Buffer.from(transferId.replace(/-/g, ''), 'hex') - const fulfillmentBuffer = Buffer.from(fulfillment, 'base64') - const writer = new Writer() - - writer.write(transferIdBuffer) - writer.write(fulfillmentBuffer) - writeProtocolData(writer, protocolData) - - return writeEnvelope(TYPE_FULFILL, requestId, writer.getBuffer()) + return { transferId, amount, executionCondition, expiresAt, protocolData } } -function deserializeFulfill (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) - +function readFulfill (reader) { const transferId = uuidParse.unparse(reader.read(16)) const fulfillment = base64url(reader.read(32)) const protocolData = readProtocolData(reader) - - return { requestId, transferId, fulfillment, protocolData } -} - -function serializeReject ({ transferId, rejectionReason }, requestId, protocolData) { - const transferIdBuffer = Buffer.from(transferId.replace(/-/g, ''), 'hex') - const rejectionReasonBuffer = maybeSerializeIlpError(rejectionReason) - - const writer = new Writer() - writer.write(transferIdBuffer) - writer.write(rejectionReasonBuffer) - writeProtocolData(writer, protocolData) - - return writeEnvelope(TYPE_REJECT, requestId, writer.getBuffer()) + return { transferId, fulfillment, protocolData } } -function deserializeReject (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) - +function readReject (reader) { const transferId = uuidParse.unparse(reader.read(16)) const rejectionReason = readIlpError(reader) const protocolData = readProtocolData(reader) - - return { requestId, transferId, rejectionReason, protocolData } + return { transferId, rejectionReason, protocolData } } -function serializeMessage (requestId, protocolData) { - const writer = new Writer() +function deserialize (buffer) { + const envelopeReader = Reader.from(buffer) - writeProtocolData(writer, protocolData) + const type = envelopeReader.readUInt8() + const requestId = envelopeReader.readUInt32() + const dataBuff = envelopeReader.readVarOctetString() + const reader = new Reader(dataBuff) - return writeEnvelope(TYPE_MESSAGE, requestId, writer.getBuffer()) -} + let data + switch (type) { + case TYPE_ACK: + case TYPE_RESPONSE: + case TYPE_MESSAGE: + data = readProtocolData(reader) // see https://github.com/interledger/rfcs/issues/284 + break -function deserializeMessage (buffer) { - const { requestId, data } = readEnvelope(buffer) - const reader = new Reader(data) + case TYPE_ERROR: + data = readError(reader) + break - const protocolData = readProtocolData(reader) - return { requestId, protocolData } -} + case TYPE_PREPARE: + data = readPrepare(reader) + break -function deserializeClpPacket (buffer) { - const {typeString, packet} = _toTypeString(buffer) - return { - type: buffer[0], - typeString, - packet - } -} + case TYPE_FULFILL: + data = readFulfill(reader) + break + + case TYPE_REJECT: + data = readReject(reader) + break -function _toTypeString (buffer) { - switch (buffer[0]) { - case TYPE_ACK: return { - typeString: 'clp_ack', - packet: deserializeAck(buffer) } - case TYPE_RESPONSE: return { - typeString: 'clp_response', - packet: deserializeResponse(buffer) } - case TYPE_ERROR: return { - typeString: 'clp_error', - packet: deserializeError(buffer) } - case TYPE_PREPARE: return { - typeString: 'clp_prepare', - packet: deserializePrepare(buffer) } - case TYPE_FULFILL: return { - typeString: 'clp_fulfill', - packet: deserializeFulfill(buffer) } - case TYPE_REJECT: return { - typeString: 'clp_reject', - packet: deserializeReject(buffer) } - case TYPE_MESSAGE: return { - typeString: 'clp_message', - packet: deserializeMessage(buffer) } default: - throw new Error('Packet has invalid type') + throw new Error('Unrecognized type') } + + return { type, requestId, data } } module.exports = { @@ -339,24 +292,145 @@ module.exports = { TYPE_REJECT, TYPE_MESSAGE, + typeToString, + MIME_APPLICATION_OCTET_STREAM, MIME_TEXT_PLAIN_UTF8, MIME_APPLICATION_JSON, - serializeAck, - serializeResponse, - serializeError, - serializePrepare, - serializeFulfill, - serializeReject, - serializeMessage, - - deserializeAck, - deserializeResponse, - deserializeError, - deserializePrepare, - deserializeFulfill, - deserializeReject, - deserializeMessage, - deserializeClpPacket + serialize, + deserialize, + + // The following legacy functions use an alternative format to access the exposed + // serialize/deserialize functionality. There is one pair of such functions per CLP call. + // The object returned by the deserialize function differs per call, is different from + // the arguments passed to the corresponding serialize function, and is also different + // from the structure of CLP's OER encoding. Due to these disadvantages, these functions + // are marked as 'legacy functions' here; however, we did not remove them because + // the serialize ones are already used by the payment plugin framework. + + serializeAck (requestId, protocolData) { + return serialize({ + type: TYPE_ACK, + requestId, + data: protocolData + }) + }, + deserializeAck (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + protocolData: obj.data + } + }, + serializeResponse (requestId, protocolData) { + return serialize({ + type: TYPE_RESPONSE, + requestId, + data: protocolData + }) + }, + deserializeResponse (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + protocolData: obj.data + } + }, + serializeError ({ rejectionReason }, requestId, protocolData) { + return serialize({ + type: TYPE_ERROR, + requestId, + data: { + rejectionReason, + protocolData + } + }) + }, + deserializeError (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + rejectionReason: obj.data.rejectionReason, + protocolData: obj.data.protocolData + } + }, + serializePrepare ({ transferId, amount, executionCondition, expiresAt }, requestId, protocolData) { + return serialize({ + type: TYPE_PREPARE, + requestId, + data: { + transferId, + amount, + executionCondition, + expiresAt, + protocolData + } + }) + }, + deserializePrepare (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + transferId: obj.data.transferId, + amount: obj.data.amount, + executionCondition: obj.data.executionCondition, + expiresAt: obj.data.expiresAt, + protocolData: obj.data.protocolData + } + }, + serializeFulfill ({ transferId, fulfillment }, requestId, protocolData) { + return serialize({ + type: TYPE_FULFILL, + requestId, + data: { + transferId, + fulfillment, + protocolData + } + }) + }, + deserializeFulfill (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + transferId: obj.data.transferId, + fulfillment: obj.data.fulfillment, + protocolData: obj.data.protocolData + } + }, + serializeReject ({ transferId, rejectionReason }, requestId, protocolData) { + return serialize({ + type: TYPE_REJECT, + requestId, + data: { + transferId, + rejectionReason, + protocolData + } + }) + }, + deserializeReject (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + transferId: obj.data.transferId, + rejectionReason: obj.data.rejectionReason, + protocolData: obj.data.protocolData + } + }, + serializeMessage (requestId, protocolData) { + return serialize({ + type: TYPE_MESSAGE, + requestId, + data: protocolData + }) + }, + deserializeMessage (buffer) { + const obj = deserialize(buffer) + return { + requestId: obj.requestId, + protocolData: obj.data + } + } } diff --git a/package.json b/package.json index fb32927..0e6f453 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "ilp-packet": "^1.3.0", "istanbul": "^0.4.5", "mocha": "^3.5.0", - "uuid": "^3.1.0", "eslint": "^4.2.0", "eslint-config-standard": "^10.2.1", "eslint-plugin-import": "^2.7.0", diff --git a/test/indexSpec.js b/test/indexSpec.js index 0c7b08e..8524758 100644 --- a/test/indexSpec.js +++ b/test/indexSpec.js @@ -3,8 +3,6 @@ const Clp = require('..') const assert = require('chai').assert const IlpPacket = require('ilp-packet') -const uuid = require('uuid') -const crypto = require('crypto') const base64url = require('base64url') describe('Common Ledger Protocol', () => { @@ -22,15 +20,15 @@ describe('Common Ledger Protocol', () => { ] this.transfer = { - transferId: uuid(), + transferId: 'b4c838f6-80b1-47f8-a82e-b1fcfbed89d5', amount: '1000', - executionCondition: base64url(crypto.randomBytes(32)), - expiresAt: new Date() + executionCondition: base64url(Buffer.from([219, 42, 249, 249, 219, 166, 255, 52, 179, 237, 173, 251, 152, 107, 155, 180, 205, 75, 75, 65, 229, 4, 65, 25, 197, 93, 52, 175, 218, 191, 252, 2])), + expiresAt: new Date('2017-08-28 11:32') } this.fulfill = { transferId: this.transfer.transferId, - fulfillment: base64url(crypto.randomBytes(32)) + fulfillment: base64url(Buffer.from([219, 42, 249, 249, 219, 166, 255, 52, 179, 237, 173, 251, 152, 107, 155, 180, 205, 75, 75, 65, 229, 4, 65, 25, 197, 93, 52, 175, 218, 191, 252, 2])) } this.reject = { @@ -39,7 +37,7 @@ describe('Common Ledger Protocol', () => { } this.rejectBuf = { - transferId: this.transfer.transferId, + transferId: this.transfer.transferId, rejectionReason: this.errorBuf } @@ -53,17 +51,194 @@ describe('Common Ledger Protocol', () => { name: 'errorName', triggeredBy: 'peer.', forwardedBy: ['die da', 'die da', 'die da'], - triggeredAt: new Date(), + triggeredAt: new Date('2017-08-28 11:32'), data: 'boo' } this.errorBuf = IlpPacket.serializeIlpError(this.error) this.errorStr = this.errorBuf.toString('base64') - + this.buffers = { + ack: Buffer.from([1, 0, 0, 0, 1, 67, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + response: Buffer.from([2, 0, 0, 0, 1, 67, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + error: Buffer.from([3, 0, 0, 0, 1, 129, 136, 8, 67, 76, 49, 51, 9, 101, 114, 114, 111, 114, 78, 97, 109, 101, 5, 112, 101, 101, 114, 46, 1, 3, 6, 100, 105, 101, 32, 100, 97, 6, 100, 105, 101, 32, 100, 97, 6, 100, 105, 101, 32, 100, 97, 19, 50, 48, 49, 55, 48, 56, 50, 56, 48, 57, 51, 50, 48, 48, 46, 48, 48, 48, 90, 3, 98, 111, 111, 0, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + prepare1: Buffer.from([4, 0, 0, 0, 1, 129, 143, 180, 200, 56, 246, 128, 177, 71, 248, 168, 46, 177, 252, 251, 237, 137, 213, 0, 0, 0, 0, 0, 0, 3, 232, 219, 42, 249, 249, 219, 166, 255, 52, 179, 237, 173, 251, 152, 107, 155, 180, 205, 75, 75, 65, 229, 4, 65, 25, 197, 93, 52, 175, 218, 191, 252, 2, 19, 50, 48, 49, 55, 48, 56, 50, 56, 48, 57, 51, 50, 48, 48, 46, 48, 48, 48, 90, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + prepare2: Buffer.from([4, 0, 0, 0, 1, 129, 143, 180, 200, 56, 246, 128, 177, 71, 248, 168, 46, 177, 252, 251, 237, 137, 213, 0, 0, 1, 31, 113, 251, 4, 203, 219, 42, 249, 249, 219, 166, 255, 52, 179, 237, 173, 251, 152, 107, 155, 180, 205, 75, 75, 65, 229, 4, 65, 25, 197, 93, 52, 175, 218, 191, 252, 2, 19, 50, 48, 49, 55, 48, 56, 50, 56, 48, 57, 51, 50, 48, 48, 46, 48, 48, 48, 90, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + fulfill: Buffer.from([5, 0, 0, 0, 1, 115, 180, 200, 56, 246, 128, 177, 71, 248, 168, 46, 177, 252, 251, 237, 137, 213, 219, 42, 249, 249, 219, 166, 255, 52, 179, 237, 173, 251, 152, 107, 155, 180, 205, 75, 75, 65, 229, 4, 65, 25, 197, 93, 52, 175, 218, 191, 252, 2, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + reject: Buffer.from([6, 0, 0, 0, 1, 129, 152, 180, 200, 56, 246, 128, 177, 71, 248, 168, 46, 177, 252, 251, 237, 137, 213, 8, 67, 76, 49, 51, 9, 101, 114, 114, 111, 114, 78, 97, 109, 101, 5, 112, 101, 101, 114, 46, 1, 3, 6, 100, 105, 101, 32, 100, 97, 6, 100, 105, 101, 32, 100, 97, 6, 100, 105, 101, 32, 100, 97, 19, 50, 48, 49, 55, 48, 56, 50, 56, 48, 57, 51, 50, 48, 48, 46, 48, 48, 48, 90, 3, 98, 111, 111, 0, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]), + message: Buffer.from([7, 0, 0, 0, 1, 67, 1, 4, 3, 105, 108, 112, 0, 30, 1, 28, 0, 0, 0, 0, 0, 0, 0, 100, 17, 101, 120, 97, 109, 112, 108, 101, 46, 114, 101, 100, 46, 97, 108, 105, 99, 101, 0, 0, 3, 102, 111, 111, 0, 3, 98, 97, 114, 4, 98, 101, 101, 112, 1, 4, 98, 111, 111, 112, 4, 106, 115, 111, 110, 2, 2, 123, 125]) + } }) describe('Ack', () => { it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_ACK, + requestId: 1, + data: this.protocolData // see https://github.com/interledger/rfcs/issues/284 + } + assert.deepEqual(Clp.serialize(obj), this.buffers.ack) + assert.deepEqual(Clp.deserialize(this.buffers.ack), obj) + }) + }) + + describe('Response', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_RESPONSE, + requestId: 1, + data: this.protocolData // see https://github.com/interledger/rfcs/issues/284 + } + assert.deepEqual(Clp.serialize(obj), this.buffers.response) + assert.deepEqual(Clp.deserialize(this.buffers.response), obj) + }) + }) + + describe('Error', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_ERROR, + requestId: 1, + data: { + protocolData: this.protocolData, + rejectionReason: this.error + } + } + assert.deepEqual(Clp.serialize(obj), this.buffers.error) + assert.deepEqual(Clp.deserialize(this.buffers.error), obj) + }) + + it('should serialize from buffer without losing data', function () { + const objWithBuf = { + type: Clp.TYPE_ERROR, + requestId: 1, + data: { + protocolData: this.protocolData, + rejectionReason: this.errorBuf + } + } + assert.deepEqual(Clp.serialize(objWithBuf), this.buffers.error) + }) + + it('should serialize from string without losing data', function () { + const objWithStr = { + type: Clp.TYPE_ERROR, + requestId: 1, + data: { + protocolData: this.protocolData, + rejectionReason: this.errorStr + } + } + assert.deepEqual(Clp.serialize(objWithStr), this.buffers.error) + }) + }) + + describe('Prepare', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_PREPARE, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.transfer.transferId, + amount: this.transfer.amount, + expiresAt: this.transfer.expiresAt, + executionCondition: this.transfer.executionCondition + } + } + assert.deepEqual(Clp.serialize(obj), this.buffers.prepare1) + assert.deepEqual(Clp.deserialize(this.buffers.prepare1), obj) + }) + + it('should serialize/deserialize 64-bit amount without losing precision', function () { + const obj = { + type: Clp.TYPE_PREPARE, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.transfer.transferId, + amount: '1234567890123', + expiresAt: this.transfer.expiresAt, + executionCondition: this.transfer.executionCondition + } + } + assert.deepEqual(Clp.serialize(obj), this.buffers.prepare2) + assert.deepEqual(Clp.deserialize(this.buffers.prepare2), obj) + }) + }) + + describe('Fufill', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_FULFILL, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.fulfill.transferId, + fulfillment: this.fulfill.fulfillment + } + } + assert.deepEqual(Clp.serialize(obj), this.buffers.fulfill) + assert.deepEqual(Clp.deserialize(this.buffers.fulfill), obj) + }) + }) + + describe('Reject', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_REJECT, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.fulfill.transferId, + rejectionReason: this.error + } + } + assert.deepEqual(Clp.serialize(obj), this.buffers.reject) + assert.deepEqual(Clp.deserialize(this.buffers.reject), obj) + }) + + it('should serialize from buffer without losing data', function () { + const objWithBuf = { + type: Clp.TYPE_REJECT, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.fulfill.transferId, + rejectionReason: this.errorBuf + } + } + assert.deepEqual(Clp.serialize(objWithBuf), this.buffers.reject) + }) + + it('should serialize from string without losing data', function () { + const objWithStr = { + type: Clp.TYPE_REJECT, + requestId: 1, + data: { + protocolData: this.protocolData, + transferId: this.fulfill.transferId, + rejectionReason: this.errorStr + } + } + assert.deepEqual(Clp.serialize(objWithStr), this.buffers.reject) + }) + }) + + describe('Message', () => { + it('should serialize/deserialize without losing data', function () { + const obj = { + type: Clp.TYPE_MESSAGE, + requestId: 1, + data: this.protocolData // see https://github.com/interledger/rfcs/issues/284 + } + assert.deepEqual(Clp.serialize(obj), this.buffers.message) + assert.deepEqual(Clp.deserialize(this.buffers.message), obj) + }) + }) + + describe('Ack (legacy)', () => { + it('should serialize / deserialize without losing data', function () { const buf = Clp.serializeAck(1, this.protocolData) + assert.deepEqual(buf, this.buffers.ack) const res = Clp.deserializeAck(buf) assert.deepEqual(res, { @@ -73,9 +248,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Response', () => { + describe('Response (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializeResponse(1, this.protocolData) + assert.deepEqual(buf, this.buffers.response) const res = Clp.deserializeResponse(buf) assert.deepEqual(res, { @@ -85,9 +261,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Error', () => { + describe('Error (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializeError({ rejectionReason: this.error }, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.error) const res = Clp.deserializeError(buf) assert.deepEqual(res, { @@ -99,6 +276,7 @@ describe('Common Ledger Protocol', () => { it('should serialize from buffer without losing data', function () { const buf = Clp.serializeError({ rejectionReason: this.errorBuf }, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.error) const res = Clp.deserializeError(buf) assert.deepEqual(res, { @@ -110,6 +288,7 @@ describe('Common Ledger Protocol', () => { it('should serialize from string without losing data', function () { const buf = Clp.serializeError({ rejectionReason: this.errorStr }, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.error) const res = Clp.deserializeError(buf) assert.deepEqual(res, { @@ -120,9 +299,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Prepare', () => { + describe('Prepare (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializePrepare(this.transfer, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.prepare1) const res = Clp.deserializePrepare(buf) assert.deepEqual(res, Object.assign({ @@ -135,6 +315,7 @@ describe('Common Ledger Protocol', () => { this.transfer.amount = '1234567890123' const buf = Clp.serializePrepare(this.transfer, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.prepare2) const res = Clp.deserializePrepare(buf) assert.deepEqual(res, Object.assign({ @@ -144,9 +325,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Fufill', () => { + describe('Fufill (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializeFulfill(this.fulfill, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.fulfill) const res = Clp.deserializeFulfill(buf) assert.deepEqual(res, Object.assign({ @@ -156,9 +338,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Reject', () => { + describe('Reject (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializeReject(this.reject, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.reject) const res = Clp.deserializeReject(buf) assert.deepEqual(res, Object.assign({ @@ -170,6 +353,7 @@ describe('Common Ledger Protocol', () => { it('should serialize from buffer without losing data', function () { const buf = Clp.serializeReject(this.rejectBuf, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.reject) const res = Clp.deserializeReject(buf) assert.deepEqual(res, Object.assign({ @@ -181,6 +365,7 @@ describe('Common Ledger Protocol', () => { it('should serialize from string without losing data', function () { const buf = Clp.serializeReject(this.rejectStr, 1, this.protocolData) + assert.deepEqual(buf, this.buffers.reject) const res = Clp.deserializeReject(buf) assert.deepEqual(res, Object.assign({ @@ -191,9 +376,10 @@ describe('Common Ledger Protocol', () => { }) }) - describe('Message', () => { + describe('Message (legacy)', () => { it('should serialize/deserialize without losing data', function () { const buf = Clp.serializeMessage(1, this.protocolData) + assert.deepEqual(buf, this.buffers.message) const res = Clp.deserializeMessage(buf) assert.deepEqual(res, {