UNPKG

35.4 kBJavaScriptView Raw
1import { common, crypto, InvalidFormatError, IOHelper, } from '@neo-one/client-common-esnext-esm';
2import { BlockBase } from './BlockBase';
3import { MerkleTree } from './crypto';
4import { VerifyError } from './errors';
5import { Header } from './Header';
6import { ScriptContainerType } from './ScriptContainer';
7import { deserializeTransactionWireBase, TransactionType, } from './transaction';
8import { BinaryReader, utils } from './utils';
9export class Block extends BlockBase {
10 constructor({ version, previousHash, timestamp, index, consensusData, nextConsensus, script, hash, transactions, merkleRoot = MerkleTree.computeRoot(transactions.map((transaction) => transaction.hash)), }) {
11 super({
12 version,
13 previousHash,
14 merkleRoot,
15 timestamp,
16 index,
17 consensusData,
18 nextConsensus,
19 script,
20 hash,
21 });
22 this.sizeExclusive = utils.lazy(() => IOHelper.sizeOfArray(this.transactions, (transaction) => transaction.size));
23 this.headerInternal = utils.lazy(() => new Header({
24 version: this.version,
25 previousHash: this.previousHash,
26 merkleRoot: this.merkleRoot,
27 timestamp: this.timestamp,
28 index: this.index,
29 consensusData: this.consensusData,
30 nextConsensus: this.nextConsensus,
31 script: this.script,
32 }));
33 this.transactions = transactions;
34 }
35 static async calculateNetworkFee(context, transactions) {
36 const fees = await Promise.all(transactions.map(async (transaction) => transaction.getNetworkFee(context)));
37 return fees.reduce((acc, fee) => acc.add(fee), utils.ZERO);
38 }
39 static deserializeWireBase(options) {
40 const { reader } = options;
41 const blockBase = super.deserializeBlockBaseWireBase(options);
42 const transactions = reader.readArray(() => deserializeTransactionWireBase(options), 0x10000);
43 if (transactions.length === 0) {
44 throw new InvalidFormatError('Expected at least one transcaction in the block');
45 }
46 const merkleRoot = MerkleTree.computeRoot(transactions.map((transaction) => transaction.hash));
47 if (!common.uInt256Equal(merkleRoot, blockBase.merkleRoot)) {
48 throw new InvalidFormatError('Invalid merkle root');
49 }
50 return new this({
51 version: blockBase.version,
52 previousHash: blockBase.previousHash,
53 merkleRoot: blockBase.merkleRoot,
54 timestamp: blockBase.timestamp,
55 index: blockBase.index,
56 consensusData: blockBase.consensusData,
57 nextConsensus: blockBase.nextConsensus,
58 script: blockBase.script,
59 transactions,
60 });
61 }
62 static deserializeWire(options) {
63 return this.deserializeWireBase({
64 context: options.context,
65 reader: new BinaryReader(options.buffer),
66 });
67 }
68 get header() {
69 return this.headerInternal();
70 }
71 clone({ transactions, script, }) {
72 return new Block({
73 version: this.version,
74 previousHash: this.previousHash,
75 merkleRoot: this.merkleRoot,
76 timestamp: this.timestamp,
77 index: this.index,
78 consensusData: this.consensusData,
79 nextConsensus: this.nextConsensus,
80 transactions,
81 script,
82 });
83 }
84 async getNetworkFee(context) {
85 return Block.calculateNetworkFee(context, this.transactions);
86 }
87 getSystemFee(context) {
88 return this.transactions.reduce((acc, transaction) => acc.add(transaction.getSystemFee(context)), utils.ZERO);
89 }
90 async verify(options) {
91 const { completely = false } = options;
92 if (this.transactions.length === 0 ||
93 this.transactions[0].type !== TransactionType.Miner ||
94 this.transactions.slice(1).some((transaction) => transaction.type === TransactionType.Miner)) {
95 throw new VerifyError('Invalid miner transaction in block.');
96 }
97 await Promise.all([this.verifyBase(options), completely ? this.verifyComplete(options) : Promise.resolve()]);
98 }
99 serializeWireBase(writer) {
100 super.serializeWireBase(writer);
101 writer.writeArray(this.transactions, (transaction) => transaction.serializeWireBase(writer));
102 }
103 async serializeJSON(context) {
104 const blockBaseJSON = super.serializeBlockBaseJSON(context);
105 return {
106 version: blockBaseJSON.version,
107 hash: blockBaseJSON.hash,
108 previousblockhash: blockBaseJSON.previousblockhash,
109 merkleroot: blockBaseJSON.merkleroot,
110 time: blockBaseJSON.time,
111 index: blockBaseJSON.index,
112 nonce: blockBaseJSON.nonce,
113 nextconsensus: blockBaseJSON.nextconsensus,
114 script: blockBaseJSON.script,
115 tx: await Promise.all(this.transactions.map((transaction) => transaction.serializeJSON(context))),
116 size: blockBaseJSON.size,
117 confirmations: blockBaseJSON.confirmations,
118 };
119 }
120 async verifyBase({ genesisBlock, tryGetBlock, tryGetHeader, verifyScript, }) {
121 if (common.uInt256Equal(this.hash, genesisBlock.hash)) {
122 return;
123 }
124 const existingBlock = await tryGetBlock({ hashOrIndex: this.hash });
125 if (existingBlock !== undefined) {
126 return;
127 }
128 const previousHeader = await tryGetHeader({
129 hashOrIndex: this.previousHash,
130 });
131 if (previousHeader === undefined) {
132 throw new VerifyError('Previous header does not exist.');
133 }
134 if (previousHeader.index + 1 !== this.index) {
135 throw new VerifyError('Previous index + 1 does not match index.');
136 }
137 if (previousHeader.timestamp >= this.timestamp) {
138 throw new VerifyError('Previous timestamp is greater than block.');
139 }
140 const { failureMessage } = await verifyScript({
141 scriptContainer: { type: ScriptContainerType.Block, value: this },
142 hash: previousHeader.nextConsensus,
143 witness: this.script,
144 });
145 if (failureMessage !== undefined) {
146 throw new VerifyError(failureMessage);
147 }
148 }
149 async verifyComplete(options) {
150 await Promise.all([
151 this.verifyConsensus(options),
152 this.verifyTransactions(options),
153 this.verifyNetworkFee(options),
154 ]);
155 }
156 async verifyConsensus({ getValidators }) {
157 const validators = await getValidators(this.transactions);
158 if (!common.uInt160Equal(this.nextConsensus, crypto.getConsensusAddress(validators))) {
159 throw new VerifyError('Invalid next consensus address');
160 }
161 }
162 async verifyTransactions(options) {
163 const results = await Promise.all(this.transactions.map(async (transaction) => transaction.verify({
164 isSpent: options.isSpent,
165 getAsset: options.getAsset,
166 getOutput: options.getOutput,
167 tryGetAccount: options.tryGetAccount,
168 calculateClaimAmount: options.calculateClaimAmount,
169 standbyValidators: options.standbyValidators,
170 getAllValidators: options.getAllValidators,
171 verifyScript: options.verifyScript,
172 currentHeight: options.currentHeight,
173 governingToken: options.governingToken,
174 utilityToken: options.utilityToken,
175 fees: options.fees,
176 registerValidatorFee: options.registerValidatorFee,
177 })));
178 const failureResults = results.filter((verifyResults) => verifyResults.some(({ failureMessage }) => failureMessage !== undefined));
179 if (failureResults.length > 0) {
180 const failureResult = failureResults[0].find(({ failureMessage }) => failureMessage !== undefined);
181 if (failureResult !== undefined && failureResult.failureMessage !== undefined) {
182 throw new VerifyError(failureResult.failureMessage);
183 }
184 }
185 }
186 async verifyNetworkFee(options) {
187 const networkFee = await this.getNetworkFee({
188 getOutput: options.getOutput,
189 governingToken: options.governingToken,
190 utilityToken: options.utilityToken,
191 fees: options.fees,
192 registerValidatorFee: options.registerValidatorFee,
193 });
194 const minerTransaction = this.transactions.find((transaction) => transaction.type === TransactionType.Miner);
195 if (minerTransaction === undefined) {
196 throw new VerifyError('Missing miner transaction');
197 }
198 const minerTransactionNetworkFee = minerTransaction.outputs.reduce((acc, output) => acc.add(output.value), utils.ZERO);
199 if (!networkFee.eq(minerTransactionNetworkFee)) {
200 throw new VerifyError('Miner output does not equal network fee.');
201 }
202 }
203}
204
205//# sourceMappingURL=data:application/json;charset=utf8;base64,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QUNILENBQUM7SUFFTyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsT0FBMkI7UUFDeEQsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQzFDLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztZQUM1QixjQUFjLEVBQUUsT0FBTyxDQUFDLGNBQWM7WUFDdEMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1lBQ2xDLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixvQkFBb0IsRUFBRSxPQUFPLENBQUMsb0JBQW9CO1NBQ25ELENBQUMsQ0FBQztRQUVILE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEtBQUssZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTdHLElBQUksZ0JBQWdCLEtBQUssU0FBUyxFQUFFO1lBQ2xDLE1BQU0sSUFBSSxXQUFXLENBQUMsMkJBQTJCLENBQUMsQ0FBQztTQUNwRDtRQUVELE1BQU0sMEJBQTBCLEdBQUcsZ0JBQWdCLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FDaEUsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFDdEMsS0FBSyxDQUFDLElBQUksQ0FDWCxDQUFDO1FBRUYsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsMEJBQTBCLENBQUMsRUFBRTtZQUM5QyxNQUFNLElBQUksV0FBVyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7U0FDbkU7SUFDSCxDQUFDO0NBQ0YiLCJmaWxlIjoibmVvLW9uZS1ub2RlLWNvcmUvc3JjL0Jsb2NrLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQmluYXJ5V3JpdGVyLFxuICBCbG9ja0pTT04sXG4gIGNvbW1vbixcbiAgY3J5cHRvLFxuICBFQ1BvaW50LFxuICBJbnZhbGlkRm9ybWF0RXJyb3IsXG4gIElPSGVscGVyLFxuICBUcmFuc2FjdGlvbkpTT04sXG4gIFVJbnQxNjAsXG4gIFVJbnQyNTYsXG59IGZyb20gJ0BuZW8tb25lL2NsaWVudC1jb21tb24tZXNuZXh0LWVzbSc7XG5pbXBvcnQgQk4gZnJvbSAnYm4uanMnO1xuaW1wb3J0IHsgQWNjb3VudCwgQWNjb3VudEtleSB9IGZyb20gJy4vQWNjb3VudCc7XG5pbXBvcnQgeyBBc3NldCwgQXNzZXRLZXkgfSBmcm9tICcuL0Fzc2V0JztcbmltcG9ydCB7IEJsb2NrQmFzZSB9IGZyb20gJy4vQmxvY2tCYXNlJztcbmltcG9ydCB7IE1lcmtsZVRyZWUgfSBmcm9tICcuL2NyeXB0byc7XG5pbXBvcnQgeyBWZXJpZnlFcnJvciB9IGZyb20gJy4vZXJyb3JzJztcbmltcG9ydCB7IEhlYWRlciwgSGVhZGVyS2V5IH0gZnJvbSAnLi9IZWFkZXInO1xuaW1wb3J0IHsgU2NyaXB0Q29udGFpbmVyVHlwZSB9IGZyb20gJy4vU2NyaXB0Q29udGFpbmVyJztcbmltcG9ydCB7XG4gIERlc2VyaWFsaXplV2lyZUJhc2VPcHRpb25zLFxuICBEZXNlcmlhbGl6ZVdpcmVPcHRpb25zLFxuICBTZXJpYWxpemFibGVKU09OLFxuICBTZXJpYWxpemFibGVXaXJlLFxuICBTZXJpYWxpemVKU09OQ29udGV4dCxcbn0gZnJvbSAnLi9TZXJpYWxpemFibGUnO1xuaW1wb3J0IHtcbiAgZGVzZXJpYWxpemVUcmFuc2FjdGlvbldpcmVCYXNlLFxuICBGZWVDb250ZXh0LFxuICBJbnB1dCxcbiAgT3V0cHV0LFxuICBPdXRwdXRLZXksXG4gIFJlZ2lzdGVyVHJhbnNhY3Rpb24sXG4gIFRyYW5zYWN0aW9uLFxuICBUcmFuc2FjdGlvblR5cGUsXG59IGZyb20gJy4vdHJhbnNhY3Rpb24nO1xuaW1wb3J0IHsgQmluYXJ5UmVhZGVyLCB1dGlscyB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgVmFsaWRhdG9yIH0gZnJvbSAnLi9WYWxpZGF0b3InO1xuaW1wb3J0IHsgVmVyaWZ5U2NyaXB0IH0gZnJvbSAnLi92bSc7XG5pbXBvcnQgeyBXaXRuZXNzIH0gZnJvbSAnLi9XaXRuZXNzJztcblxuZXhwb3J0IGludGVyZmFjZSBCbG9ja0FkZCB7XG4gIHJlYWRvbmx5IHZlcnNpb24/OiBudW1iZXI7XG4gIHJlYWRvbmx5IHByZXZpb3VzSGFzaDogVUludDI1NjtcbiAgcmVhZG9ubHkgbWVya2xlUm9vdD86IFVJbnQyNTY7XG4gIHJlYWRvbmx5IHRpbWVzdGFtcDogbnVtYmVyO1xuICByZWFkb25seSBpbmRleDogbnVtYmVyO1xuICByZWFkb25seSBjb25zZW5zdXNEYXRhOiBCTjtcbiAgcmVhZG9ubHkgbmV4dENvbnNlbnN1czogVUludDE2MDtcbiAgcmVhZG9ubHkgc2NyaXB0PzogV2l0bmVzcztcbiAgcmVhZG9ubHkgaGFzaD86IFVJbnQyNTY7XG4gIHJlYWRvbmx5IHRyYW5zYWN0aW9uczogUmVhZG9ubHlBcnJheTxUcmFuc2FjdGlvbj47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmxvY2tLZXkge1xuICByZWFkb25seSBoYXNoT3JJbmRleDogVUludDI1NiB8IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBCbG9ja1ZlcmlmeU9wdGlvbnMge1xuICByZWFkb25seSBnZW5lc2lzQmxvY2s6IEJsb2NrO1xuICByZWFkb25seSB0cnlHZXRCbG9jazogKGJsb2NrOiBCbG9ja0tleSkgPT4gUHJvbWlzZTxCbG9jayB8IHVuZGVmaW5lZD47XG4gIHJlYWRvbmx5IHRyeUdldEhlYWRlcjogKGhlYWRlcjogSGVhZGVyS2V5KSA9PiBQcm9taXNlPEhlYWRlciB8IHVuZGVmaW5lZD47XG4gIHJlYWRvbmx5IGlzU3BlbnQ6IChrZXk6IE91dHB1dEtleSkgPT4gUHJvbWlzZTxib29sZWFuPjtcbiAgcmVhZG9ubHkgZ2V0QXNzZXQ6IChrZXk6IEFzc2V0S2V5KSA9PiBQcm9taXNlPEFzc2V0PjtcbiAgcmVhZG9ubHkgZ2V0T3V0cHV0OiAoa2V5OiBPdXRwdXRLZXkpID0+IFByb21pc2U8T3V0cHV0PjtcbiAgcmVhZG9ubHkgdHJ5R2V0QWNjb3VudDogKGtleTogQWNjb3VudEtleSkgPT4gUHJvbWlzZTxBY2NvdW50IHwgdW5kZWZpbmVkPjtcbiAgcmVhZG9ubHkgZ2V0VmFsaWRhdG9yczogKHRyYW5zYWN0aW9uczogUmVhZG9ubHlBcnJheTxUcmFuc2FjdGlvbj4pID0+IFByb21pc2U8UmVhZG9ubHlBcnJheTxFQ1BvaW50Pj47XG4gIHJlYWRvbmx5IHN0YW5kYnlWYWxpZGF0b3JzOiBSZWFkb25seUFycmF5PEVDUG9pbnQ+O1xuICByZWFkb25seSBnZXRBbGxWYWxpZGF0b3JzOiAoKSA9PiBQcm9taXNlPFJlYWRvbmx5QXJyYXk8VmFsaWRhdG9yPj47XG4gIHJlYWRvbmx5IGNhbGN1bGF0ZUNsYWltQW1vdW50OiAoaW5wdXRzOiBSZWFkb25seUFycmF5PElucHV0PikgPT4gUHJvbWlzZTxCTj47XG4gIHJlYWRvbmx5IHZlcmlmeVNjcmlwdDogVmVyaWZ5U2NyaXB0O1xuICByZWFkb25seSBjdXJyZW50SGVpZ2h0OiBudW1iZXI7XG4gIHJlYWRvbmx5IGdvdmVybmluZ1Rva2VuOiBSZWdpc3RlclRyYW5zYWN0aW9uO1xuICByZWFkb25seSB1dGlsaXR5VG9rZW46IFJlZ2lzdGVyVHJhbnNhY3Rpb247XG4gIHJlYWRvbmx5IGZlZXM6IHsgW0sgaW4gVHJhbnNhY3Rpb25UeXBlXT86IEJOIH07XG4gIHJlYWRvbmx5IHJlZ2lzdGVyVmFsaWRhdG9yRmVlOiBCTjtcbiAgcmVhZG9ubHkgY29tcGxldGVseT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBCbG9jayBleHRlbmRzIEJsb2NrQmFzZSBpbXBsZW1lbnRzIFNlcmlhbGl6YWJsZVdpcmU8QmxvY2s+LCBTZXJpYWxpemFibGVKU09OPEJsb2NrSlNPTj4ge1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIGNhbGN1bGF0ZU5ldHdvcmtGZWUoY29udGV4dDogRmVlQ29udGV4dCwgdHJhbnNhY3Rpb25zOiBSZWFkb25seUFycmF5PFRyYW5zYWN0aW9uPik6IFByb21pc2U8Qk4+IHtcbiAgICBjb25zdCBmZWVzID0gYXdhaXQgUHJvbWlzZS5hbGwodHJhbnNhY3Rpb25zLm1hcChhc3luYyAodHJhbnNhY3Rpb24pID0+IHRyYW5zYWN0aW9uLmdldE5ldHdvcmtGZWUoY29udGV4dCkpKTtcblxuICAgIHJldHVybiBmZWVzLnJlZHVjZSgoYWNjLCBmZWUpID0+IGFjYy5hZGQoZmVlKSwgdXRpbHMuWkVSTyk7XG4gIH1cblxuICBwdWJsaWMgc3RhdGljIGRlc2VyaWFsaXplV2lyZUJhc2Uob3B0aW9uczogRGVzZXJpYWxpemVXaXJlQmFzZU9wdGlvbnMpOiBCbG9jayB7XG4gICAgY29uc3QgeyByZWFkZXIgfSA9IG9wdGlvbnM7XG4gICAgY29uc3QgYmxvY2tCYXNlID0gc3VwZXIuZGVzZXJpYWxpemVCbG9ja0Jhc2VXaXJlQmFzZShvcHRpb25zKTtcbiAgICBjb25zdCB0cmFuc2FjdGlvbnMgPSByZWFkZXIucmVhZEFycmF5KCgpID0+IGRlc2VyaWFsaXplVHJhbnNhY3Rpb25XaXJlQmFzZShvcHRpb25zKSwgMHgxMDAwMCk7XG5cbiAgICBpZiAodHJhbnNhY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRGb3JtYXRFcnJvcignRXhwZWN0ZWQgYXQgbGVhc3Qgb25lIHRyYW5zY2FjdGlvbiBpbiB0aGUgYmxvY2snKTtcbiAgICB9XG5cbiAgICBjb25zdCBtZXJrbGVSb290ID0gTWVya2xlVHJlZS5jb21wdXRlUm9vdCh0cmFuc2FjdGlvbnMubWFwKCh0cmFuc2FjdGlvbikgPT4gdHJhbnNhY3Rpb24uaGFzaCkpO1xuXG4gICAgaWYgKCFjb21tb24udUludDI1NkVxdWFsKG1lcmtsZVJvb3QsIGJsb2NrQmFzZS5tZXJrbGVSb290KSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRGb3JtYXRFcnJvcignSW52YWxpZCBtZXJrbGUgcm9vdCcpO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgdGhpcyh7XG4gICAgICB2ZXJzaW9uOiBibG9ja0Jhc2UudmVyc2lvbixcbiAgICAgIHByZXZpb3VzSGFzaDogYmxvY2tCYXNlLnByZXZpb3VzSGFzaCxcbiAgICAgIG1lcmtsZVJvb3Q6IGJsb2NrQmFzZS5tZXJrbGVSb290LFxuICAgICAgdGltZXN0YW1wOiBibG9ja0Jhc2UudGltZXN0YW1wLFxuICAgICAgaW5kZXg6IGJsb2NrQmFzZS5pbmRleCxcbiAgICAgIGNvbnNlbnN1c0RhdGE6IGJsb2NrQmFzZS5jb25zZW5zdXNEYXRhLFxuICAgICAgbmV4dENvbnNlbnN1czogYmxvY2tCYXNlLm5leHRDb25zZW5zdXMsXG4gICAgICBzY3JpcHQ6IGJsb2NrQmFzZS5zY3JpcHQsXG4gICAgICB0cmFuc2FjdGlvbnMsXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgc3RhdGljIGRlc2VyaWFsaXplV2lyZShvcHRpb25zOiBEZXNlcmlhbGl6ZVdpcmVPcHRpb25zKTogQmxvY2sge1xuICAgIHJldHVybiB0aGlzLmRlc2VyaWFsaXplV2lyZUJhc2Uoe1xuICAgICAgY29udGV4dDogb3B0aW9ucy5jb250ZXh0LFxuICAgICAgcmVhZGVyOiBuZXcgQmluYXJ5UmVhZGVyKG9wdGlvbnMuYnVmZmVyKSxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSB0cmFuc2FjdGlvbnM6IFJlYWRvbmx5QXJyYXk8VHJhbnNhY3Rpb24+O1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc2l6ZUV4Y2x1c2l2ZSA9IHV0aWxzLmxhenkoKCkgPT5cbiAgICBJT0hlbHBlci5zaXplT2ZBcnJheSh0aGlzLnRyYW5zYWN0aW9ucywgKHRyYW5zYWN0aW9uKSA9PiB0cmFuc2FjdGlvbi5zaXplKSxcbiAgKTtcbiAgcHJpdmF0ZSByZWFkb25seSBoZWFkZXJJbnRlcm5hbCA9IHV0aWxzLmxhenkoXG4gICAgKCkgPT5cbiAgICAgIG5ldyBIZWFkZXIoe1xuICAgICAgICB2ZXJzaW9uOiB0aGlzLnZlcnNpb24sXG4gICAgICAgIHByZXZpb3VzSGFzaDogdGhpcy5wcmV2aW91c0hhc2gsXG4gICAgICAgIG1lcmtsZVJvb3Q6IHRoaXMubWVya2xlUm9vdCxcbiAgICAgICAgdGltZXN0YW1wOiB0aGlzLnRpbWVzdGFtcCxcbiAgICAgICAgaW5kZXg6IHRoaXMuaW5kZXgsXG4gICAgICAgIGNvbnNlbnN1c0RhdGE6IHRoaXMuY29uc2Vuc3VzRGF0YSxcbiAgICAgICAgbmV4dENvbnNlbnN1czogdGhpcy5uZXh0Q29uc2Vuc3VzLFxuICAgICAgICBzY3JpcHQ6IHRoaXMuc2NyaXB0LFxuICAgICAgfSksXG4gICk7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHtcbiAgICB2ZXJzaW9uLFxuICAgIHByZXZpb3VzSGFzaCxcbiAgICB0aW1lc3RhbXAsXG4gICAgaW5kZXgsXG4gICAgY29uc2Vuc3VzRGF0YSxcbiAgICBuZXh0Q29uc2Vuc3VzLFxuICAgIHNjcmlwdCxcbiAgICBoYXNoLFxuICAgIHRyYW5zYWN0aW9ucyxcbiAgICBtZXJrbGVSb290ID0gTWVya2xlVHJlZS5jb21wdXRlUm9vdCh0cmFuc2FjdGlvbnMubWFwKCh0cmFuc2FjdGlvbikgPT4gdHJhbnNhY3Rpb24uaGFzaCkpLFxuICB9OiBCbG9ja0FkZCkge1xuICAgIHN1cGVyKHtcbiAgICAgIHZlcnNpb24sXG4gICAgICBwcmV2aW91c0hhc2gsXG4gICAgICBtZXJrbGVSb290LFxuICAgICAgdGltZXN0YW1wLFxuICAgICAgaW5kZXgsXG4gICAgICBjb25zZW5zdXNEYXRhLFxuICAgICAgbmV4dENvbnNlbnN1cyxcbiAgICAgIHNjcmlwdCxcbiAgICAgIGhhc2gsXG4gICAgfSk7XG5cbiAgICB0aGlzLnRyYW5zYWN0aW9ucyA9IHRyYW5zYWN0aW9ucztcbiAgfVxuXG4gIHB1YmxpYyBnZXQgaGVhZGVyKCk6IEhlYWRlciB7XG4gICAgcmV0dXJuIHRoaXMuaGVhZGVySW50ZXJuYWwoKTtcbiAgfVxuXG4gIHB1YmxpYyBjbG9uZSh7XG4gICAgdHJhbnNhY3Rpb25zLFxuICAgIHNjcmlwdCxcbiAgfToge1xuICAgIHJlYWRvbmx5IHRyYW5zYWN0aW9uczogUmVhZG9ubHlBcnJheTxUcmFuc2FjdGlvbj47XG4gICAgcmVhZG9ubHkgc2NyaXB0OiBXaXRuZXNzO1xuICB9KTogQmxvY2sge1xuICAgIHJldHVybiBuZXcgQmxvY2soe1xuICAgICAgdmVyc2lvbjogdGhpcy52ZXJzaW9uLFxuICAgICAgcHJldmlvdXNIYXNoOiB0aGlzLnByZXZpb3VzSGFzaCxcbiAgICAgIG1lcmtsZVJvb3Q6IHRoaXMubWVya2xlUm9vdCxcbiAgICAgIHRpbWVzdGFtcDogdGhpcy50aW1lc3RhbXAsXG4gICAgICBpbmRleDogdGhpcy5pbmRleCxcbiAgICAgIGNvbnNlbnN1c0RhdGE6IHRoaXMuY29uc2Vuc3VzRGF0YSxcbiAgICAgIG5leHRDb25zZW5zdXM6IHRoaXMubmV4dENvbnNlbnN1cyxcbiAgICAgIHRyYW5zYWN0aW9ucyxcbiAgICAgIHNjcmlwdCxcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBnZXROZXR3b3JrRmVlKGNvbnRleHQ6IEZlZUNvbnRleHQpOiBQcm9taXNlPEJOPiB7XG4gICAgcmV0dXJuIEJsb2NrLmNhbGN1bGF0ZU5ldHdvcmtGZWUoY29udGV4dCwgdGhpcy50cmFuc2FjdGlvbnMpO1xuICB9XG5cbiAgcHVibGljIGdldFN5c3RlbUZlZShjb250ZXh0OiBGZWVDb250ZXh0KTogQk4ge1xuICAgIHJldHVybiB0aGlzLnRyYW5zYWN0aW9ucy5yZWR1Y2UoKGFjYywgdHJhbnNhY3Rpb24pID0+IGFjYy5hZGQodHJhbnNhY3Rpb24uZ2V0U3lzdGVtRmVlKGNvbnRleHQpKSwgdXRpbHMuWkVSTyk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgdmVyaWZ5KG9wdGlvbnM6IEJsb2NrVmVyaWZ5T3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgY29tcGxldGVseSA9IGZhbHNlIH0gPSBvcHRpb25zO1xuXG4gICAgaWYgKFxuICAgICAgdGhpcy50cmFuc2FjdGlvbnMubGVuZ3RoID09PSAwIHx8XG4gICAgICB0aGlzLnRyYW5zYWN0aW9uc1swXS50eXBlICE9PSBUcmFuc2FjdGlvblR5cGUuTWluZXIgfHxcbiAgICAgIHRoaXMudHJhbnNhY3Rpb25zLnNsaWNlKDEpLnNvbWUoKHRyYW5zYWN0aW9uKSA9PiB0cmFuc2FjdGlvbi50eXBlID09PSBUcmFuc2FjdGlvblR5cGUuTWluZXIpXG4gICAgKSB7XG4gICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ0ludmFsaWQgbWluZXIgdHJhbnNhY3Rpb24gaW4gYmxvY2suJyk7XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW3RoaXMudmVyaWZ5QmFzZShvcHRpb25zKSwgY29tcGxldGVseSA/IHRoaXMudmVyaWZ5Q29tcGxldGUob3B0aW9ucykgOiBQcm9taXNlLnJlc29sdmUoKV0pO1xuICB9XG5cbiAgcHVibGljIHNlcmlhbGl6ZVdpcmVCYXNlKHdyaXRlcjogQmluYXJ5V3JpdGVyKTogdm9pZCB7XG4gICAgc3VwZXIuc2VyaWFsaXplV2lyZUJhc2Uod3JpdGVyKTtcbiAgICB3cml0ZXIud3JpdGVBcnJheSh0aGlzLnRyYW5zYWN0aW9ucywgKHRyYW5zYWN0aW9uKSA9PiB0cmFuc2FjdGlvbi5zZXJpYWxpemVXaXJlQmFzZSh3cml0ZXIpKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBzZXJpYWxpemVKU09OKGNvbnRleHQ6IFNlcmlhbGl6ZUpTT05Db250ZXh0KTogUHJvbWlzZTxCbG9ja0pTT04+IHtcbiAgICBjb25zdCBibG9ja0Jhc2VKU09OID0gc3VwZXIuc2VyaWFsaXplQmxvY2tCYXNlSlNPTihjb250ZXh0KTtcblxuICAgIHJldHVybiB7XG4gICAgICB2ZXJzaW9uOiBibG9ja0Jhc2VKU09OLnZlcnNpb24sXG4gICAgICBoYXNoOiBibG9ja0Jhc2VKU09OLmhhc2gsXG4gICAgICBwcmV2aW91c2Jsb2NraGFzaDogYmxvY2tCYXNlSlNPTi5wcmV2aW91c2Jsb2NraGFzaCxcbiAgICAgIG1lcmtsZXJvb3Q6IGJsb2NrQmFzZUpTT04ubWVya2xlcm9vdCxcbiAgICAgIHRpbWU6IGJsb2NrQmFzZUpTT04udGltZSxcbiAgICAgIGluZGV4OiBibG9ja0Jhc2VKU09OLmluZGV4LFxuICAgICAgbm9uY2U6IGJsb2NrQmFzZUpTT04ubm9uY2UsXG4gICAgICBuZXh0Y29uc2Vuc3VzOiBibG9ja0Jhc2VKU09OLm5leHRjb25zZW5zdXMsXG4gICAgICBzY3JpcHQ6IGJsb2NrQmFzZUpTT04uc2NyaXB0LFxuICAgICAgdHg6IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICB0aGlzLnRyYW5zYWN0aW9ucy5tYXAoXG4gICAgICAgICAgKHRyYW5zYWN0aW9uKSA9PiB0cmFuc2FjdGlvbi5zZXJpYWxpemVKU09OKGNvbnRleHQpIGFzIFRyYW5zYWN0aW9uSlNPTiB8IFByb21pc2VMaWtlPFRyYW5zYWN0aW9uSlNPTj4sXG4gICAgICAgICksXG4gICAgICApLFxuICAgICAgc2l6ZTogYmxvY2tCYXNlSlNPTi5zaXplLFxuICAgICAgY29uZmlybWF0aW9uczogYmxvY2tCYXNlSlNPTi5jb25maXJtYXRpb25zLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHZlcmlmeUJhc2Uoe1xuICAgIGdlbmVzaXNCbG9jayxcbiAgICB0cnlHZXRCbG9jayxcbiAgICB0cnlHZXRIZWFkZXIsXG4gICAgdmVyaWZ5U2NyaXB0LFxuICB9OiBCbG9ja1ZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoY29tbW9uLnVJbnQyNTZFcXVhbCh0aGlzLmhhc2gsIGdlbmVzaXNCbG9jay5oYXNoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGV4aXN0aW5nQmxvY2sgPSBhd2FpdCB0cnlHZXRCbG9jayh7IGhhc2hPckluZGV4OiB0aGlzLmhhc2ggfSk7XG4gICAgaWYgKGV4aXN0aW5nQmxvY2sgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHByZXZpb3VzSGVhZGVyID0gYXdhaXQgdHJ5R2V0SGVhZGVyKHtcbiAgICAgIGhhc2hPckluZGV4OiB0aGlzLnByZXZpb3VzSGFzaCxcbiAgICB9KTtcblxuICAgIGlmIChwcmV2aW91c0hlYWRlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ1ByZXZpb3VzIGhlYWRlciBkb2VzIG5vdCBleGlzdC4nKTtcbiAgICB9XG5cbiAgICBpZiAocHJldmlvdXNIZWFkZXIuaW5kZXggKyAxICE9PSB0aGlzLmluZGV4KSB7XG4gICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ1ByZXZpb3VzIGluZGV4ICsgMSBkb2VzIG5vdCBtYXRjaCBpbmRleC4nKTtcbiAgICB9XG5cbiAgICBpZiAocHJldmlvdXNIZWFkZXIudGltZXN0YW1wID49IHRoaXMudGltZXN0YW1wKSB7XG4gICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ1ByZXZpb3VzIHRpbWVzdGFtcCBpcyBncmVhdGVyIHRoYW4gYmxvY2suJyk7XG4gICAgfVxuXG4gICAgY29uc3QgeyBmYWlsdXJlTWVzc2FnZSB9ID0gYXdhaXQgdmVyaWZ5U2NyaXB0KHtcbiAgICAgIHNjcmlwdENvbnRhaW5lcjogeyB0eXBlOiBTY3JpcHRDb250YWluZXJUeXBlLkJsb2NrLCB2YWx1ZTogdGhpcyB9LFxuICAgICAgaGFzaDogcHJldmlvdXNIZWFkZXIubmV4dENvbnNlbnN1cyxcbiAgICAgIHdpdG5lc3M6IHRoaXMuc2NyaXB0LFxuICAgIH0pO1xuXG4gICAgaWYgKGZhaWx1cmVNZXNzYWdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBWZXJpZnlFcnJvcihmYWlsdXJlTWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlDb21wbGV0ZShvcHRpb25zOiBCbG9ja1ZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLnZlcmlmeUNvbnNlbnN1cyhvcHRpb25zKSxcbiAgICAgIHRoaXMudmVyaWZ5VHJhbnNhY3Rpb25zKG9wdGlvbnMpLFxuICAgICAgdGhpcy52ZXJpZnlOZXR3b3JrRmVlKG9wdGlvbnMpLFxuICAgIF0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlDb25zZW5zdXMoeyBnZXRWYWxpZGF0b3JzIH06IEJsb2NrVmVyaWZ5T3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHZhbGlkYXRvcnMgPSBhd2FpdCBnZXRWYWxpZGF0b3JzKHRoaXMudHJhbnNhY3Rpb25zKTtcbiAgICBpZiAoIWNvbW1vbi51SW50MTYwRXF1YWwodGhpcy5uZXh0Q29uc2Vuc3VzLCBjcnlwdG8uZ2V0Q29uc2Vuc3VzQWRkcmVzcyh2YWxpZGF0b3JzKSkpIHtcbiAgICAgIHRocm93IG5ldyBWZXJpZnlFcnJvcignSW52YWxpZCBuZXh0IGNvbnNlbnN1cyBhZGRyZXNzJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbnMob3B0aW9uczogQmxvY2tWZXJpZnlPcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgdGhpcy50cmFuc2FjdGlvbnMubWFwKGFzeW5jICh0cmFuc2FjdGlvbikgPT5cbiAgICAgICAgdHJhbnNhY3Rpb24udmVyaWZ5KHtcbiAgICAgICAgICBpc1NwZW50OiBvcHRpb25zLmlzU3BlbnQsXG4gICAgICAgICAgZ2V0QXNzZXQ6IG9wdGlvbnMuZ2V0QXNzZXQsXG4gICAgICAgICAgZ2V0T3V0cHV0OiBvcHRpb25zLmdldE91dHB1dCxcbiAgICAgICAgICB0cnlHZXRBY2NvdW50OiBvcHRpb25zLnRyeUdldEFjY291bnQsXG4gICAgICAgICAgY2FsY3VsYXRlQ2xhaW1BbW91bnQ6IG9wdGlvbnMuY2FsY3VsYXRlQ2xhaW1BbW91bnQsXG4gICAgICAgICAgc3RhbmRieVZhbGlkYXRvcnM6IG9wdGlvbnMuc3RhbmRieVZhbGlkYXRvcnMsXG4gICAgICAgICAgZ2V0QWxsVmFsaWRhdG9yczogb3B0aW9ucy5nZXRBbGxWYWxpZGF0b3JzLFxuICAgICAgICAgIHZlcmlmeVNjcmlwdDogb3B0aW9ucy52ZXJpZnlTY3JpcHQsXG4gICAgICAgICAgY3VycmVudEhlaWdodDogb3B0aW9ucy5jdXJyZW50SGVpZ2h0LFxuICAgICAgICAgIGdvdmVybmluZ1Rva2VuOiBvcHRpb25zLmdvdmVybmluZ1Rva2VuLFxuICAgICAgICAgIHV0aWxpdHlUb2tlbjogb3B0aW9ucy51dGlsaXR5VG9rZW4sXG4gICAgICAgICAgZmVlczogb3B0aW9ucy5mZWVzLFxuICAgICAgICAgIHJlZ2lzdGVyVmFsaWRhdG9yRmVlOiBvcHRpb25zLnJlZ2lzdGVyVmFsaWRhdG9yRmVlLFxuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKTtcbiAgICBjb25zdCBmYWlsdXJlUmVzdWx0cyA9IHJlc3VsdHMuZmlsdGVyKCh2ZXJpZnlSZXN1bHRzKSA9PlxuICAgICAgdmVyaWZ5UmVzdWx0cy5zb21lKCh7IGZhaWx1cmVNZXNzYWdlIH0pID0+IGZhaWx1cmVNZXNzYWdlICE9PSB1bmRlZmluZWQpLFxuICAgICk7XG4gICAgaWYgKGZhaWx1cmVSZXN1bHRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGZhaWx1cmVSZXN1bHQgPSBmYWlsdXJlUmVzdWx0c1swXS5maW5kKCh7IGZhaWx1cmVNZXNzYWdlIH0pID0+IGZhaWx1cmVNZXNzYWdlICE9PSB1bmRlZmluZWQpO1xuICAgICAgaWYgKGZhaWx1cmVSZXN1bHQgIT09IHVuZGVmaW5lZCAmJiBmYWlsdXJlUmVzdWx0LmZhaWx1cmVNZXNzYWdlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKGZhaWx1cmVSZXN1bHQuZmFpbHVyZU1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgdmVyaWZ5TmV0d29ya0ZlZShvcHRpb25zOiBCbG9ja1ZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBuZXR3b3JrRmVlID0gYXdhaXQgdGhpcy5nZXROZXR3b3JrRmVlKHtcbiAgICAgIGdldE91dHB1dDogb3B0aW9ucy5nZXRPdXRwdXQsXG4gICAgICBnb3Zlcm5pbmdUb2tlbjogb3B0aW9ucy5nb3Zlcm5pbmdUb2tlbixcbiAgICAgIHV0aWxpdHlUb2tlbjogb3B0aW9ucy51dGlsaXR5VG9rZW4sXG4gICAgICBmZWVzOiBvcHRpb25zLmZlZXMsXG4gICAgICByZWdpc3RlclZhbGlkYXRvckZlZTogb3B0aW9ucy5yZWdpc3RlclZhbGlkYXRvckZlZSxcbiAgICB9KTtcblxuICAgIGNvbnN0IG1pbmVyVHJhbnNhY3Rpb24gPSB0aGlzLnRyYW5zYWN0aW9ucy5maW5kKCh0cmFuc2FjdGlvbikgPT4gdHJhbnNhY3Rpb24udHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLk1pbmVyKTtcblxuICAgIGlmIChtaW5lclRyYW5zYWN0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBWZXJpZnlFcnJvcignTWlzc2luZyBtaW5lciB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIGNvbnN0IG1pbmVyVHJhbnNhY3Rpb25OZXR3b3JrRmVlID0gbWluZXJUcmFuc2FjdGlvbi5vdXRwdXRzLnJlZHVjZShcbiAgICAgIChhY2MsIG91dHB1dCkgPT4gYWNjLmFkZChvdXRwdXQudmFsdWUpLFxuICAgICAgdXRpbHMuWkVSTyxcbiAgICApO1xuXG4gICAgaWYgKCFuZXR3b3JrRmVlLmVxKG1pbmVyVHJhbnNhY3Rpb25OZXR3b3JrRmVlKSkge1xuICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKCdNaW5lciBvdXRwdXQgZG9lcyBub3QgZXF1YWwgbmV0d29yayBmZWUuJyk7XG4gICAgfVxuICB9XG59XG4iXX0=