1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const client_common_1 = require("@neo-one/client-common");
|
5 | const node_core_1 = require("@neo-one/node-core");
|
6 | const utils_1 = require("@neo-one/utils");
|
7 | const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
8 | const context_1 = require("./context");
|
9 | exports.signAndRelay = ({ node, privateKey, context, consensusMessage, }) => {
|
10 | const payload = node_core_1.ConsensusPayload.sign(new node_core_1.UnsignedConsensusPayload({
|
11 | version: context.version,
|
12 | previousHash: context.previousHash,
|
13 | blockIndex: context.blockIndex,
|
14 | validatorIndex: context.myIndex,
|
15 | consensusMessage,
|
16 | }), privateKey);
|
17 | node.relayConsensusPayload(payload);
|
18 | };
|
19 | exports.getInitialContextAdd = ({ blockchain, publicKey, validators, blockReceivedTimeSeconds, }) => {
|
20 | const blockIndex = blockchain.currentBlock.index + 1;
|
21 | const primaryIndex = blockIndex % validators.length;
|
22 | const myIndex = lodash_1.default.findIndex(validators, (validator) => client_common_1.common.ecPointEqual(validator, publicKey));
|
23 | return {
|
24 | type: primaryIndex === myIndex ? 'primary' : 'backup',
|
25 | previousHash: blockchain.currentBlock.hash,
|
26 | blockIndex,
|
27 | viewNumber: 0,
|
28 | myIndex,
|
29 | primaryIndex,
|
30 | expectedView: lodash_1.default.range(0, validators.length).map(() => 0),
|
31 | validators,
|
32 | blockReceivedTimeSeconds,
|
33 | };
|
34 | };
|
35 | function initializeConsensusCommon({ context, blockchain, consensusContext, }) {
|
36 | if (context.myIndex < 0) {
|
37 | return { context };
|
38 | }
|
39 | if (context.type === 'primary') {
|
40 | return {
|
41 | context,
|
42 | timerSeconds: Math.max(0, blockchain.settings.secondsPerBlock - (consensusContext.nowSeconds() - context.blockReceivedTimeSeconds)),
|
43 | };
|
44 | }
|
45 | const { secondsPerBlock } = blockchain.settings;
|
46 | return {
|
47 | context,
|
48 | timerSeconds: secondsPerBlock << (context.viewNumber + 1),
|
49 | };
|
50 | }
|
51 | exports.initializeNewConsensus = async ({ blockchain, publicKey, consensusContext, }) => {
|
52 | const validators = await blockchain.getValidators([]);
|
53 | const blockReceivedTimeSeconds = blockchain.currentBlock.timestamp;
|
54 | const blockIndex = blockchain.currentBlock.index + 1;
|
55 | const primaryIndex = blockIndex % validators.length;
|
56 | const myIndex = lodash_1.default.findIndex(validators, (validator) => client_common_1.common.ecPointEqual(validator, publicKey));
|
57 | const context = new context_1.InitialContext({
|
58 | type: primaryIndex === myIndex ? 'primary' : 'backup',
|
59 | previousHash: blockchain.currentBlock.hash,
|
60 | blockIndex,
|
61 | viewNumber: 0,
|
62 | myIndex,
|
63 | primaryIndex,
|
64 | expectedView: lodash_1.default.range(0, validators.length).map(() => 0),
|
65 | validators,
|
66 | blockReceivedTimeSeconds,
|
67 | });
|
68 | return initializeConsensusCommon({ context, blockchain, consensusContext });
|
69 | };
|
70 | const getPrimaryIndexType = ({ context, viewNumber, }) => {
|
71 | let primaryIndex = (context.blockIndex - viewNumber) % context.validators.length;
|
72 | if (primaryIndex < 0) {
|
73 | primaryIndex += context.validators.length;
|
74 | }
|
75 | return {
|
76 | type: primaryIndex === context.myIndex ? 'primary' : 'backup',
|
77 | primaryIndex,
|
78 | };
|
79 | };
|
80 | exports.initializeConsensus = ({ node, context: contextIn, viewNumber, consensusContext, }) => {
|
81 | if (viewNumber <= 0) {
|
82 | throw new Error('Programming error');
|
83 | }
|
84 | const { blockchain } = node;
|
85 | let context = contextIn;
|
86 | let primaryIndex = (context.blockIndex - viewNumber) % context.validators.length;
|
87 | if (primaryIndex < 0) {
|
88 | primaryIndex += context.validators.length;
|
89 | }
|
90 | const type = primaryIndex === context.myIndex ? 'primary' : 'backup';
|
91 | context =
|
92 | type === 'primary' && context instanceof context_1.SignatureSentContext
|
93 | ? context.clone({ type, primaryIndex, viewNumber })
|
94 | : context_1.cloneInitial(context, { type, primaryIndex, viewNumber });
|
95 | return initializeConsensusCommon({ blockchain, context, consensusContext });
|
96 | };
|
97 | async function checkSignatures({ node, context, }) {
|
98 | const signaturesLength = context.signatures.filter((p) => p !== undefined).length;
|
99 | if (signaturesLength >= context.M &&
|
100 | context.transactionHashes.every((hash) => context.transactions[hash] !== undefined)) {
|
101 | const mutablePublicKeyToSignature = {};
|
102 | for (let i = 0, j = 0; i < context.validators.length && j < context.M; i += 1) {
|
103 | const validator = context.validators[i];
|
104 | const signature = context.signatures[i];
|
105 | if (signature !== undefined) {
|
106 | mutablePublicKeyToSignature[client_common_1.common.ecPointToHex(validator)] = signature;
|
107 | j += 1;
|
108 | }
|
109 | }
|
110 | const script = client_common_1.crypto.createMultiSignatureWitness(context.M, context.validators, mutablePublicKeyToSignature, node_core_1.Witness);
|
111 | const block = context.header.clone({
|
112 | transactions: context.transactionHashes.map((hash) => context.transactions[hash]).filter(utils_1.utils.notNull),
|
113 | script,
|
114 | });
|
115 | await node.relayBlock(block);
|
116 | return { context: context_1.cloneBlockSent(context) };
|
117 | }
|
118 | return { context };
|
119 | }
|
120 | exports.checkSignatures = checkSignatures;
|
121 | exports.signAndRelayChangeView = ({ node, privateKey, context, }) => {
|
122 | exports.signAndRelay({
|
123 | node,
|
124 | privateKey,
|
125 | context,
|
126 | consensusMessage: new node_core_1.ChangeViewConsensusMessage({
|
127 | viewNumber: context.viewNumber,
|
128 | newViewNumber: context.expectedView[context.myIndex],
|
129 | }),
|
130 | });
|
131 | };
|
132 | exports.checkExpectedView = ({ context, viewNumber, }) => context.viewNumber !== viewNumber && context.expectedView.filter((p) => p === viewNumber).length >= context.M;
|
133 | exports.initializeConsensusInitial = ({ blockchain, context, viewNumber, consensusContext, }) => {
|
134 | const { primaryIndex, type } = getPrimaryIndexType({ context, viewNumber });
|
135 | return initializeConsensusCommon({
|
136 | blockchain,
|
137 | context: context_1.cloneInitial(context, { type, primaryIndex, viewNumber }),
|
138 | consensusContext,
|
139 | });
|
140 | };
|
141 | exports.incrementExpectedView = (context) => {
|
142 | const mutableExpectedView = [...context.expectedView];
|
143 | mutableExpectedView[context.myIndex] += 1;
|
144 | return mutableExpectedView;
|
145 | };
|
146 | const requestChangeViewBackup = ({ context: contextIn, node, privateKey, consensusContext, }) => {
|
147 | const context = contextIn.cloneViewChanging({
|
148 | expectedView: exports.incrementExpectedView(contextIn),
|
149 | });
|
150 | exports.signAndRelayChangeView({ context, node, privateKey });
|
151 | const viewNumber = context.expectedView[context.myIndex];
|
152 | if (exports.checkExpectedView({ context, viewNumber })) {
|
153 | return exports.initializeConsensusInitial({
|
154 | blockchain: node.blockchain,
|
155 | context,
|
156 | viewNumber,
|
157 | consensusContext,
|
158 | });
|
159 | }
|
160 | return { context };
|
161 | };
|
162 | exports.addTransaction = async ({ context: contextIn, node, privateKey, transaction, verify, consensusContext, }) => {
|
163 | let context = contextIn;
|
164 | const { blockchain } = node;
|
165 | const tx = await blockchain.transaction.tryGet({ hash: transaction.hash });
|
166 | if (tx !== undefined) {
|
167 | return { context };
|
168 | }
|
169 | if (verify) {
|
170 | let verified = true;
|
171 | try {
|
172 | const { verifications } = await blockchain.verifyTransaction({
|
173 | transaction,
|
174 | memPool: Object.values(context.transactions).filter(utils_1.utils.notNull),
|
175 | });
|
176 | verified = verifications.every(({ failureMessage }) => failureMessage === undefined);
|
177 | }
|
178 | catch (_a) {
|
179 | verified = false;
|
180 | }
|
181 | if (!verified) {
|
182 | return { context };
|
183 | }
|
184 | }
|
185 | context = context.clone({
|
186 | transactions: Object.assign(Object.assign({}, context.transactions), { [transaction.hashHex]: transaction }),
|
187 | });
|
188 | const transactionsLength = Object.values(context.transactions).length;
|
189 | if (context.transactionHashes.length === transactionsLength) {
|
190 | const validators = await blockchain.getValidators(Object.values(context.transactions).filter(utils_1.utils.notNull));
|
191 | const consensusAddress = client_common_1.crypto.getConsensusAddress(validators);
|
192 | if (client_common_1.common.uInt160Equal(consensusAddress, context.header.nextConsensus)) {
|
193 | const mutableSignatures = [...context.signatures];
|
194 | mutableSignatures[context.myIndex] = client_common_1.crypto.sign({
|
195 | message: context.header.message,
|
196 | privateKey,
|
197 | });
|
198 | const newContext = context.cloneSignatureSent({ signatures: mutableSignatures });
|
199 | exports.signAndRelay({
|
200 | node,
|
201 | context: newContext,
|
202 | privateKey,
|
203 | consensusMessage: new node_core_1.PrepareResponseConsensusMessage({
|
204 | viewNumber: newContext.viewNumber,
|
205 | signature: utils_1.utils.nullthrows(mutableSignatures[newContext.myIndex]),
|
206 | }),
|
207 | });
|
208 | return checkSignatures({ node, context: newContext });
|
209 | }
|
210 | return requestChangeViewBackup({
|
211 | context,
|
212 | node,
|
213 | privateKey,
|
214 | consensusContext,
|
215 | });
|
216 | }
|
217 | return { context };
|
218 | };
|
219 |
|
220 | //# sourceMappingURL=data:application/json;charset=utf8;base64,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QUM7Z0JBQ1gsSUFBSTtnQkFDSixPQUFPLEVBQUUsVUFBVTtnQkFDbkIsVUFBVTtnQkFDVixnQkFBZ0IsRUFBRSxJQUFJLDJDQUErQixDQUFDO29CQUNwRCxVQUFVLEVBQUUsVUFBVSxDQUFDLFVBQVU7b0JBQ2pDLFNBQVMsRUFBRSxhQUFXLENBQUMsVUFBVSxDQUFDLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztpQkFDekUsQ0FBQzthQUNILENBQUMsQ0FBQztZQUVILE9BQU8sZUFBZSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDO1NBQ3ZEO1FBRUQsT0FBTyx1QkFBdUIsQ0FBQztZQUM3QixPQUFPO1lBQ1AsSUFBSTtZQUNKLFVBQVU7WUFDVixnQkFBZ0I7U0FDakIsQ0FBQyxDQUFDO0tBQ0o7SUFFRCxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7QUFDckIsQ0FBQyxDQUFDIiwiZmlsZSI6Im5lby1vbmUtbm9kZS1jb25zZW5zdXMvc3JjL2NvbW1vbi5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNvbW1vbiwgY3J5cHRvLCBFQ1BvaW50LCBQcml2YXRlS2V5IH0gZnJvbSAnQG5lby1vbmUvY2xpZW50LWNvbW1vbic7XG5pbXBvcnQge1xuICBCbG9ja2NoYWluLFxuICBDaGFuZ2VWaWV3Q29uc2Vuc3VzTWVzc2FnZSxcbiAgQ29uc2Vuc3VzTWVzc2FnZSxcbiAgQ29uc2Vuc3VzUGF5bG9hZCxcbiAgTm9kZSxcbiAgUHJlcGFyZVJlc3BvbnNlQ29uc2Vuc3VzTWVzc2FnZSxcbiAgVHJhbnNhY3Rpb24sXG4gIFVuc2lnbmVkQ29uc2Vuc3VzUGF5bG9hZCxcbiAgV2l0bmVzcyxcbn0gZnJvbSAnQG5lby1vbmUvbm9kZS1jb3JlJztcbmltcG9ydCB7IHV0aWxzIGFzIGNvbW1vblV0aWxzIH0gZnJvbSAnQG5lby1vbmUvdXRpbHMnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IENvbnNlbnN1c0NvbnRleHQgfSBmcm9tICcuL0NvbnNlbnN1c0NvbnRleHQnO1xuaW1wb3J0IHtcbiAgQmxvY2tTZW50Q29udGV4dCxcbiAgY2xvbmVCbG9ja1NlbnQsXG4gIGNsb25lSW5pdGlhbCxcbiAgQ29udGV4dCxcbiAgSGVhZGVyQ29udGV4dCxcbiAgSW5pdGlhbENvbnRleHQsXG4gIFJlcXVlc3RSZWNlaXZlZENvbnRleHQsXG4gIFNpZ25hdHVyZVNlbnRDb250ZXh0LFxuICBUeXBlLFxuICBWaWV3Q2hhbmdpbmdDb250ZXh0LFxufSBmcm9tICcuL2NvbnRleHQnO1xuaW1wb3J0IHsgUmVzdWx0IH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCBjb25zdCBzaWduQW5kUmVsYXkgPSAoe1xuICBub2RlLFxuICBwcml2YXRlS2V5LFxuICBjb250ZXh0LFxuICBjb25zZW5zdXNNZXNzYWdlLFxufToge1xuICByZWFkb25seSBub2RlOiBOb2RlO1xuICByZWFkb25seSBwcml2YXRlS2V5OiBQcml2YXRlS2V5O1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0O1xuICByZWFkb25seSBjb25zZW5zdXNNZXNzYWdlOiBDb25zZW5zdXNNZXNzYWdlO1xufSkgPT4ge1xuICBjb25zdCBwYXlsb2FkID0gQ29uc2Vuc3VzUGF5bG9hZC5zaWduKFxuICAgIG5ldyBVbnNpZ25lZENvbnNlbnN1c1BheWxvYWQoe1xuICAgICAgdmVyc2lvbjogY29udGV4dC52ZXJzaW9uLFxuICAgICAgcHJldmlvdXNIYXNoOiBjb250ZXh0LnByZXZpb3VzSGFzaCxcbiAgICAgIGJsb2NrSW5kZXg6IGNvbnRleHQuYmxvY2tJbmRleCxcbiAgICAgIHZhbGlkYXRvckluZGV4OiBjb250ZXh0Lm15SW5kZXgsXG4gICAgICBjb25zZW5zdXNNZXNzYWdlLFxuICAgIH0pLFxuXG4gICAgcHJpdmF0ZUtleSxcbiAgKTtcblxuICBub2RlLnJlbGF5Q29uc2Vuc3VzUGF5bG9hZChwYXlsb2FkKTtcbn07XG5cbmV4cG9ydCBjb25zdCBnZXRJbml0aWFsQ29udGV4dEFkZCA9ICh7XG4gIGJsb2NrY2hhaW4sXG4gIHB1YmxpY0tleSxcbiAgdmFsaWRhdG9ycyxcbiAgYmxvY2tSZWNlaXZlZFRpbWVTZWNvbmRzLFxufToge1xuICByZWFkb25seSBibG9ja2NoYWluOiBCbG9ja2NoYWluO1xuICByZWFkb25seSBwdWJsaWNLZXk6IEVDUG9pbnQ7XG4gIHJlYWRvbmx5IHZhbGlkYXRvcnM6IHJlYWRvbmx5IEVDUG9pbnRbXTtcbiAgcmVhZG9ubHkgYmxvY2tSZWNlaXZlZFRpbWVTZWNvbmRzPzogbnVtYmVyO1xufSkgPT4ge1xuICBjb25zdCBibG9ja0luZGV4ID0gYmxvY2tjaGFpbi5jdXJyZW50QmxvY2suaW5kZXggKyAxO1xuICBjb25zdCBwcmltYXJ5SW5kZXggPSBibG9ja0luZGV4ICUgdmFsaWRhdG9ycy5sZW5ndGg7XG4gIGNvbnN0IG15SW5kZXggPSBfLmZpbmRJbmRleCh2YWxpZGF0b3JzLCAodmFsaWRhdG9yKSA9PiBjb21tb24uZWNQb2ludEVxdWFsKHZhbGlkYXRvciwgcHVibGljS2V5KSk7XG5cbiAgcmV0dXJuIHtcbiAgICB0eXBlOiBwcmltYXJ5SW5kZXggPT09IG15SW5kZXggPyAncHJpbWFyeScgOiAnYmFja3VwJyxcbiAgICBwcmV2aW91c0hhc2g6IGJsb2NrY2hhaW4uY3VycmVudEJsb2NrLmhhc2gsXG4gICAgYmxvY2tJbmRleCxcbiAgICB2aWV3TnVtYmVyOiAwLFxuICAgIG15SW5kZXgsXG4gICAgcHJpbWFyeUluZGV4LFxuICAgIGV4cGVjdGVkVmlldzogXy5yYW5nZSgwLCB2YWxpZGF0b3JzLmxlbmd0aCkubWFwKCgpID0+IDApLFxuICAgIHZhbGlkYXRvcnMsXG4gICAgYmxvY2tSZWNlaXZlZFRpbWVTZWNvbmRzLFxuICB9O1xufTtcblxuZnVuY3Rpb24gaW5pdGlhbGl6ZUNvbnNlbnN1c0NvbW1vbjxUQ29udGV4dCBleHRlbmRzIEluaXRpYWxDb250ZXh0IHwgU2lnbmF0dXJlU2VudENvbnRleHQ+KHtcbiAgY29udGV4dCxcbiAgYmxvY2tjaGFpbixcbiAgY29uc2Vuc3VzQ29udGV4dCxcbn06IHtcbiAgcmVhZG9ubHkgY29udGV4dDogVENvbnRleHQ7XG4gIHJlYWRvbmx5IGJsb2NrY2hhaW46IEJsb2NrY2hhaW47XG4gIHJlYWRvbmx5IGNvbnNlbnN1c0NvbnRleHQ6IENvbnNlbnN1c0NvbnRleHQ7XG59KTogUmVzdWx0PFRDb250ZXh0PiB7XG4gIGlmIChjb250ZXh0Lm15SW5kZXggPCAwKSB7XG4gICAgcmV0dXJuIHsgY29udGV4dCB9O1xuICB9XG5cbiAgaWYgKGNvbnRleHQudHlwZSA9PT0gJ3ByaW1hcnknKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbnRleHQsXG4gICAgICB0aW1lclNlY29uZHM6IE1hdGgubWF4KFxuICAgICAgICAwLFxuICAgICAgICBibG9ja2NoYWluLnNldHRpbmdzLnNlY29uZHNQZXJCbG9jayAtIChjb25zZW5zdXNDb250ZXh0Lm5vd1NlY29uZHMoKSAtIGNvbnRleHQuYmxvY2tSZWNlaXZlZFRpbWVTZWNvbmRzKSxcbiAgICAgICksXG4gICAgfTtcbiAgfVxuXG4gIGNvbnN0IHsgc2Vjb25kc1BlckJsb2NrIH0gPSBibG9ja2NoYWluLnNldHRpbmdzO1xuXG4gIHJldHVybiB7XG4gICAgY29udGV4dCxcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tYml0d2lzZVxuICAgIHRpbWVyU2Vjb25kczogc2Vjb25kc1BlckJsb2NrIDw8IChjb250ZXh0LnZpZXdOdW1iZXIgKyAxKSxcbiAgfTtcbn1cblxuZXhwb3J0IGNvbnN0IGluaXRpYWxpemVOZXdDb25zZW5zdXMgPSBhc3luYyAoe1xuICBibG9ja2NoYWluLFxuICBwdWJsaWNLZXksXG4gIGNvbnNlbnN1c0NvbnRleHQsXG59OiB7XG4gIHJlYWRvbmx5IGJsb2NrY2hhaW46IEJsb2NrY2hhaW47XG4gIHJlYWRvbmx5IHB1YmxpY0tleTogRUNQb2ludDtcbiAgcmVhZG9ubHkgY29uc2Vuc3VzQ29udGV4dDogQ29uc2Vuc3VzQ29udGV4dDtcbn0pOiBQcm9taXNlPFJlc3VsdDxJbml0aWFsQ29udGV4dD4+ID0+IHtcbiAgY29uc3QgdmFsaWRhdG9ycyA9IGF3YWl0IGJsb2NrY2hhaW4uZ2V0VmFsaWRhdG9ycyhbXSk7XG4gIGNvbnN0IGJsb2NrUmVjZWl2ZWRUaW1lU2Vjb25kcyA9IGJsb2NrY2hhaW4uY3VycmVudEJsb2NrLnRpbWVzdGFtcDtcbiAgY29uc3QgYmxvY2tJbmRleCA9IGJsb2NrY2hhaW4uY3VycmVudEJsb2NrLmluZGV4ICsgMTtcbiAgY29uc3QgcHJpbWFyeUluZGV4ID0gYmxvY2tJbmRleCAlIHZhbGlkYXRvcnMubGVuZ3RoO1xuICBjb25zdCBteUluZGV4ID0gXy5maW5kSW5kZXgodmFsaWRhdG9ycywgKHZhbGlkYXRvcikgPT4gY29tbW9uLmVjUG9pbnRFcXVhbCh2YWxpZGF0b3IsIHB1YmxpY0tleSkpO1xuXG4gIGNvbnN0IGNvbnRleHQgPSBuZXcgSW5pdGlhbENvbnRleHQoe1xuICAgIHR5cGU6IHByaW1hcnlJbmRleCA9PT0gbXlJbmRleCA/ICdwcmltYXJ5JyA6ICdiYWNrdXAnLFxuICAgIHByZXZpb3VzSGFzaDogYmxvY2tjaGFpbi5jdXJyZW50QmxvY2suaGFzaCxcbiAgICBibG9ja0luZGV4LFxuICAgIHZpZXdOdW1iZXI6IDAsXG4gICAgbXlJbmRleCxcbiAgICBwcmltYXJ5SW5kZXgsXG4gICAgZXhwZWN0ZWRWaWV3OiBfLnJhbmdlKDAsIHZhbGlkYXRvcnMubGVuZ3RoKS5tYXAoKCkgPT4gMCksXG4gICAgdmFsaWRhdG9ycyxcbiAgICBibG9ja1JlY2VpdmVkVGltZVNlY29uZHMsXG4gIH0pO1xuXG4gIHJldHVybiBpbml0aWFsaXplQ29uc2Vuc3VzQ29tbW9uKHsgY29udGV4dCwgYmxvY2tjaGFpbiwgY29uc2Vuc3VzQ29udGV4dCB9KTtcbn07XG5cbmNvbnN0IGdldFByaW1hcnlJbmRleFR5cGUgPSAoe1xuICBjb250ZXh0LFxuICB2aWV3TnVtYmVyLFxufToge1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0O1xuICByZWFkb25seSB2aWV3TnVtYmVyOiBudW1iZXI7XG59KToge1xuICByZWFkb25seSB0eXBlOiBUeXBlO1xuICByZWFkb25seSBwcmltYXJ5SW5kZXg6IG51bWJlcjtcbn0gPT4ge1xuICBsZXQgcHJpbWFyeUluZGV4ID0gKGNvbnRleHQuYmxvY2tJbmRleCAtIHZpZXdOdW1iZXIpICUgY29udGV4dC52YWxpZGF0b3JzLmxlbmd0aDtcbiAgaWYgKHByaW1hcnlJbmRleCA8IDApIHtcbiAgICBwcmltYXJ5SW5kZXggKz0gY29udGV4dC52YWxpZGF0b3JzLmxlbmd0aDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgdHlwZTogcHJpbWFyeUluZGV4ID09PSBjb250ZXh0Lm15SW5kZXggPyAncHJpbWFyeScgOiAnYmFja3VwJyxcbiAgICBwcmltYXJ5SW5kZXgsXG4gIH07XG59O1xuXG5leHBvcnQgY29uc3QgaW5pdGlhbGl6ZUNvbnNlbnN1cyA9ICh7XG4gIG5vZGUsXG4gIGNvbnRleHQ6IGNvbnRleHRJbixcbiAgdmlld051bWJlcixcbiAgY29uc2Vuc3VzQ29udGV4dCxcbn06IHtcbiAgcmVhZG9ubHkgbm9kZTogTm9kZTtcbiAgcmVhZG9ubHkgY29udGV4dDogQ29udGV4dDtcbiAgcmVhZG9ubHkgdmlld051bWJlcjogbnVtYmVyO1xuICByZWFkb25seSBjb25zZW5zdXNDb250ZXh0OiBDb25zZW5zdXNDb250ZXh0O1xufSk6IFJlc3VsdDxJbml0aWFsQ29udGV4dCB8IFNpZ25hdHVyZVNlbnRDb250ZXh0PiA9PiB7XG4gIGlmICh2aWV3TnVtYmVyIDw9IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1Byb2dyYW1taW5nIGVycm9yJyk7XG4gIH1cbiAgY29uc3QgeyBibG9ja2NoYWluIH0gPSBub2RlO1xuICBsZXQgY29udGV4dCA9IGNvbnRleHRJbjtcbiAgbGV0IHByaW1hcnlJbmRleCA9IChjb250ZXh0LmJsb2NrSW5kZXggLSB2aWV3TnVtYmVyKSAlIGNvbnRleHQudmFsaWRhdG9ycy5sZW5ndGg7XG4gIGlmIChwcmltYXJ5SW5kZXggPCAwKSB7XG4gICAgcHJpbWFyeUluZGV4ICs9IGNvbnRleHQudmFsaWRhdG9ycy5sZW5ndGg7XG4gIH1cbiAgY29uc3QgdHlwZSA9IHByaW1hcnlJbmRleCA9PT0gY29udGV4dC5teUluZGV4ID8gJ3ByaW1hcnknIDogJ2JhY2t1cCc7XG4gIGNvbnRleHQgPVxuICAgIHR5cGUgPT09ICdwcmltYXJ5JyAmJiBjb250ZXh0IGluc3RhbmNlb2YgU2lnbmF0dXJlU2VudENvbnRleHRcbiAgICAgID8gY29udGV4dC5jbG9uZSh7IHR5cGUsIHByaW1hcnlJbmRleCwgdmlld051bWJlciB9KVxuICAgICAgOiBjbG9uZUluaXRpYWwoY29udGV4dCwgeyB0eXBlLCBwcmltYXJ5SW5kZXgsIHZpZXdOdW1iZXIgfSk7XG5cbiAgcmV0dXJuIGluaXRpYWxpemVDb25zZW5zdXNDb21tb24oeyBibG9ja2NoYWluLCBjb250ZXh0LCBjb25zZW5zdXNDb250ZXh0IH0pO1xufTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrU2lnbmF0dXJlczxUQ29udGV4dCBleHRlbmRzIEhlYWRlckNvbnRleHQ+KHtcbiAgbm9kZSxcbiAgY29udGV4dCxcbn06IHtcbiAgcmVhZG9ubHkgbm9kZTogTm9kZTtcbiAgcmVhZG9ubHkgY29udGV4dDogVENvbnRleHQ7XG59KTogUHJvbWlzZTxSZXN1bHQ8VENvbnRleHQgfCBCbG9ja1NlbnRDb250ZXh0Pj4ge1xuICBjb25zdCBzaWduYXR1cmVzTGVuZ3RoID0gY29udGV4dC5zaWduYXR1cmVzLmZpbHRlcigocCkgPT4gcCAhPT0gdW5kZWZpbmVkKS5sZW5ndGg7XG5cbiAgaWYgKFxuICAgIHNpZ25hdHVyZXNMZW5ndGggPj0gY29udGV4dC5NICYmXG4gICAgY29udGV4dC50cmFuc2FjdGlvbkhhc2hlcy5ldmVyeSgoaGFzaCkgPT4gY29udGV4dC50cmFuc2FjdGlvbnNbaGFzaF0gIT09IHVuZGVmaW5lZClcbiAgKSB7XG4gICAgY29uc3QgbXV0YWJsZVB1YmxpY0tleVRvU2lnbmF0dXJlOiB7IFtrZXk6IHN0cmluZ106IEJ1ZmZlciB9ID0ge307XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWxvb3Atc3RhdGVtZW50XG4gICAgZm9yIChsZXQgaSA9IDAsIGogPSAwOyBpIDwgY29udGV4dC52YWxpZGF0b3JzLmxlbmd0aCAmJiBqIDwgY29udGV4dC5NOyBpICs9IDEpIHtcbiAgICAgIGNvbnN0IHZhbGlkYXRvciA9IGNvbnRleHQudmFsaWRhdG9yc1tpXTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGNvbnRleHQuc2lnbmF0dXJlc1tpXTtcbiAgICAgIGlmIChzaWduYXR1cmUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBtdXRhYmxlUHVibGljS2V5VG9TaWduYXR1cmVbY29tbW9uLmVjUG9pbnRUb0hleCh2YWxpZGF0b3IpXSA9IHNpZ25hdHVyZTtcbiAgICAgICAgaiArPSAxO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBzY3JpcHQgPSBjcnlwdG8uY3JlYXRlTXVsdGlTaWduYXR1cmVXaXRuZXNzKFxuICAgICAgY29udGV4dC5NLFxuICAgICAgY29udGV4dC52YWxpZGF0b3JzLFxuICAgICAgbXV0YWJsZVB1YmxpY0tleVRvU2lnbmF0dXJlLFxuICAgICAgV2l0bmVzcyxcbiAgICApO1xuXG4gICAgY29uc3QgYmxvY2sgPSBjb250ZXh0LmhlYWRlci5jbG9uZSh7XG4gICAgICB0cmFuc2FjdGlvbnM6IGNvbnRleHQudHJhbnNhY3Rpb25IYXNoZXMubWFwKChoYXNoKSA9PiBjb250ZXh0LnRyYW5zYWN0aW9uc1toYXNoXSkuZmlsdGVyKGNvbW1vblV0aWxzLm5vdE51bGwpLFxuICAgICAgc2NyaXB0LFxuICAgIH0pO1xuXG4gICAgYXdhaXQgbm9kZS5yZWxheUJsb2NrKGJsb2NrKTtcblxuICAgIHJldHVybiB7IGNvbnRleHQ6IGNsb25lQmxvY2tTZW50KGNvbnRleHQpIH07XG4gIH1cblxuICByZXR1cm4geyBjb250ZXh0IH07XG59XG5cbmV4cG9ydCBjb25zdCBzaWduQW5kUmVsYXlDaGFuZ2VWaWV3ID0gKHtcbiAgbm9kZSxcbiAgcHJpdmF0ZUtleSxcbiAgY29udGV4dCxcbn06IHtcbiAgcmVhZG9ubHkgbm9kZTogTm9kZTtcbiAgcmVhZG9ubHkgcHJpdmF0ZUtleTogUHJpdmF0ZUtleTtcbiAgcmVhZG9ubHkgY29udGV4dDogQ29udGV4dDtcbn0pID0+IHtcbiAgc2lnbkFuZFJlbGF5KHtcbiAgICBub2RlLFxuICAgIHByaXZhdGVLZXksXG4gICAgY29udGV4dCxcbiAgICBjb25zZW5zdXNNZXNzYWdlOiBuZXcgQ2hhbmdlVmlld0NvbnNlbnN1c01lc3NhZ2Uoe1xuICAgICAgdmlld051bWJlcjogY29udGV4dC52aWV3TnVtYmVyLFxuICAgICAgbmV3Vmlld051bWJlcjogY29udGV4dC5leHBlY3RlZFZpZXdbY29udGV4dC5teUluZGV4XSxcbiAgICB9KSxcbiAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgY2hlY2tFeHBlY3RlZFZpZXcgPSAoe1xuICBjb250ZXh0LFxuICB2aWV3TnVtYmVyLFxufToge1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0O1xuICByZWFkb25seSB2aWV3TnVtYmVyOiBudW1iZXI7XG59KSA9PiBjb250ZXh0LnZpZXdOdW1iZXIgIT09IHZpZXdOdW1iZXIgJiYgY29udGV4dC5leHBlY3RlZFZpZXcuZmlsdGVyKChwKSA9PiBwID09PSB2aWV3TnVtYmVyKS5sZW5ndGggPj0gY29udGV4dC5NO1xuXG5leHBvcnQgY29uc3QgaW5pdGlhbGl6ZUNvbnNlbnN1c0luaXRpYWwgPSAoe1xuICBibG9ja2NoYWluLFxuICBjb250ZXh0LFxuICB2aWV3TnVtYmVyLFxuICBjb25zZW5zdXNDb250ZXh0LFxufToge1xuICByZWFkb25seSBibG9ja2NoYWluOiBCbG9ja2NoYWluO1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0O1xuICByZWFkb25seSB2aWV3TnVtYmVyOiBudW1iZXI7XG4gIHJlYWRvbmx5IGNvbnNlbnN1c0NvbnRleHQ6IENvbnNlbnN1c0NvbnRleHQ7XG59KTogUmVzdWx0PEluaXRpYWxDb250ZXh0PiA9PiB7XG4gIGNvbnN0IHsgcHJpbWFyeUluZGV4LCB0eXBlIH0gPSBnZXRQcmltYXJ5SW5kZXhUeXBlKHsgY29udGV4dCwgdmlld051bWJlciB9KTtcblxuICByZXR1cm4gaW5pdGlhbGl6ZUNvbnNlbnN1c0NvbW1vbih7XG4gICAgYmxvY2tjaGFpbixcbiAgICBjb250ZXh0OiBjbG9uZUluaXRpYWwoY29udGV4dCwgeyB0eXBlLCBwcmltYXJ5SW5kZXgsIHZpZXdOdW1iZXIgfSksXG4gICAgY29uc2Vuc3VzQ29udGV4dCxcbiAgfSk7XG59O1xuXG5leHBvcnQgY29uc3QgaW5jcmVtZW50RXhwZWN0ZWRWaWV3ID0gKGNvbnRleHQ6IENvbnRleHQpOiByZWFkb25seSBudW1iZXJbXSA9PiB7XG4gIGNvbnN0IG11dGFibGVFeHBlY3RlZFZpZXcgPSBbLi4uY29udGV4dC5leHBlY3RlZFZpZXddO1xuICBtdXRhYmxlRXhwZWN0ZWRWaWV3W2NvbnRleHQubXlJbmRleF0gKz0gMTtcblxuICByZXR1cm4gbXV0YWJsZUV4cGVjdGVkVmlldztcbn07XG5cbmNvbnN0IHJlcXVlc3RDaGFuZ2VWaWV3QmFja3VwID0gKHtcbiAgY29udGV4dDogY29udGV4dEluLFxuICBub2RlLFxuICBwcml2YXRlS2V5LFxuICBjb25zZW5zdXNDb250ZXh0LFxufToge1xuICByZWFkb25seSBjb250ZXh0OiBSZXF1ZXN0UmVjZWl2ZWRDb250ZXh0O1xuICByZWFkb25seSBub2RlOiBOb2RlO1xuICByZWFkb25seSBwcml2YXRlS2V5OiBQcml2YXRlS2V5O1xuICByZWFkb25seSBjb25zZW5zdXNDb250ZXh0OiBDb25zZW5zdXNDb250ZXh0O1xufSk6IFJlc3VsdDxJbml0aWFsQ29udGV4dCB8IFZpZXdDaGFuZ2luZ0NvbnRleHQ+ID0+IHtcbiAgY29uc3QgY29udGV4dCA9IGNvbnRleHRJbi5jbG9uZVZpZXdDaGFuZ2luZyh7XG4gICAgZXhwZWN0ZWRWaWV3OiBpbmNyZW1lbnRFeHBlY3RlZFZpZXcoY29udGV4dEluKSxcbiAgfSk7XG5cbiAgc2lnbkFuZFJlbGF5Q2hhbmdlVmlldyh7IGNvbnRleHQsIG5vZGUsIHByaXZhdGVLZXkgfSk7XG5cbiAgY29uc3Qgdmlld051bWJlciA9IGNvbnRleHQuZXhwZWN0ZWRWaWV3W2NvbnRleHQubXlJbmRleF07XG4gIGlmIChjaGVja0V4cGVjdGVkVmlldyh7IGNvbnRleHQsIHZpZXdOdW1iZXIgfSkpIHtcbiAgICByZXR1cm4gaW5pdGlhbGl6ZUNvbnNlbnN1c0luaXRpYWwoe1xuICAgICAgYmxvY2tjaGFpbjogbm9kZS5ibG9ja2NoYWluLFxuICAgICAgY29udGV4dCxcbiAgICAgIHZpZXdOdW1iZXIsXG4gICAgICBjb25zZW5zdXNDb250ZXh0LFxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIHsgY29udGV4dCB9O1xufTtcblxuZXhwb3J0IGNvbnN0IGFkZFRyYW5zYWN0aW9uID0gYXN5bmMgKHtcbiAgY29udGV4dDogY29udGV4dEluLFxuICBub2RlLFxuICBwcml2YXRlS2V5LFxuICB0cmFuc2FjdGlvbixcbiAgdmVyaWZ5LFxuICBjb25zZW5zdXNDb250ZXh0LFxufToge1xuICByZWFkb25seSBjb250ZXh0OiBSZXF1ZXN0UmVjZWl2ZWRDb250ZXh0O1xuICByZWFkb25seSBub2RlOiBOb2RlO1xuICByZWFkb25seSBwcml2YXRlS2V5OiBQcml2YXRlS2V5O1xuICByZWFkb25seSB0cmFuc2FjdGlvbjogVHJhbnNhY3Rpb247XG4gIHJlYWRvbmx5IHZlcmlmeTogYm9vbGVhbjtcbiAgcmVhZG9ubHkgY29uc2Vuc3VzQ29udGV4dDogQ29uc2Vuc3VzQ29udGV4dDtcbn0pOiBQcm9taXNlPFxuICBSZXN1bHQ8UmVxdWVzdFJlY2VpdmVkQ29udGV4dCB8IEluaXRpYWxDb250ZXh0IHwgVmlld0NoYW5naW5nQ29udGV4dCB8IFNpZ25hdHVyZVNlbnRDb250ZXh0IHwgQmxvY2tTZW50Q29udGV4dD5cbj4gPT4ge1xuICBsZXQgY29udGV4dCA9IGNvbnRleHRJbjtcbiAgY29uc3QgeyBibG9ja2NoYWluIH0gPSBub2RlO1xuICBjb25zdCB0eCA9IGF3YWl0IGJsb2NrY2hhaW4udHJhbnNhY3Rpb24udHJ5R2V0KHsgaGFzaDogdHJhbnNhY3Rpb24uaGFzaCB9KTtcbiAgaWYgKHR4ICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4geyBjb250ZXh0IH07XG4gIH1cbiAgaWYgKHZlcmlmeSkge1xuICAgIGxldCB2ZXJpZmllZCA9IHRydWU7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHsgdmVyaWZpY2F0aW9ucyB9ID0gYXdhaXQgYmxvY2tjaGFpbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBtZW1Qb29sOiBPYmplY3QudmFsdWVzKGNvbnRleHQudHJhbnNhY3Rpb25zKS5maWx0ZXIoY29tbW9uVXRpbHMubm90TnVsbCksXG4gICAgICB9KTtcbiAgICAgIHZlcmlmaWVkID0gdmVyaWZpY2F0aW9ucy5ldmVyeSgoeyBmYWlsdXJlTWVzc2FnZSB9KSA9PiBmYWlsdXJlTWVzc2FnZSA9PT0gdW5kZWZpbmVkKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHZlcmlmaWVkID0gZmFsc2U7XG4gICAgfVxuICAgIGlmICghdmVyaWZpZWQpIHtcbiAgICAgIHJldHVybiB7IGNvbnRleHQgfTtcbiAgICB9XG4gIH1cblxuICBjb250ZXh0ID0gY29udGV4dC5jbG9uZSh7XG4gICAgdHJhbnNhY3Rpb25zOiB7XG4gICAgICAuLi5jb250ZXh0LnRyYW5zYWN0aW9ucyxcbiAgICAgIFt0cmFuc2FjdGlvbi5oYXNoSGV4XTogdHJhbnNhY3Rpb24sXG4gICAgfSxcbiAgfSk7XG5cbiAgY29uc3QgdHJhbnNhY3Rpb25zTGVuZ3RoID0gT2JqZWN0LnZhbHVlcyhjb250ZXh0LnRyYW5zYWN0aW9ucykubGVuZ3RoO1xuICBpZiAoY29udGV4dC50cmFuc2FjdGlvbkhhc2hlcy5sZW5ndGggPT09IHRyYW5zYWN0aW9uc0xlbmd0aCkge1xuICAgIGNvbnN0IHZhbGlkYXRvcnMgPSBhd2FpdCBibG9ja2NoYWluLmdldFZhbGlkYXRvcnMoT2JqZWN0LnZhbHVlcyhjb250ZXh0LnRyYW5zYWN0aW9ucykuZmlsdGVyKGNvbW1vblV0aWxzLm5vdE51bGwpKTtcblxuICAgIGNvbnN0IGNvbnNlbnN1c0FkZHJlc3MgPSBjcnlwdG8uZ2V0Q29uc2Vuc3VzQWRkcmVzcyh2YWxpZGF0b3JzKTtcbiAgICBpZiAoY29tbW9uLnVJbnQxNjBFcXVhbChjb25zZW5zdXNBZGRyZXNzLCBjb250ZXh0LmhlYWRlci5uZXh0Q29uc2Vuc3VzKSkge1xuICAgICAgY29uc3QgbXV0YWJsZVNpZ25hdHVyZXMgPSBbLi4uY29udGV4dC5zaWduYXR1cmVzXTtcbiAgICAgIG11dGFibGVTaWduYXR1cmVzW2NvbnRleHQubXlJbmRleF0gPSBjcnlwdG8uc2lnbih7XG4gICAgICAgIG1lc3NhZ2U6IGNvbnRleHQuaGVhZGVyLm1lc3NhZ2UsXG4gICAgICAgIHByaXZhdGVLZXksXG4gICAgICB9KTtcblxuICAgICAgY29uc3QgbmV3Q29udGV4dCA9IGNvbnRleHQuY2xvbmVTaWduYXR1cmVTZW50KHsgc2lnbmF0dXJlczogbXV0YWJsZVNpZ25hdHVyZXMgfSk7XG4gICAgICBzaWduQW5kUmVsYXkoe1xuICAgICAgICBub2RlLFxuICAgICAgICBjb250ZXh0OiBuZXdDb250ZXh0LFxuICAgICAgICBwcml2YXRlS2V5LFxuICAgICAgICBjb25zZW5zdXNNZXNzYWdlOiBuZXcgUHJlcGFyZVJlc3BvbnNlQ29uc2Vuc3VzTWVzc2FnZSh7XG4gICAgICAgICAgdmlld051bWJlcjogbmV3Q29udGV4dC52aWV3TnVtYmVyLFxuICAgICAgICAgIHNpZ25hdHVyZTogY29tbW9uVXRpbHMubnVsbHRocm93cyhtdXRhYmxlU2lnbmF0dXJlc1tuZXdDb250ZXh0Lm15SW5kZXhdKSxcbiAgICAgICAgfSksXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIGNoZWNrU2lnbmF0dXJlcyh7IG5vZGUsIGNvbnRleHQ6IG5ld0NvbnRleHQgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcXVlc3RDaGFuZ2VWaWV3QmFja3VwKHtcbiAgICAgIGNvbnRleHQsXG4gICAgICBub2RlLFxuICAgICAgcHJpdmF0ZUtleSxcbiAgICAgIGNvbnNlbnN1c0NvbnRleHQsXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4geyBjb250ZXh0IH07XG59O1xuIl19
|