Complex classes like InputSigner often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use InputSigner, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
45 | class InputSigner implements InputSignerInterface |
||
46 | { |
||
47 | /** |
||
48 | * @var array |
||
49 | */ |
||
50 | protected static $canSign = [ |
||
51 | ScriptType::P2PKH, |
||
52 | ScriptType::P2PK, |
||
53 | ScriptType::MULTISIG |
||
54 | ]; |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | */ |
||
59 | protected static $validP2sh = [ |
||
60 | ScriptType::P2WKH, |
||
61 | ScriptType::P2WSH, |
||
62 | ScriptType::P2PKH, |
||
63 | ScriptType::P2PK, |
||
64 | ScriptType::MULTISIG |
||
65 | ]; |
||
66 | |||
67 | /** |
||
68 | * @var EcAdapterInterface |
||
69 | */ |
||
70 | private $ecAdapter; |
||
71 | |||
72 | /** |
||
73 | * @var OutputData $scriptPubKey |
||
74 | */ |
||
75 | private $scriptPubKey; |
||
76 | |||
77 | /** |
||
78 | * @var OutputData $redeemScript |
||
79 | */ |
||
80 | private $redeemScript; |
||
81 | |||
82 | /** |
||
83 | * @var OutputData $witnessScript |
||
84 | */ |
||
85 | private $witnessScript; |
||
86 | |||
87 | /** |
||
88 | * @var OutputData |
||
89 | */ |
||
90 | private $signScript; |
||
91 | |||
92 | /** |
||
93 | * @var bool |
||
94 | */ |
||
95 | private $padUnsignedMultisigs = false; |
||
96 | |||
97 | /** |
||
98 | * @var bool |
||
99 | */ |
||
100 | private $tolerateInvalidPublicKey = false; |
||
101 | |||
102 | /** |
||
103 | * @var bool |
||
104 | */ |
||
105 | private $redeemBitcoinCash = false; |
||
106 | |||
107 | /** |
||
108 | * @var bool |
||
109 | */ |
||
110 | private $allowComplexScripts = false; |
||
111 | |||
112 | /** |
||
113 | * @var SignData |
||
114 | */ |
||
115 | private $signData; |
||
116 | |||
117 | /** |
||
118 | * @var int |
||
119 | */ |
||
120 | private $sigVersion; |
||
121 | |||
122 | /** |
||
123 | * @var int |
||
124 | */ |
||
125 | private $flags; |
||
126 | |||
127 | /** |
||
128 | * @var TransactionInterface |
||
129 | */ |
||
130 | private $tx; |
||
131 | |||
132 | /** |
||
133 | * @var int |
||
134 | */ |
||
135 | private $nInput; |
||
136 | |||
137 | /** |
||
138 | * @var TransactionOutputInterface |
||
139 | */ |
||
140 | private $txOut; |
||
141 | |||
142 | /** |
||
143 | * @var Interpreter |
||
144 | */ |
||
145 | private $interpreter; |
||
146 | |||
147 | /** |
||
148 | * @var Checker |
||
149 | */ |
||
150 | private $signatureChecker; |
||
151 | |||
152 | /** |
||
153 | * @var TransactionSignatureSerializer |
||
154 | */ |
||
155 | private $txSigSerializer; |
||
156 | |||
157 | /** |
||
158 | * @var PublicKeySerializerInterface |
||
159 | */ |
||
160 | private $pubKeySerializer; |
||
161 | |||
162 | /** |
||
163 | * @var Conditional[]|Checksig[] |
||
164 | */ |
||
165 | private $steps = []; |
||
166 | |||
167 | /** |
||
168 | * InputSigner constructor. |
||
169 | * |
||
170 | * Note, the implementation of this class is considered internal |
||
171 | * and only the methods exposed on InputSignerInterface should |
||
172 | * be depended on to avoid BC breaks. |
||
173 | * |
||
174 | * The only recommended way to produce this class is using Signer::input() |
||
175 | * |
||
176 | * @param EcAdapterInterface $ecAdapter |
||
177 | * @param TransactionInterface $tx |
||
178 | * @param int $nInput |
||
179 | * @param TransactionOutputInterface $txOut |
||
180 | * @param SignData $signData |
||
181 | * @param TransactionSignatureSerializer|null $sigSerializer |
||
182 | * @param PublicKeySerializerInterface|null $pubKeySerializer |
||
183 | */ |
||
184 | 190 | public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $tx, $nInput, TransactionOutputInterface $txOut, SignData $signData, TransactionSignatureSerializer $sigSerializer = null, PublicKeySerializerInterface $pubKeySerializer = null) |
|
185 | { |
||
186 | 190 | $this->ecAdapter = $ecAdapter; |
|
187 | 190 | $this->tx = $tx; |
|
188 | 190 | $this->nInput = $nInput; |
|
189 | 190 | $this->txOut = $txOut; |
|
190 | 190 | $this->signData = $signData; |
|
191 | |||
192 | 190 | $this->txSigSerializer = $sigSerializer ?: new TransactionSignatureSerializer(EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $ecAdapter)); |
|
193 | 190 | $this->pubKeySerializer = $pubKeySerializer ?: EcSerializer::getSerializer(PublicKeySerializerInterface::class, true, $ecAdapter); |
|
194 | 190 | $this->interpreter = new Interpreter($this->ecAdapter); |
|
195 | 190 | } |
|
196 | |||
197 | /** |
||
198 | * @return InputSigner |
||
199 | */ |
||
200 | 190 | public function extract() |
|
201 | { |
||
202 | 190 | $defaultFlags = Interpreter::VERIFY_DERSIG | Interpreter::VERIFY_P2SH | Interpreter::VERIFY_CHECKLOCKTIMEVERIFY | Interpreter::VERIFY_CHECKSEQUENCEVERIFY | Interpreter::VERIFY_WITNESS; |
|
203 | 190 | $checker = new Checker($this->ecAdapter, $this->tx, $this->nInput, $this->txOut->getValue(), $this->txSigSerializer, $this->pubKeySerializer); |
|
204 | |||
205 | 190 | if ($this->redeemBitcoinCash) { |
|
206 | // unset VERIFY_WITNESS default |
||
207 | 2 | $defaultFlags = $defaultFlags & (~Interpreter::VERIFY_WITNESS); |
|
208 | |||
209 | 2 | if ($this->signData->hasSignaturePolicy()) { |
|
210 | if ($this->signData->getSignaturePolicy() & Interpreter::VERIFY_WITNESS) { |
||
211 | throw new \RuntimeException("VERIFY_WITNESS is not possible for bitcoin cash"); |
||
212 | } |
||
213 | } |
||
214 | |||
215 | 2 | $checker = new BitcoinCashChecker($this->ecAdapter, $this->tx, $this->nInput, $this->txOut->getValue(), $this->txSigSerializer, $this->pubKeySerializer); |
|
216 | } |
||
217 | |||
218 | 190 | $this->flags = $this->signData->hasSignaturePolicy() ? $this->signData->getSignaturePolicy() : $defaultFlags; |
|
219 | 190 | $this->signatureChecker = $checker; |
|
220 | |||
221 | 190 | $witnesses = $this->tx->getWitnesses(); |
|
222 | 190 | $witness = array_key_exists($this->nInput, $witnesses) ? $witnesses[$this->nInput]->all() : []; |
|
223 | |||
224 | 190 | return $this->solve( |
|
225 | 190 | $this->signData, |
|
226 | 190 | $this->txOut->getScript(), |
|
227 | 190 | $this->tx->getInput($this->nInput)->getScript(), |
|
228 | 188 | $witness |
|
229 | ); |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * @param bool $setting |
||
234 | * @return $this |
||
235 | */ |
||
236 | 160 | public function padUnsignedMultisigs($setting) |
|
237 | { |
||
238 | 160 | $this->padUnsignedMultisigs = (bool) $setting; |
|
239 | 160 | return $this; |
|
240 | } |
||
241 | |||
242 | /** |
||
243 | * @param bool $setting |
||
244 | * @return $this |
||
245 | */ |
||
246 | 160 | public function tolerateInvalidPublicKey($setting) |
|
247 | { |
||
248 | 160 | $this->tolerateInvalidPublicKey = (bool) $setting; |
|
249 | 160 | return $this; |
|
250 | } |
||
251 | |||
252 | /** |
||
253 | * @param bool $setting |
||
254 | * @return $this |
||
255 | */ |
||
256 | 160 | public function redeemBitcoinCash($setting) |
|
257 | { |
||
258 | 160 | $this->redeemBitcoinCash = (bool) $setting; |
|
259 | 160 | return $this; |
|
260 | } |
||
261 | |||
262 | /** |
||
263 | * @param bool $setting |
||
264 | * @return $this |
||
265 | */ |
||
266 | 160 | public function allowComplexScripts($setting) |
|
267 | { |
||
268 | 160 | $this->allowComplexScripts = (bool) $setting; |
|
269 | 160 | return $this; |
|
270 | } |
||
271 | |||
272 | /** |
||
273 | * @param BufferInterface $vchPubKey |
||
274 | * @return PublicKeyInterface|null |
||
275 | * @throws \Exception |
||
276 | */ |
||
277 | 138 | protected function parseStepPublicKey(BufferInterface $vchPubKey) |
|
278 | { |
||
279 | try { |
||
280 | 138 | return $this->pubKeySerializer->parse($vchPubKey); |
|
281 | 6 | } catch (\Exception $e) { |
|
282 | 6 | if ($this->tolerateInvalidPublicKey) { |
|
283 | 2 | return null; |
|
284 | } |
||
285 | |||
286 | 4 | throw $e; |
|
287 | } |
||
288 | } |
||
289 | |||
290 | /** |
||
291 | * A snippet from OP_CHECKMULTISIG - links keys to signatures |
||
292 | * |
||
293 | * @param ScriptInterface $script |
||
294 | * @param BufferInterface[] $signatures |
||
295 | * @param BufferInterface[] $publicKeys |
||
296 | * @param int $sigVersion |
||
297 | * @return \SplObjectStorage |
||
298 | */ |
||
299 | 50 | private function sortMultisigs(ScriptInterface $script, array $signatures, array $publicKeys, $sigVersion) |
|
300 | { |
||
301 | 50 | $sigCount = count($signatures); |
|
302 | 50 | $keyCount = count($publicKeys); |
|
303 | 50 | $ikey = $isig = 0; |
|
304 | 50 | $fSuccess = true; |
|
305 | 50 | $result = new \SplObjectStorage; |
|
306 | |||
307 | 50 | while ($fSuccess && $sigCount > 0) { |
|
308 | // Fetch the signature and public key |
||
309 | 50 | $sig = $signatures[$isig]; |
|
310 | 50 | $pubkey = $publicKeys[$ikey]; |
|
311 | |||
312 | 50 | if ($this->signatureChecker->checkSig($script, $sig, $pubkey, $sigVersion, $this->flags)) { |
|
313 | 48 | $result[$pubkey] = $sig; |
|
314 | 48 | $isig++; |
|
315 | 48 | $sigCount--; |
|
316 | } |
||
317 | |||
318 | 50 | $ikey++; |
|
319 | 50 | $keyCount--; |
|
320 | |||
321 | // If there are more signatures left than keys left, |
||
322 | // then too many signatures have failed. Exit early, |
||
323 | // without checking any further signatures. |
||
324 | 50 | if ($sigCount > $keyCount) { |
|
325 | 2 | $fSuccess = false; |
|
326 | } |
||
327 | } |
||
328 | |||
329 | 50 | return $result; |
|
330 | } |
||
331 | |||
332 | /** |
||
333 | * @param ScriptInterface $script |
||
334 | * @return \BitWasp\Buffertools\BufferInterface[] |
||
335 | */ |
||
336 | 186 | private function evalPushOnly(ScriptInterface $script) |
|
337 | { |
||
338 | 186 | $stack = new Stack(); |
|
339 | 186 | $this->interpreter->evaluate($script, $stack, SigHash::V0, $this->flags | Interpreter::VERIFY_SIGPUSHONLY, $this->signatureChecker); |
|
340 | 186 | return $stack->all(); |
|
341 | } |
||
342 | |||
343 | /** |
||
344 | * Create a script consisting only of push-data operations. |
||
345 | * Suitable for a scriptSig. |
||
346 | * |
||
347 | * @param BufferInterface[] $buffers |
||
348 | * @return ScriptInterface |
||
349 | */ |
||
350 | private function pushAll(array $buffers) |
||
351 | { |
||
352 | 126 | return ScriptFactory::sequence(array_map(function ($buffer) { |
|
353 | 104 | if (!($buffer instanceof BufferInterface)) { |
|
354 | throw new \RuntimeException('Script contained a non-push opcode'); |
||
355 | } |
||
356 | |||
357 | 104 | $size = $buffer->getSize(); |
|
358 | 104 | if ($size === 0) { |
|
359 | 44 | return Opcodes::OP_0; |
|
360 | } |
||
361 | |||
362 | 104 | $first = ord($buffer->getBinary()[0]); |
|
363 | 104 | if ($size === 1 && $first >= 1 && $first <= 16) { |
|
364 | 8 | return \BitWasp\Bitcoin\Script\encodeOpN($first); |
|
365 | } else { |
||
366 | 104 | return $buffer; |
|
367 | } |
||
368 | 126 | }, $buffers)); |
|
369 | } |
||
370 | |||
371 | /** |
||
372 | * Verify a scriptSig / scriptWitness against a scriptPubKey. |
||
373 | * Useful for checking the outcome of certain things, like hash locks (p2sh) |
||
374 | * |
||
375 | * @param int $flags |
||
376 | * @param ScriptInterface $scriptSig |
||
377 | * @param ScriptInterface $scriptPubKey |
||
378 | * @param ScriptWitnessInterface|null $scriptWitness |
||
379 | * @return bool |
||
380 | */ |
||
381 | 70 | private function verifySolution($flags, ScriptInterface $scriptSig, ScriptInterface $scriptPubKey, ScriptWitnessInterface $scriptWitness = null) |
|
382 | { |
||
383 | 70 | return $this->interpreter->verify($scriptSig, $scriptPubKey, $flags, $this->signatureChecker, $scriptWitness); |
|
384 | } |
||
385 | |||
386 | /** |
||
387 | * @param array $decoded |
||
388 | * @param null $solution |
||
389 | * @return null|TimeLock|Checksig |
||
390 | */ |
||
391 | 166 | private function classifySignStep(array $decoded, &$solution = null) |
|
428 | |||
429 | /** |
||
430 | * @param Operation[] $scriptOps |
||
431 | * @return Checksig[] |
||
432 | */ |
||
433 | 166 | public function parseSequence(array $scriptOps) |
|
434 | { |
||
435 | 166 | $j = 0; |
|
436 | 166 | $l = count($scriptOps); |
|
437 | 166 | $result = []; |
|
438 | 166 | while ($j < $l) { |
|
439 | 166 | $step = null; |
|
440 | 166 | $slice = null; |
|
441 | |||
442 | // increment the $last, and break if it's valid |
||
443 | 166 | for ($i = 0; $i < ($l - $j) + 1; $i++) { |
|
444 | 166 | $slice = array_slice($scriptOps, $j, $i); |
|
445 | 166 | $step = $this->classifySignStep($slice, $solution); |
|
446 | 166 | if ($step !== null) { |
|
447 | 166 | break; |
|
448 | } |
||
449 | } |
||
450 | |||
451 | 166 | if (null === $step) { |
|
452 | throw new \RuntimeException("Invalid script"); |
||
453 | } else { |
||
454 | 166 | $j += $i; |
|
455 | 166 | $result[] = $step; |
|
456 | } |
||
457 | } |
||
458 | |||
459 | 166 | return $result; |
|
460 | } |
||
461 | |||
462 | /** |
||
463 | * @param Operation $operation |
||
464 | * @param Stack $mainStack |
||
465 | * @param bool[] $pathData |
||
466 | * @return Conditional |
||
467 | */ |
||
468 | 22 | public function extractConditionalOp(Operation $operation, Stack $mainStack, array &$pathData) |
|
469 | { |
||
470 | 22 | $opValue = null; |
|
471 | |||
472 | 22 | if (!$mainStack->isEmpty()) { |
|
473 | 22 | if (count($pathData) === 0) { |
|
474 | throw new \RuntimeException("Extracted conditional op (including mainstack) without corresponding element in path data"); |
||
475 | } |
||
476 | |||
477 | 22 | $opValue = $this->interpreter->castToBool($mainStack->pop()); |
|
478 | 22 | $dataValue = array_shift($pathData); |
|
479 | 22 | if ($opValue !== $dataValue) { |
|
480 | 22 | throw new \RuntimeException("Current stack doesn't follow branch path"); |
|
481 | } |
||
482 | } else { |
||
483 | 18 | if (count($pathData) === 0) { |
|
484 | throw new \RuntimeException("Extracted conditional op without corresponding element in path data"); |
||
485 | } |
||
486 | |||
487 | 18 | $opValue = array_shift($pathData); |
|
488 | } |
||
489 | |||
490 | 22 | $conditional = new Conditional($operation->getOp()); |
|
491 | |||
492 | 22 | if ($opValue !== null) { |
|
493 | 22 | if (!is_bool($opValue)) { |
|
494 | throw new \RuntimeException("Sanity check, path value (likely from pathData) was not a bool"); |
||
495 | } |
||
496 | |||
497 | 22 | $conditional->setValue($opValue); |
|
498 | } |
||
499 | |||
500 | 22 | return $conditional; |
|
501 | } |
||
502 | |||
503 | /** |
||
504 | * @param int $idx |
||
505 | * @return Checksig|Conditional |
||
506 | */ |
||
507 | 36 | public function step($idx) |
|
508 | { |
||
509 | 36 | if (!array_key_exists($idx, $this->steps)) { |
|
510 | throw new \RuntimeException("Out of range index for input sign step"); |
||
511 | } |
||
512 | |||
513 | 36 | return $this->steps[$idx]; |
|
514 | } |
||
515 | |||
516 | /** |
||
517 | * @param OutputData $solution |
||
518 | * @param array $sigChunks |
||
519 | * @param SignData $signData |
||
520 | */ |
||
521 | 166 | public function extractScript(OutputData $solution, array $sigChunks, SignData $signData) |
|
522 | { |
||
523 | 166 | $logicInterpreter = new BranchInterpreter(); |
|
524 | 166 | $tree = $logicInterpreter->getScriptTree($solution->getScript()); |
|
525 | |||
526 | 166 | if ($tree->hasMultipleBranches()) { |
|
527 | 22 | $logicalPath = $signData->getLogicalPath(); |
|
528 | // we need a function like findWitnessScript to 'check' |
||
529 | // partial signatures against _our_ path |
||
530 | } else { |
||
531 | 144 | $logicalPath = []; |
|
532 | } |
||
533 | |||
534 | $scriptSections = $tree |
||
535 | 166 | ->getBranchByPath($logicalPath) |
|
536 | 166 | ->getScriptSections(); |
|
537 | |||
538 | 166 | $vfStack = new Stack(); |
|
539 | 166 | $stack = new Stack($sigChunks); |
|
540 | |||
541 | 166 | $pathCopy = $logicalPath; |
|
542 | 166 | $steps = []; |
|
543 | 166 | foreach ($scriptSections as $i => $scriptSection) { |
|
544 | /** @var Operation[] $scriptSection */ |
||
545 | 166 | $fExec = !$this->interpreter->checkExec($vfStack, false); |
|
546 | 166 | if (count($scriptSection) === 1 && $scriptSection[0]->isLogical()) { |
|
547 | 22 | $op = $scriptSection[0]; |
|
548 | 22 | switch ($op->getOp()) { |
|
549 | 22 | case Opcodes::OP_IF: |
|
550 | 22 | case Opcodes::OP_NOTIF: |
|
551 | 22 | $value = false; |
|
552 | 22 | if ($fExec) { |
|
553 | // Pop from mainStack if $fExec |
||
554 | 22 | $step = $this->extractConditionalOp($op, $stack, $pathCopy); |
|
555 | |||
556 | // the Conditional has a value in this case: |
||
557 | 22 | $value = $step->getValue(); |
|
558 | |||
559 | // Connect the last operation (if there is one) |
||
560 | // with the last step with isRequired==$value |
||
561 | // todo: check this part out.. |
||
562 | 22 | for ($j = count($steps) - 1; $j >= 0; $j--) { |
|
563 | 8 | if ($steps[$j] instanceof Checksig && $value === $steps[$j]->isRequired()) { |
|
564 | 8 | $step->providedBy($steps[$j]); |
|
565 | 8 | break; |
|
566 | } |
||
567 | } |
||
568 | } else { |
||
569 | 2 | $step = new Conditional($op->getOp()); |
|
570 | } |
||
571 | |||
572 | 22 | $steps[] = $step; |
|
573 | |||
574 | 22 | if ($op->getOp() === Opcodes::OP_NOTIF) { |
|
575 | 10 | $value = !$value; |
|
576 | } |
||
577 | |||
578 | 22 | $vfStack->push($value); |
|
579 | 22 | break; |
|
580 | 22 | case Opcodes::OP_ENDIF: |
|
581 | 22 | $vfStack->pop(); |
|
582 | 22 | break; |
|
583 | 18 | case Opcodes::OP_ELSE: |
|
584 | 18 | $vfStack->push(!$vfStack->pop()); |
|
585 | 22 | break; |
|
586 | } |
||
587 | } else { |
||
588 | 166 | $templateTypes = $this->parseSequence($scriptSection); |
|
589 | |||
590 | // Detect if effect on mainStack is `false` |
||
591 | 166 | $resolvesFalse = count($pathCopy) > 0 && !$pathCopy[0]; |
|
592 | 166 | if ($resolvesFalse) { |
|
593 | 4 | if (count($templateTypes) > 1) { |
|
594 | throw new \RuntimeException("Unsupported script, multiple steps to segment which is negated"); |
||
595 | } |
||
596 | } |
||
597 | |||
598 | 166 | foreach ($templateTypes as $k => $checksig) { |
|
599 | 166 | if ($fExec) { |
|
600 | 166 | if ($checksig instanceof Checksig) { |
|
601 | 146 | $this->extractChecksig($solution->getScript(), $checksig, $stack, $this->sigVersion, $resolvesFalse); |
|
602 | |||
603 | // If this statement results is later consumed |
||
604 | // by a conditional which would be false, mark |
||
605 | // this operation as not required |
||
606 | 136 | if ($resolvesFalse) { |
|
607 | 136 | $checksig->setRequired(false); |
|
608 | } |
||
609 | 30 | } else if ($checksig instanceof TimeLock) { |
|
610 | 30 | $this->checkTimeLock($checksig); |
|
611 | } |
||
612 | |||
613 | 136 | $steps[] = $checksig; |
|
614 | } |
||
615 | } |
||
616 | } |
||
617 | } |
||
618 | |||
619 | 136 | $this->steps = $steps; |
|
620 | 136 | } |
|
621 | |||
622 | /** |
||
623 | * @param int $verify |
||
624 | * @param int $input |
||
625 | * @param int $threshold |
||
626 | * @return int |
||
627 | */ |
||
628 | 10 | private function compareRangeAgainstThreshold($verify, $input, $threshold) |
|
640 | |||
641 | /** |
||
642 | * @param TimeLock $timelock |
||
643 | */ |
||
644 | 30 | public function checkTimeLock(TimeLock $timelock) |
|
645 | { |
||
646 | 30 | $info = $timelock->getInfo(); |
|
647 | 30 | if (($this->flags & Interpreter::VERIFY_CHECKLOCKTIMEVERIFY) != 0 && $info instanceof CheckLocktimeVerify) { |
|
648 | 16 | $verifyLocktime = $info->getLocktime(); |
|
649 | 16 | if (!$this->signatureChecker->checkLockTime(Number::int($verifyLocktime))) { |
|
650 | 10 | $input = $this->tx->getInput($this->nInput); |
|
651 | 10 | if ($input->isFinal()) { |
|
652 | 4 | throw new \RuntimeException("Input sequence is set to max, therefore CHECKLOCKTIMEVERIFY would fail"); |
|
653 | } |
||
654 | |||
655 | 6 | $locktime = $this->tx->getLockTime(); |
|
697 | |||
698 | /** |
||
699 | * This function is strictly for $canSign types. |
||
700 | * It will extract signatures/publicKeys when given $outputData, and $stack. |
||
701 | * $stack is the result of decompiling a scriptSig, or taking the witness data. |
||
702 | * |
||
703 | * @param ScriptInterface $script |
||
704 | * @param Checksig $checksig |
||
705 | * @param Stack $stack |
||
706 | * @param int $sigVersion |
||
707 | * @param bool $expectFalse |
||
708 | */ |
||
709 | 146 | public function extractChecksig(ScriptInterface $script, Checksig $checksig, Stack $stack, $sigVersion, $expectFalse) |
|
849 | |||
850 | /** |
||
851 | * Checks $chunks (a decompiled scriptSig) for it's last element, |
||
852 | * or defers to SignData. If both are provided, it checks the |
||
853 | * value from $chunks against SignData. |
||
854 | * |
||
855 | * @param BufferInterface[] $chunks |
||
856 | * @param SignData $signData |
||
857 | * @return ScriptInterface |
||
858 | */ |
||
859 | 74 | private function findRedeemScript(array $chunks, SignData $signData) |
|
877 | |||
878 | /** |
||
879 | * Checks $witness (a witness structure) for it's last element, |
||
880 | * or defers to SignData. If both are provided, it checks the |
||
881 | * value from $chunks against SignData. |
||
882 | * |
||
883 | * @param BufferInterface[] $witness |
||
884 | * @param SignData $signData |
||
885 | * @return ScriptInterface |
||
886 | */ |
||
887 | 70 | private function findWitnessScript(array $witness, SignData $signData) |
|
905 | |||
906 | /** |
||
907 | * Needs to be called before using the instance. By `extract`. |
||
908 | * |
||
909 | * It ensures that violating the following prevents instance creation |
||
910 | * - the scriptPubKey can be directly signed, or leads to P2SH/P2WSH/P2WKH |
||
911 | * - the P2SH script covers signable types and P2WSH/P2WKH |
||
912 | * - the witnessScript covers signable types only |
||
913 | * |
||
914 | * @param SignData $signData |
||
915 | * @param ScriptInterface $scriptPubKey |
||
916 | * @param ScriptInterface $scriptSig |
||
917 | * @param BufferInterface[] $witness |
||
918 | * @return $this |
||
919 | */ |
||
920 | 188 | private function solve(SignData $signData, ScriptInterface $scriptPubKey, ScriptInterface $scriptSig, array $witness) |
|
980 | |||
981 | /** |
||
982 | * Pure function to produce a signature hash for a given $scriptCode, $sigHashType, $sigVersion. |
||
983 | * |
||
984 | * @param ScriptInterface $scriptCode |
||
985 | * @param int $sigHashType |
||
986 | * @param int $sigVersion |
||
987 | * @return BufferInterface |
||
988 | */ |
||
989 | 128 | public function calculateSigHashUnsafe(ScriptInterface $scriptCode, $sigHashType, $sigVersion) |
|
997 | |||
998 | /** |
||
999 | * Calculates the signature hash for the input for the given $sigHashType. |
||
1000 | * |
||
1001 | * @param int $sigHashType |
||
1002 | * @return BufferInterface |
||
1003 | */ |
||
1004 | 2 | public function getSigHash($sigHashType) |
|
1008 | |||
1009 | /** |
||
1010 | * Pure function to produce a signature for a given $key, $scriptCode, $sigHashType, $sigVersion. |
||
1011 | * |
||
1012 | * @param PrivateKeyInterface $key |
||
1013 | * @param ScriptInterface $scriptCode |
||
1014 | * @param int $sigHashType |
||
1015 | * @param int $sigVersion |
||
1016 | * @return TransactionSignatureInterface |
||
1017 | */ |
||
1018 | 126 | private function calculateSignature(PrivateKeyInterface $key, ScriptInterface $scriptCode, $sigHashType, $sigVersion) |
|
1024 | |||
1025 | /** |
||
1026 | * Returns whether all required signatures have been provided. |
||
1027 | * |
||
1028 | * @return bool |
||
1029 | */ |
||
1030 | 74 | public function isFullySigned() |
|
1046 | |||
1047 | /** |
||
1048 | * Returns the required number of signatures for this input. |
||
1049 | * |
||
1050 | * @return int |
||
1051 | */ |
||
1052 | 74 | public function getRequiredSigs() |
|
1062 | |||
1063 | /** |
||
1064 | * Returns an array where the values are either null, |
||
1065 | * or a TransactionSignatureInterface. |
||
1066 | * |
||
1067 | * @return TransactionSignatureInterface[] |
||
1068 | */ |
||
1069 | 74 | public function getSignatures() |
|
1073 | |||
1074 | /** |
||
1075 | * Returns an array where the values are either null, |
||
1076 | * or a PublicKeyInterface. |
||
1077 | * |
||
1078 | * @return PublicKeyInterface[] |
||
1079 | */ |
||
1080 | 52 | public function getPublicKeys() |
|
1084 | |||
1085 | /** |
||
1086 | * OutputData for the script to be signed (will be |
||
1087 | * equal to getScriptPubKey, or getRedeemScript, or |
||
1088 | * getWitnessScript. |
||
1089 | * |
||
1090 | * @return OutputData |
||
1091 | */ |
||
1092 | 50 | public function getSignScript() |
|
1096 | |||
1097 | /** |
||
1098 | * OutputData for the txOut script. |
||
1099 | * |
||
1100 | * @return OutputData |
||
1101 | */ |
||
1102 | 24 | public function getScriptPubKey() |
|
1106 | |||
1107 | /** |
||
1108 | * Returns OutputData for the P2SH redeemScript. |
||
1109 | * |
||
1110 | * @return OutputData |
||
1111 | */ |
||
1112 | 18 | public function getRedeemScript() |
|
1120 | |||
1121 | /** |
||
1122 | * Returns OutputData for the P2WSH witnessScript. |
||
1123 | * |
||
1124 | * @return OutputData |
||
1125 | */ |
||
1126 | 14 | public function getWitnessScript() |
|
1134 | |||
1135 | /** |
||
1136 | * Returns whether the scriptPubKey is P2SH. |
||
1137 | * |
||
1138 | * @return bool |
||
1139 | */ |
||
1140 | 50 | public function isP2SH() |
|
1148 | |||
1149 | /** |
||
1150 | * Returns whether the scriptPubKey or redeemScript is P2WSH. |
||
1151 | * |
||
1152 | * @return bool |
||
1153 | */ |
||
1154 | 50 | public function isP2WSH() |
|
1168 | |||
1169 | /** |
||
1170 | * @param int $stepIdx |
||
1171 | * @param PrivateKeyInterface $privateKey |
||
1172 | * @param int $sigHashType |
||
1173 | * @return $this |
||
1174 | */ |
||
1175 | 132 | public function signStep($stepIdx, PrivateKeyInterface $privateKey, $sigHashType = SigHash::ALL) |
|
1239 | |||
1240 | /** |
||
1241 | * Sign the input using $key and $sigHashTypes |
||
1242 | * |
||
1243 | * @param PrivateKeyInterface $privateKey |
||
1244 | * @param int $sigHashType |
||
1245 | * @return $this |
||
1246 | */ |
||
1247 | 86 | public function sign(PrivateKeyInterface $privateKey, $sigHashType = SigHash::ALL) |
|
1251 | |||
1252 | /** |
||
1253 | * Verifies the input using $flags for script verification |
||
1254 | * |
||
1255 | * @param int $flags |
||
1256 | * @return bool |
||
1257 | */ |
||
1258 | 96 | public function verify($flags = null) |
|
1292 | |||
1293 | /** |
||
1294 | * @return array |
||
1295 | */ |
||
1296 | 126 | private function serializeSteps() |
|
1328 | |||
1329 | /** |
||
1330 | * Produces a SigValues instance containing the scriptSig & script witness |
||
1331 | * |
||
1332 | * @return SigValues |
||
1333 | */ |
||
1334 | 126 | public function serializeSignatures() |
|
1368 | |||
1369 | 50 | public function getSteps() |
|
1373 | } |
||
1374 |