UNPKG

@neo-one/node-protocol

Version:

NEO•ONE NEO node and consensus protocol.

286 lines (284 loc) 40.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const client_common_1 = require("@neo-one/client-common"); const node_core_1 = require("@neo-one/node-core"); const utils_1 = require("@neo-one/utils"); const stream_1 = require("stream"); const Command_1 = require("./Command"); const payload_1 = require("./payload"); exports.COMMAND_LENGTH = 12; exports.PAYLOAD_MAX_SIZE = 0x02000000; const calculateChecksum = (buffer) => client_common_1.common.toUInt32LE(client_common_1.crypto.hash256(buffer)); const deserializeMessageHeader = ({ context, reader, }) => { if (reader.readUInt32LE() !== context.messageMagic) { throw new client_common_1.InvalidFormatError(`Expected BinaryReader readUInt32LE(0) to equal ${context.messageMagic}. Received: ${context.messageMagic}`); } const command = Command_1.assertCommand(reader.readFixedString(exports.COMMAND_LENGTH)); const length = reader.readUInt32LE(); if (length > exports.PAYLOAD_MAX_SIZE) { throw new client_common_1.InvalidFormatError(`Expected buffer readout to be less than max payload size of ${exports.PAYLOAD_MAX_SIZE}. Received: ${length}`); } const checksum = reader.readUInt32LE(); return { command, length, checksum }; }; class Message { constructor({ magic, value }) { this.serializeWire = client_common_1.createSerializeWire(this.serializeWireBase.bind(this)); this.magic = magic; this.value = value; } static deserializeWireBase(options) { const { reader, context } = options; const { command, length, checksum } = deserializeMessageHeader(options); const payloadBuffer = reader.readBytes(length); const payloadBufferChecksum = calculateChecksum(payloadBuffer); if (payloadBufferChecksum !== checksum) { throw new client_common_1.InvalidFormatError(`Expected payloadBuffer checksum to be ${checksum}. Received: ${payloadBufferChecksum}`); } const payloadOptions = { context: options.context, buffer: payloadBuffer, }; let value; switch (command) { case Command_1.Command.addr: value = { command: Command_1.Command.addr, payload: payload_1.AddrPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.block: value = { command: Command_1.Command.block, payload: node_core_1.Block.deserializeWire(payloadOptions), }; break; case Command_1.Command.consensus: value = { command: Command_1.Command.consensus, payload: node_core_1.ConsensusPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.filteradd: value = { command: Command_1.Command.filteradd, payload: payload_1.FilterAddPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.filterclear: value = { command: Command_1.Command.filterclear }; break; case Command_1.Command.filterload: value = { command: Command_1.Command.filterload, payload: payload_1.FilterLoadPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.getaddr: value = { command: Command_1.Command.getaddr }; break; case Command_1.Command.getblocks: value = { command: Command_1.Command.getblocks, payload: payload_1.GetBlocksPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.getdata: value = { command: Command_1.Command.getdata, payload: payload_1.InvPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.getheaders: value = { command: Command_1.Command.getheaders, payload: payload_1.GetBlocksPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.headers: value = { command: Command_1.Command.headers, payload: payload_1.HeadersPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.inv: value = { command: Command_1.Command.inv, payload: payload_1.InvPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.mempool: value = { command: Command_1.Command.mempool }; break; case Command_1.Command.tx: value = { command: Command_1.Command.tx, payload: node_core_1.deserializeTransactionWire(payloadOptions), }; break; case Command_1.Command.verack: value = { command: Command_1.Command.verack }; break; case Command_1.Command.version: value = { command: Command_1.Command.version, payload: payload_1.VersionPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.alert: value = { command: Command_1.Command.alert }; break; case Command_1.Command.merkleblock: value = { command: Command_1.Command.merkleblock, payload: payload_1.MerkleBlockPayload.deserializeWire(payloadOptions), }; break; case Command_1.Command.notfound: value = { command: Command_1.Command.notfound }; break; case Command_1.Command.ping: value = { command: Command_1.Command.ping }; break; case Command_1.Command.pong: value = { command: Command_1.Command.pong }; break; case Command_1.Command.reject: value = { command: Command_1.Command.reject }; break; default: utils_1.utils.assertNever(command); throw new client_common_1.InvalidFormatError(``); } return new this({ magic: context.messageMagic, value }); } static deserializeWire(options) { return this.deserializeWireBase({ context: options.context, reader: new node_core_1.BinaryReader(options.buffer), }); } serializeWireBase(writer) { const { value } = this; writer.writeUInt32LE(this.magic); writer.writeFixedString(value.command, exports.COMMAND_LENGTH); let payload = Buffer.alloc(0); switch (value.command) { case Command_1.Command.addr: payload = value.payload.serializeWire(); break; case Command_1.Command.block: payload = value.payload.serializeWire(); break; case Command_1.Command.consensus: payload = value.payload.serializeWire(); break; case Command_1.Command.filteradd: payload = value.payload.serializeWire(); break; case Command_1.Command.filterclear: break; case Command_1.Command.filterload: payload = value.payload.serializeWire(); break; case Command_1.Command.getaddr: break; case Command_1.Command.getblocks: payload = value.payload.serializeWire(); break; case Command_1.Command.getdata: payload = value.payload.serializeWire(); break; case Command_1.Command.getheaders: payload = value.payload.serializeWire(); break; case Command_1.Command.headers: payload = value.payload.serializeWire(); break; case Command_1.Command.inv: payload = value.payload.serializeWire(); break; case Command_1.Command.mempool: break; case Command_1.Command.tx: payload = value.payload.serializeWire(); break; case Command_1.Command.verack: break; case Command_1.Command.version: payload = value.payload.serializeWire(); break; case Command_1.Command.alert: break; case Command_1.Command.merkleblock: payload = value.payload.serializeWire(); break; case Command_1.Command.notfound: break; case Command_1.Command.ping: break; case Command_1.Command.pong: break; case Command_1.Command.reject: break; default: utils_1.utils.assertNever(value); throw new client_common_1.InvalidFormatError('Command does not exist'); } writer.writeUInt32LE(payload.length); writer.writeUInt32LE(calculateChecksum(payload)); writer.writeBytes(payload); } } exports.Message = Message; exports.InvalidMessageTransformEncodingError = utils_1.makeErrorWithCode('INVALID_MESSAGE_TRANSFORM_ENCODING', (message) => message); const SIZE_OF_MESSAGE_HEADER = client_common_1.IOHelper.sizeOfUInt32LE + client_common_1.IOHelper.sizeOfFixedString(exports.COMMAND_LENGTH) + client_common_1.IOHelper.sizeOfUInt32LE + client_common_1.IOHelper.sizeOfUInt32LE; class MessageTransform extends stream_1.Transform { constructor(context) { super({ readableObjectMode: true }); this.context = context; this.mutableBuffer = Buffer.from([]); } _transform(chunk, encoding, callback) { if (typeof chunk === 'string') { throw new exports.InvalidMessageTransformEncodingError(`Invalid Message Transform Chunk Type. Expected chunk type to be 'string', found: ${typeof chunk}`); } if (encoding !== 'buffer') { throw new exports.InvalidMessageTransformEncodingError(`Invalid Message Transform Encoding. Expected: 'buffer', found: ${encoding}`); } this.mutableBuffer = Buffer.concat([this.mutableBuffer, chunk]); try { const { remainingBuffer, mutableMessages } = this.processBuffer(new node_core_1.BinaryReader(this.mutableBuffer)); this.mutableBuffer = remainingBuffer; mutableMessages.forEach((message) => this.push(message)); callback(undefined); } catch (error) { callback(error); } } processBuffer(reader) { if (reader.remaining < SIZE_OF_MESSAGE_HEADER) { return { remainingBuffer: reader.remainingBuffer, mutableMessages: [] }; } const { length } = deserializeMessageHeader({ context: this.context, reader: reader.clone(), }); if (reader.remaining < SIZE_OF_MESSAGE_HEADER + length) { return { remainingBuffer: reader.remainingBuffer, mutableMessages: [] }; } const message = Message.deserializeWireBase({ context: this.context, reader, }); const { remainingBuffer, mutableMessages } = this.processBuffer(reader); mutableMessages.push(message); return { remainingBuffer, mutableMessages }; } } exports.MessageTransform = MessageTransform; //# sourceMappingURL=data:application/json;charset=utf8;base64,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U0FDdkIsQ0FBQyxDQUFDO1FBRUgsSUFBSSxNQUFNLENBQUMsU0FBUyxHQUFHLHNCQUFzQixHQUFHLE1BQU0sRUFBRTtZQUN0RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxDQUFDO1NBQ3pFO1FBRUQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDO1lBQzFDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztZQUNyQixNQUFNO1NBQ1AsQ0FBQyxDQUFDO1FBRUgsTUFBTSxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3hFLGVBQWUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFOUIsT0FBTyxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsQ0FBQztJQUM5QyxDQUFDO0NBQ0Y7QUFuRUQsNENBbUVDIiwiZmlsZSI6Im5lby1vbmUtbm9kZS1wcm90b2NvbC9zcmMvTWVzc2FnZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEJpbmFyeVdyaXRlcixcbiAgY29tbW9uLFxuICBjcmVhdGVTZXJpYWxpemVXaXJlLFxuICBjcnlwdG8sXG4gIEludmFsaWRGb3JtYXRFcnJvcixcbiAgSU9IZWxwZXIsXG4gIFNlcmlhbGl6YWJsZVdpcmUsXG4gIFNlcmlhbGl6ZVdpcmUsXG59IGZyb20gJ0BuZW8tb25lL2NsaWVudC1jb21tb24nO1xuaW1wb3J0IHtcbiAgQmluYXJ5UmVhZGVyLFxuICBCbG9jayxcbiAgQ29uc2Vuc3VzUGF5bG9hZCxcbiAgZGVzZXJpYWxpemVUcmFuc2FjdGlvbldpcmUsXG4gIERlc2VyaWFsaXplV2lyZUJhc2VPcHRpb25zLFxuICBEZXNlcmlhbGl6ZVdpcmVDb250ZXh0LFxuICBEZXNlcmlhbGl6ZVdpcmVPcHRpb25zLFxuICBUcmFuc2FjdGlvbixcbn0gZnJvbSAnQG5lby1vbmUvbm9kZS1jb3JlJztcbmltcG9ydCB7IG1ha2VFcnJvcldpdGhDb2RlLCB1dGlscyB9IGZyb20gJ0BuZW8tb25lL3V0aWxzJztcbmltcG9ydCB7IFRyYW5zZm9ybSB9IGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgeyBhc3NlcnRDb21tYW5kLCBDb21tYW5kIH0gZnJvbSAnLi9Db21tYW5kJztcbmltcG9ydCB7XG4gIEFkZHJQYXlsb2FkLFxuICBGaWx0ZXJBZGRQYXlsb2FkLFxuICBGaWx0ZXJMb2FkUGF5bG9hZCxcbiAgR2V0QmxvY2tzUGF5bG9hZCxcbiAgSGVhZGVyc1BheWxvYWQsXG4gIEludlBheWxvYWQsXG4gIE1lcmtsZUJsb2NrUGF5bG9hZCxcbiAgVmVyc2lvblBheWxvYWQsXG59IGZyb20gJy4vcGF5bG9hZCc7XG5leHBvcnQgdHlwZSBNZXNzYWdlVmFsdWUgPVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC5hZGRyOyByZWFkb25seSBwYXlsb2FkOiBBZGRyUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmJsb2NrOyByZWFkb25seSBwYXlsb2FkOiBCbG9jayB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmNvbnNlbnN1czsgcmVhZG9ubHkgcGF5bG9hZDogQ29uc2Vuc3VzUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmZpbHRlcmFkZDsgcmVhZG9ubHkgcGF5bG9hZDogRmlsdGVyQWRkUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmZpbHRlcmNsZWFyIH1cbiAgfCB7IHJlYWRvbmx5IGNvbW1hbmQ6IENvbW1hbmQuZmlsdGVybG9hZDsgcmVhZG9ubHkgcGF5bG9hZDogRmlsdGVyTG9hZFBheWxvYWQgfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC5nZXRhZGRyIH1cbiAgfCB7IHJlYWRvbmx5IGNvbW1hbmQ6IENvbW1hbmQuZ2V0YmxvY2tzOyByZWFkb25seSBwYXlsb2FkOiBHZXRCbG9ja3NQYXlsb2FkIH1cbiAgfCB7IHJlYWRvbmx5IGNvbW1hbmQ6IENvbW1hbmQuZ2V0ZGF0YTsgcmVhZG9ubHkgcGF5bG9hZDogSW52UGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmdldGhlYWRlcnM7IHJlYWRvbmx5IHBheWxvYWQ6IEdldEJsb2Nrc1BheWxvYWQgfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC5oZWFkZXJzOyByZWFkb25seSBwYXlsb2FkOiBIZWFkZXJzUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmludjsgcmVhZG9ubHkgcGF5bG9hZDogSW52UGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLm1lbXBvb2wgfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC50eDsgcmVhZG9ubHkgcGF5bG9hZDogVHJhbnNhY3Rpb24gfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC52ZXJhY2sgfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC52ZXJzaW9uOyByZWFkb25seSBwYXlsb2FkOiBWZXJzaW9uUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLmFsZXJ0IH1cbiAgfCB7IHJlYWRvbmx5IGNvbW1hbmQ6IENvbW1hbmQubWVya2xlYmxvY2s7IHJlYWRvbmx5IHBheWxvYWQ6IE1lcmtsZUJsb2NrUGF5bG9hZCB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLm5vdGZvdW5kIH1cbiAgfCB7IHJlYWRvbmx5IGNvbW1hbmQ6IENvbW1hbmQucGluZyB9XG4gIHwgeyByZWFkb25seSBjb21tYW5kOiBDb21tYW5kLnBvbmcgfVxuICB8IHsgcmVhZG9ubHkgY29tbWFuZDogQ29tbWFuZC5yZWplY3QgfTtcbmV4cG9ydCBpbnRlcmZhY2UgTWVzc2FnZUFkZCB7XG4gIHJlYWRvbmx5IG1hZ2ljOiBudW1iZXI7XG4gIHJlYWRvbmx5IHZhbHVlOiBNZXNzYWdlVmFsdWU7XG59XG5cbmV4cG9ydCBjb25zdCBDT01NQU5EX0xFTkdUSCA9IDEyO1xuZXhwb3J0IGNvbnN0IFBBWUxPQURfTUFYX1NJWkUgPSAweDAyMDAwMDAwO1xuXG5jb25zdCBjYWxjdWxhdGVDaGVja3N1bSA9IChidWZmZXI6IEJ1ZmZlcikgPT4gY29tbW9uLnRvVUludDMyTEUoY3J5cHRvLmhhc2gyNTYoYnVmZmVyKSk7XG5cbmNvbnN0IGRlc2VyaWFsaXplTWVzc2FnZUhlYWRlciA9ICh7XG4gIGNvbnRleHQsXG4gIHJlYWRlcixcbn06IERlc2VyaWFsaXplV2lyZUJhc2VPcHRpb25zKToge1xuICByZWFkb25seSBjb21tYW5kOiBDb21tYW5kO1xuICByZWFkb25seSBsZW5ndGg6IG51bWJlcjtcbiAgcmVhZG9ubHkgY2hlY2tzdW06IG51bWJlcjtcbn0gPT4ge1xuICBpZiAocmVhZGVyLnJlYWRVSW50MzJMRSgpICE9PSBjb250ZXh0Lm1lc3NhZ2VNYWdpYykge1xuICAgIHRocm93IG5ldyBJbnZhbGlkRm9ybWF0RXJyb3IoXG4gICAgICBgRXhwZWN0ZWQgQmluYXJ5UmVhZGVyIHJlYWRVSW50MzJMRSgwKSB0byBlcXVhbCAke2NvbnRleHQubWVzc2FnZU1hZ2ljfS4gUmVjZWl2ZWQ6ICR7Y29udGV4dC5tZXNzYWdlTWFnaWN9YCxcbiAgICApO1xuICB9XG4gIGNvbnN0IGNvbW1hbmQgPSBhc3NlcnRDb21tYW5kKHJlYWRlci5yZWFkRml4ZWRTdHJpbmcoQ09NTUFORF9MRU5HVEgpKTtcbiAgY29uc3QgbGVuZ3RoID0gcmVhZGVyLnJlYWRVSW50MzJMRSgpO1xuICBpZiAobGVuZ3RoID4gUEFZTE9BRF9NQVhfU0laRSkge1xuICAgIHRocm93IG5ldyBJbnZhbGlkRm9ybWF0RXJyb3IoXG4gICAgICBgRXhwZWN0ZWQgYnVmZmVyIHJlYWRvdXQgdG8gYmUgbGVzcyB0aGFuIG1heCBwYXlsb2FkIHNpemUgb2YgJHtQQVlMT0FEX01BWF9TSVpFfS4gUmVjZWl2ZWQ6ICR7bGVuZ3RofWAsXG4gICAgKTtcbiAgfVxuICBjb25zdCBjaGVja3N1bSA9IHJlYWRlci5yZWFkVUludDMyTEUoKTtcblxuICByZXR1cm4geyBjb21tYW5kLCBsZW5ndGgsIGNoZWNrc3VtIH07XG59O1xuXG5leHBvcnQgY2xhc3MgTWVzc2FnZSBpbXBsZW1lbnRzIFNlcmlhbGl6YWJsZVdpcmU8TWVzc2FnZT4ge1xuICBwdWJsaWMgc3RhdGljIGRlc2VyaWFsaXplV2lyZUJhc2Uob3B0aW9uczogRGVzZXJpYWxpemVXaXJlQmFzZU9wdGlvbnMpOiBNZXNzYWdlIHtcbiAgICBjb25zdCB7IHJlYWRlciwgY29udGV4dCB9ID0gb3B0aW9ucztcbiAgICBjb25zdCB7IGNvbW1hbmQsIGxlbmd0aCwgY2hlY2tzdW0gfSA9IGRlc2VyaWFsaXplTWVzc2FnZUhlYWRlcihvcHRpb25zKTtcbiAgICBjb25zdCBwYXlsb2FkQnVmZmVyID0gcmVhZGVyLnJlYWRCeXRlcyhsZW5ndGgpO1xuICAgIGNvbnN0IHBheWxvYWRCdWZmZXJDaGVja3N1bSA9IGNhbGN1bGF0ZUNoZWNrc3VtKHBheWxvYWRCdWZmZXIpO1xuICAgIGlmIChwYXlsb2FkQnVmZmVyQ2hlY2tzdW0gIT09IGNoZWNrc3VtKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEZvcm1hdEVycm9yKFxuICAgICAgICBgRXhwZWN0ZWQgcGF5bG9hZEJ1ZmZlciBjaGVja3N1bSB0byBiZSAke2NoZWNrc3VtfS4gUmVjZWl2ZWQ6ICR7cGF5bG9hZEJ1ZmZlckNoZWNrc3VtfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHBheWxvYWRPcHRpb25zID0ge1xuICAgICAgY29udGV4dDogb3B0aW9ucy5jb250ZXh0LFxuICAgICAgYnVmZmVyOiBwYXlsb2FkQnVmZmVyLFxuICAgIH07XG5cbiAgICBsZXQgdmFsdWU6IE1lc3NhZ2VWYWx1ZTtcbiAgICBzd2l0Y2ggKGNvbW1hbmQpIHtcbiAgICAgIGNhc2UgQ29tbWFuZC5hZGRyOlxuICAgICAgICB2YWx1ZSA9IHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmFkZHIsXG4gICAgICAgICAgcGF5bG9hZDogQWRkclBheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5ibG9jazpcbiAgICAgICAgdmFsdWUgPSB7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5ibG9jayxcbiAgICAgICAgICBwYXlsb2FkOiBCbG9jay5kZXNlcmlhbGl6ZVdpcmUocGF5bG9hZE9wdGlvbnMpLFxuICAgICAgICB9O1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmNvbnNlbnN1czpcbiAgICAgICAgdmFsdWUgPSB7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5jb25zZW5zdXMsXG4gICAgICAgICAgcGF5bG9hZDogQ29uc2Vuc3VzUGF5bG9hZC5kZXNlcmlhbGl6ZVdpcmUocGF5bG9hZE9wdGlvbnMpLFxuICAgICAgICB9O1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmFkZDpcbiAgICAgICAgdmFsdWUgPSB7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5maWx0ZXJhZGQsXG4gICAgICAgICAgcGF5bG9hZDogRmlsdGVyQWRkUGF5bG9hZC5kZXNlcmlhbGl6ZVdpcmUocGF5bG9hZE9wdGlvbnMpLFxuICAgICAgICB9O1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmNsZWFyOlxuICAgICAgICB2YWx1ZSA9IHsgY29tbWFuZDogQ29tbWFuZC5maWx0ZXJjbGVhciB9O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5maWx0ZXJsb2FkOlxuICAgICAgICB2YWx1ZSA9IHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmZpbHRlcmxvYWQsXG4gICAgICAgICAgcGF5bG9hZDogRmlsdGVyTG9hZFBheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5nZXRhZGRyOlxuICAgICAgICB2YWx1ZSA9IHsgY29tbWFuZDogQ29tbWFuZC5nZXRhZGRyIH07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmdldGJsb2NrczpcbiAgICAgICAgdmFsdWUgPSB7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5nZXRibG9ja3MsXG4gICAgICAgICAgcGF5bG9hZDogR2V0QmxvY2tzUGF5bG9hZC5kZXNlcmlhbGl6ZVdpcmUocGF5bG9hZE9wdGlvbnMpLFxuICAgICAgICB9O1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmdldGRhdGE6XG4gICAgICAgIHZhbHVlID0ge1xuICAgICAgICAgIGNvbW1hbmQ6IENvbW1hbmQuZ2V0ZGF0YSxcbiAgICAgICAgICBwYXlsb2FkOiBJbnZQYXlsb2FkLmRlc2VyaWFsaXplV2lyZShwYXlsb2FkT3B0aW9ucyksXG4gICAgICAgIH07XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuZ2V0aGVhZGVyczpcbiAgICAgICAgdmFsdWUgPSB7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5nZXRoZWFkZXJzLFxuICAgICAgICAgIHBheWxvYWQ6IEdldEJsb2Nrc1BheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5oZWFkZXJzOlxuICAgICAgICB2YWx1ZSA9IHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmhlYWRlcnMsXG4gICAgICAgICAgcGF5bG9hZDogSGVhZGVyc1BheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5pbnY6XG4gICAgICAgIHZhbHVlID0ge1xuICAgICAgICAgIGNvbW1hbmQ6IENvbW1hbmQuaW52LFxuICAgICAgICAgIHBheWxvYWQ6IEludlBheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5tZW1wb29sOlxuICAgICAgICB2YWx1ZSA9IHsgY29tbWFuZDogQ29tbWFuZC5tZW1wb29sIH07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnR4OlxuICAgICAgICB2YWx1ZSA9IHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLnR4LFxuICAgICAgICAgIHBheWxvYWQ6IGRlc2VyaWFsaXplVHJhbnNhY3Rpb25XaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC52ZXJhY2s6XG4gICAgICAgIHZhbHVlID0geyBjb21tYW5kOiBDb21tYW5kLnZlcmFjayB9O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC52ZXJzaW9uOlxuICAgICAgICB2YWx1ZSA9IHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLnZlcnNpb24sXG4gICAgICAgICAgcGF5bG9hZDogVmVyc2lvblBheWxvYWQuZGVzZXJpYWxpemVXaXJlKHBheWxvYWRPcHRpb25zKSxcbiAgICAgICAgfTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5hbGVydDpcbiAgICAgICAgdmFsdWUgPSB7IGNvbW1hbmQ6IENvbW1hbmQuYWxlcnQgfTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQubWVya2xlYmxvY2s6XG4gICAgICAgIHZhbHVlID0ge1xuICAgICAgICAgIGNvbW1hbmQ6IENvbW1hbmQubWVya2xlYmxvY2ssXG4gICAgICAgICAgcGF5bG9hZDogTWVya2xlQmxvY2tQYXlsb2FkLmRlc2VyaWFsaXplV2lyZShwYXlsb2FkT3B0aW9ucyksXG4gICAgICAgIH07XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQubm90Zm91bmQ6XG4gICAgICAgIHZhbHVlID0geyBjb21tYW5kOiBDb21tYW5kLm5vdGZvdW5kIH07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnBpbmc6XG4gICAgICAgIHZhbHVlID0geyBjb21tYW5kOiBDb21tYW5kLnBpbmcgfTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQucG9uZzpcbiAgICAgICAgdmFsdWUgPSB7IGNvbW1hbmQ6IENvbW1hbmQucG9uZyB9O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5yZWplY3Q6XG4gICAgICAgIHZhbHVlID0geyBjb21tYW5kOiBDb21tYW5kLnJlamVjdCB9O1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHV0aWxzLmFzc2VydE5ldmVyKGNvbW1hbmQpO1xuICAgICAgICB0aHJvdyBuZXcgSW52YWxpZEZvcm1hdEVycm9yKGBgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IHRoaXMoeyBtYWdpYzogY29udGV4dC5tZXNzYWdlTWFnaWMsIHZhbHVlIH0pO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyBkZXNlcmlhbGl6ZVdpcmUob3B0aW9uczogRGVzZXJpYWxpemVXaXJlT3B0aW9ucyk6IE1lc3NhZ2Uge1xuICAgIHJldHVybiB0aGlzLmRlc2VyaWFsaXplV2lyZUJhc2Uoe1xuICAgICAgY29udGV4dDogb3B0aW9ucy5jb250ZXh0LFxuICAgICAgcmVhZGVyOiBuZXcgQmluYXJ5UmVhZGVyKG9wdGlvbnMuYnVmZmVyKSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSBtYWdpYzogbnVtYmVyO1xuICBwdWJsaWMgcmVhZG9ubHkgdmFsdWU6IE1lc3NhZ2VWYWx1ZTtcbiAgcHVibGljIHJlYWRvbmx5IHNlcmlhbGl6ZVdpcmU6IFNlcmlhbGl6ZVdpcmUgPSBjcmVhdGVTZXJpYWxpemVXaXJlKHRoaXMuc2VyaWFsaXplV2lyZUJhc2UuYmluZCh0aGlzKSk7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHsgbWFnaWMsIHZhbHVlIH06IE1lc3NhZ2VBZGQpIHtcbiAgICB0aGlzLm1hZ2ljID0gbWFnaWM7XG4gICAgdGhpcy52YWx1ZSA9IHZhbHVlO1xuICB9XG5cbiAgcHVibGljIHNlcmlhbGl6ZVdpcmVCYXNlKHdyaXRlcjogQmluYXJ5V3JpdGVyKTogdm9pZCB7XG4gICAgY29uc3QgeyB2YWx1ZSB9ID0gdGhpcztcblxuICAgIHdyaXRlci53cml0ZVVJbnQzMkxFKHRoaXMubWFnaWMpO1xuICAgIHdyaXRlci53cml0ZUZpeGVkU3RyaW5nKHZhbHVlLmNvbW1hbmQsIENPTU1BTkRfTEVOR1RIKTtcblxuICAgIGxldCBwYXlsb2FkID0gQnVmZmVyLmFsbG9jKDApO1xuICAgIHN3aXRjaCAodmFsdWUuY29tbWFuZCkge1xuICAgICAgY2FzZSBDb21tYW5kLmFkZHI6XG4gICAgICAgIHBheWxvYWQgPSB2YWx1ZS5wYXlsb2FkLnNlcmlhbGl6ZVdpcmUoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuYmxvY2s6XG4gICAgICAgIHBheWxvYWQgPSB2YWx1ZS5wYXlsb2FkLnNlcmlhbGl6ZVdpcmUoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuY29uc2Vuc3VzOlxuICAgICAgICBwYXlsb2FkID0gdmFsdWUucGF5bG9hZC5zZXJpYWxpemVXaXJlKCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmFkZDpcbiAgICAgICAgcGF5bG9hZCA9IHZhbHVlLnBheWxvYWQuc2VyaWFsaXplV2lyZSgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5maWx0ZXJjbGVhcjpcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuZmlsdGVybG9hZDpcbiAgICAgICAgcGF5bG9hZCA9IHZhbHVlLnBheWxvYWQuc2VyaWFsaXplV2lyZSgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5nZXRhZGRyOlxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5nZXRibG9ja3M6XG4gICAgICAgIHBheWxvYWQgPSB2YWx1ZS5wYXlsb2FkLnNlcmlhbGl6ZVdpcmUoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuZ2V0ZGF0YTpcbiAgICAgICAgcGF5bG9hZCA9IHZhbHVlLnBheWxvYWQuc2VyaWFsaXplV2lyZSgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5nZXRoZWFkZXJzOlxuICAgICAgICBwYXlsb2FkID0gdmFsdWUucGF5bG9hZC5zZXJpYWxpemVXaXJlKCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLmhlYWRlcnM6XG4gICAgICAgIHBheWxvYWQgPSB2YWx1ZS5wYXlsb2FkLnNlcmlhbGl6ZVdpcmUoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQuaW52OlxuICAgICAgICBwYXlsb2FkID0gdmFsdWUucGF5bG9hZC5zZXJpYWxpemVXaXJlKCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLm1lbXBvb2w6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnR4OlxuICAgICAgICBwYXlsb2FkID0gdmFsdWUucGF5bG9hZC5zZXJpYWxpemVXaXJlKCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnZlcmFjazpcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQudmVyc2lvbjpcbiAgICAgICAgcGF5bG9hZCA9IHZhbHVlLnBheWxvYWQuc2VyaWFsaXplV2lyZSgpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgQ29tbWFuZC5hbGVydDpcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQubWVya2xlYmxvY2s6XG4gICAgICAgIHBheWxvYWQgPSB2YWx1ZS5wYXlsb2FkLnNlcmlhbGl6ZVdpcmUoKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIENvbW1hbmQubm90Zm91bmQ6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnBpbmc6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnBvbmc6XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBDb21tYW5kLnJlamVjdDpcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB1dGlscy5hc3NlcnROZXZlcih2YWx1ZSk7XG4gICAgICAgIHRocm93IG5ldyBJbnZhbGlkRm9ybWF0RXJyb3IoJ0NvbW1hbmQgZG9lcyBub3QgZXhpc3QnKTtcbiAgICB9XG5cbiAgICB3cml0ZXIud3JpdGVVSW50MzJMRShwYXlsb2FkLmxlbmd0aCk7XG4gICAgd3JpdGVyLndyaXRlVUludDMyTEUoY2FsY3VsYXRlQ2hlY2tzdW0ocGF5bG9hZCkpO1xuICAgIHdyaXRlci53cml0ZUJ5dGVzKHBheWxvYWQpO1xuICB9XG59XG5cbmV4cG9ydCBjb25zdCBJbnZhbGlkTWVzc2FnZVRyYW5zZm9ybUVuY29kaW5nRXJyb3IgPSBtYWtlRXJyb3JXaXRoQ29kZShcbiAgJ0lOVkFMSURfTUVTU0FHRV9UUkFOU0ZPUk1fRU5DT0RJTkcnLFxuICAobWVzc2FnZTogc3RyaW5nKSA9PiBtZXNzYWdlLFxuKTtcblxuY29uc3QgU0laRV9PRl9NRVNTQUdFX0hFQURFUiA9XG4gIElPSGVscGVyLnNpemVPZlVJbnQzMkxFICtcbiAgSU9IZWxwZXIuc2l6ZU9mRml4ZWRTdHJpbmcoQ09NTUFORF9MRU5HVEgpICtcbiAgSU9IZWxwZXIuc2l6ZU9mVUludDMyTEUgK1xuICBJT0hlbHBlci5zaXplT2ZVSW50MzJMRTtcblxuZXhwb3J0IGNsYXNzIE1lc3NhZ2VUcmFuc2Zvcm0gZXh0ZW5kcyBUcmFuc2Zvcm0ge1xuICBwdWJsaWMgcmVhZG9ubHkgY29udGV4dDogRGVzZXJpYWxpemVXaXJlQ29udGV4dDtcbiAgcHVibGljIG11dGFibGVCdWZmZXI6IEJ1ZmZlcjtcblxuICBwdWJsaWMgY29uc3RydWN0b3IoY29udGV4dDogRGVzZXJpYWxpemVXaXJlQ29udGV4dCkge1xuICAgIHN1cGVyKHsgcmVhZGFibGVPYmplY3RNb2RlOiB0cnVlIH0pO1xuICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgdGhpcy5tdXRhYmxlQnVmZmVyID0gQnVmZmVyLmZyb20oW10pO1xuICB9XG5cbiAgcHVibGljIF90cmFuc2Zvcm0oXG4gICAgY2h1bms6IEJ1ZmZlciB8IHN0cmluZyxcbiAgICBlbmNvZGluZzogc3RyaW5nLFxuICAgIGNhbGxiYWNrOiAoZXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkLCBkYXRhPzogQnVmZmVyIHwgc3RyaW5nKSA9PiB2b2lkLFxuICApOiB2b2lkIHtcbiAgICBpZiAodHlwZW9mIGNodW5rID09PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRNZXNzYWdlVHJhbnNmb3JtRW5jb2RpbmdFcnJvcihcbiAgICAgICAgYEludmFsaWQgTWVzc2FnZSBUcmFuc2Zvcm0gQ2h1bmsgVHlwZS4gRXhwZWN0ZWQgY2h1bmsgdHlwZSB0byBiZSAnc3RyaW5nJywgZm91bmQ6ICR7dHlwZW9mIGNodW5rfWAsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoZW5jb2RpbmcgIT09ICdidWZmZXInKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZE1lc3NhZ2VUcmFuc2Zvcm1FbmNvZGluZ0Vycm9yKFxuICAgICAgICBgSW52YWxpZCBNZXNzYWdlIFRyYW5zZm9ybSBFbmNvZGluZy4gRXhwZWN0ZWQ6ICdidWZmZXInLCBmb3VuZDogJHtlbmNvZGluZ31gLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aGlzLm11dGFibGVCdWZmZXIgPSBCdWZmZXIuY29uY2F0KFt0aGlzLm11dGFibGVCdWZmZXIsIGNodW5rXSk7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgcmVtYWluaW5nQnVmZmVyLCBtdXRhYmxlTWVzc2FnZXMgfSA9IHRoaXMucHJvY2Vzc0J1ZmZlcihuZXcgQmluYXJ5UmVhZGVyKHRoaXMubXV0YWJsZUJ1ZmZlcikpO1xuXG4gICAgICB0aGlzLm11dGFibGVCdWZmZXIgPSByZW1haW5pbmdCdWZmZXI7XG4gICAgICBtdXRhYmxlTWVzc2FnZXMuZm9yRWFjaCgobWVzc2FnZSkgPT4gdGhpcy5wdXNoKG1lc3NhZ2UpKTtcbiAgICAgIGNhbGxiYWNrKHVuZGVmaW5lZCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNhbGxiYWNrKGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHByb2Nlc3NCdWZmZXIoXG4gICAgcmVhZGVyOiBCaW5hcnlSZWFkZXIsXG4gICk6IHtcbiAgICByZWFkb25seSByZW1haW5pbmdCdWZmZXI6IEJ1ZmZlcjtcbiAgICByZWFkb25seSBtdXRhYmxlTWVzc2FnZXM6IE1lc3NhZ2VbXTtcbiAgfSB7XG4gICAgaWYgKHJlYWRlci5yZW1haW5pbmcgPCBTSVpFX09GX01FU1NBR0VfSEVBREVSKSB7XG4gICAgICByZXR1cm4geyByZW1haW5pbmdCdWZmZXI6IHJlYWRlci5yZW1haW5pbmdCdWZmZXIsIG11dGFibGVNZXNzYWdlczogW10gfTtcbiAgICB9XG5cbiAgICBjb25zdCB7IGxlbmd0aCB9ID0gZGVzZXJpYWxpemVNZXNzYWdlSGVhZGVyKHtcbiAgICAgIGNvbnRleHQ6IHRoaXMuY29udGV4dCxcbiAgICAgIHJlYWRlcjogcmVhZGVyLmNsb25lKCksXG4gICAgfSk7XG5cbiAgICBpZiAocmVhZGVyLnJlbWFpbmluZyA8IFNJWkVfT0ZfTUVTU0FHRV9IRUFERVIgKyBsZW5ndGgpIHtcbiAgICAgIHJldHVybiB7IHJlbWFpbmluZ0J1ZmZlcjogcmVhZGVyLnJlbWFpbmluZ0J1ZmZlciwgbXV0YWJsZU1lc3NhZ2VzOiBbXSB9O1xuICAgIH1cblxuICAgIGNvbnN0IG1lc3NhZ2UgPSBNZXNzYWdlLmRlc2VyaWFsaXplV2lyZUJhc2Uoe1xuICAgICAgY29udGV4dDogdGhpcy5jb250ZXh0LFxuICAgICAgcmVhZGVyLFxuICAgIH0pO1xuXG4gICAgY29uc3QgeyByZW1haW5pbmdCdWZmZXIsIG11dGFibGVNZXNzYWdlcyB9ID0gdGhpcy5wcm9jZXNzQnVmZmVyKHJlYWRlcik7XG4gICAgbXV0YWJsZU1lc3NhZ2VzLnB1c2gobWVzc2FnZSk7XG5cbiAgICByZXR1cm4geyByZW1haW5pbmdCdWZmZXIsIG11dGFibGVNZXNzYWdlcyB9O1xuICB9XG59XG4iXX0=