Completed
Push — master ( f7b67d...189a61 )
by thomas
53:21 queued 33:10
created

InputSigner::extractFromValues()   D

Complexity

Conditions 10
Paths 27

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 10.0033

Importance

Changes 0
Metric Value
cc 10
eloc 23
c 0
b 0
f 0
nc 27
nop 4
dl 0
loc 39
ccs 30
cts 31
cp 0.9677
crap 10.0033
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Factory;
4
5
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
8
use BitWasp\Bitcoin\Crypto\Hash;
9
use BitWasp\Bitcoin\Crypto\Random\Rfc6979;
10
use BitWasp\Bitcoin\Key\PublicKeyFactory;
11
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier;
12
use BitWasp\Bitcoin\Script\Opcodes;
13
use BitWasp\Bitcoin\Script\Script;
14
use BitWasp\Bitcoin\Script\ScriptFactory;
15
use BitWasp\Bitcoin\Script\ScriptInfo\Multisig;
16
use BitWasp\Bitcoin\Script\ScriptInterface;
17
use BitWasp\Bitcoin\Script\ScriptWitness;
18
use BitWasp\Bitcoin\Signature\SignatureSort;
19
use BitWasp\Bitcoin\Signature\TransactionSignature;
20
use BitWasp\Bitcoin\Signature\TransactionSignatureFactory;
21
use BitWasp\Bitcoin\Signature\TransactionSignatureInterface;
22
use BitWasp\Bitcoin\Transaction\SignatureHash\Hasher;
23
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHashInterface;
24
use BitWasp\Bitcoin\Transaction\SignatureHash\V1Hasher;
25
use BitWasp\Bitcoin\Transaction\TransactionInterface;
26
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
27
use BitWasp\Buffertools\BufferInterface;
28
29
class InputSigner
30
{
31
    /**
32
     * @var EcAdapterInterface
33
     */
34
    private $ecAdapter;
35
36
    /**
37
     * @var ScriptInterface $redeemScript
38
     */
39
    private $redeemScript;
40
41
    /**
42
     * @var ScriptInterface $witnessScript
43
     */
44
    private $witnessScript;
45
46
    /**
47
     * @var TransactionInterface
48
     */
49
    private $tx;
50
51
    /**
52
     * @var int
53
     */
54
    private $nInput;
55
56
    /**
57
     * @var TransactionOutputInterface
58
     */
59
    private $txOut;
60
61
    /**
62
     * @var PublicKeyInterface[]
63
     */
64
    private $publicKeys = [];
65
66
    /**
67
     * @var TransactionSignatureInterface[]
68
     */
69
    private $signatures = [];
70
71
    /**
72
     * @var int
73
     */
74
    private $requiredSigs = 0;
75
76
    /**
77
     * @var OutputClassifier
78
     */
79
    private $classifier;
80
81
    /**
82
     * TxInputSigning constructor.
83
     * @param EcAdapterInterface $ecAdapter
84
     * @param TransactionInterface $tx
85
     * @param int $nInput
86
     * @param TransactionOutputInterface $txOut
87
     */
88 84
    public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $tx, $nInput, TransactionOutputInterface $txOut)
89
    {
90 84
        $this->ecAdapter = $ecAdapter;
91 84
        $this->tx = $tx;
92 84
        $this->nInput = $nInput;
93 84
        $this->txOut = $txOut;
94 84
        $this->classifier = new OutputClassifier();
95 84
        $this->publicKeys = [];
96 84
        $this->signatures = [];
97
98 84
        $this->extractSignatures();
99 84
    }
100
101
    /**
102
     * @param int $sigVersion
103
     * @param TransactionSignatureInterface[] $stack
104
     * @param ScriptInterface $scriptCode
105
     * @return \SplObjectStorage
106
     */
107 24
    private function sortMultiSigs($sigVersion, $stack, ScriptInterface $scriptCode)
108
    {
109 24
        if ($sigVersion === 1) {
110 12
            $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
111 4
        } else {
112 12
            $hasher = new Hasher($this->tx);
113
        }
114
115 24
        $sigSort = new SignatureSort($this->ecAdapter);
116 24
        $sigs = new \SplObjectStorage;
117
118 24
        foreach ($stack as $txSig) {
119
            $hash = $hasher->calculate($scriptCode, $this->nInput, $txSig->getHashType());
120
            $linked = $sigSort->link([$txSig->getSignature()], $this->publicKeys, $hash);
121
122
            foreach ($this->publicKeys as $key) {
123
                if ($linked->contains($key)) {
124
                    $sigs[$key] = $txSig;
125
                }
126
            }
127 8
        }
128
129 24
        return $sigs;
130
    }
131
132
    /**
133
     * @param string $type
134
     * @param ScriptInterface $scriptCode
135
     * @param BufferInterface[] $stack
136
     * @param int $sigVersion
137
     * @return string
138
     */
139 72
    public function extractFromValues($type, ScriptInterface $scriptCode, array $stack, $sigVersion)
140
    {
141 72
        $size = count($stack);
142 72
        if ($type === OutputClassifier::PAYTOPUBKEYHASH) {
143 30
            $this->requiredSigs = 1;
144 30
            if ($size === 2) {
145 12
                $this->signatures = [TransactionSignatureFactory::fromHex($stack[0], $this->ecAdapter)];
146 12
                $this->publicKeys = [PublicKeyFactory::fromHex($stack[1], $this->ecAdapter)];
147 4
            }
148 10
        }
149
150 72
        if ($type === OutputClassifier::PAYTOPUBKEY) {
151 12
            $this->requiredSigs = 1;
152 12
            if ($size === 1) {
153 6
                $this->signatures = [TransactionSignatureFactory::fromHex($stack[0], $this->ecAdapter)];
154 2
            }
155 4
        }
156
157 72
        if ($type === OutputClassifier::MULTISIG) {
158 24
            $info = new Multisig($scriptCode);
159 24
            $this->requiredSigs = $info->getRequiredSigCount();
160 24
            $this->publicKeys = $info->getKeys();
161
162 24
            if ($size > 1) {
163 24
                $vars = [];
164 24
                foreach (array_slice($stack, 1, -1) as $sig) {
165
                    $vars[] = TransactionSignatureFactory::fromHex($sig, $this->ecAdapter);
166 8
                }
167
168 24
                $sigs = $this->sortMultiSigs($sigVersion, $vars, $scriptCode);
169
170 24
                foreach ($this->publicKeys as $idx => $key) {
171 24
                    $this->signatures[$idx] = isset($sigs[$key]) ? $sigs[$key]->getBuffer() : null;
172 8
                }
173 8
            }
174 8
        }
175
176 72
        return $type;
177
    }
178
179
    /**
180
     * @return $this
181
     */
182 84
    public function extractSignatures()
183
    {
184 84
        $scriptPubKey = $this->txOut->getScript();
185 84
        $scriptSig = $this->tx->getInput($this->nInput)->getScript();
186 84
        $type = $this->classifier->classify($scriptPubKey);
187 84
        if ($type === OutputClassifier::PAYTOPUBKEYHASH || $type === OutputClassifier::PAYTOPUBKEY || $type === OutputClassifier::MULTISIG) {
188 42
            $values = [];
189 42
            foreach ($scriptSig->getScriptParser()->decode() as $o) {
190 18
                $values[] = $o->getData();
191 14
            }
192
193 42
            $this->extractFromValues($type, $scriptPubKey, $values, 0);
194 26
        }
195
196 84
        if ($type === OutputClassifier::PAYTOSCRIPTHASH) {
197 24
            $decodeSig = $scriptSig->getScriptParser()->decode();
198 24
            if (count($decodeSig) > 0) {
199 18
                $redeemScript = new Script(end($decodeSig)->getData());
200 18
                $type = $this->classifier->classify($redeemScript);
201 18
                if (count($decodeSig) > 1) {
202 6
                    $decodeSig = array_slice($decodeSig, 0, -1);
203 2
                }
204
205 18
                $internalSig = [];
206 18
                foreach ($decodeSig as $operation) {
207 18
                    $internalSig[] = $operation->getData();
208 6
                }
209
210 18
                $this->redeemScript = $redeemScript;
211 18
                $this->extractFromValues($type, $redeemScript, $internalSig, 0);
212 6
            }
213 8
        }
214
215 84
        $witnesses = $this->tx->getWitnesses();
216 84
        if ($type === OutputClassifier::WITNESS_V0_KEYHASH) {
217 12
            $this->requiredSigs = 1;
218 12
            if (isset($witnesses[$this->nInput])) {
219 12
                $witness = $witnesses[$this->nInput];
220 12
                $this->signatures = [TransactionSignatureFactory::fromHex($witness[0], $this->ecAdapter)];
221 12
                $this->publicKeys = [PublicKeyFactory::fromHex($witness[1], $this->ecAdapter)];
222 4
            }
223 80
        } else if ($type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
224 18
            if (isset($witnesses[$this->nInput])) {
225 18
                $witness = $witnesses[$this->nInput];
226 18
                $witCount = count($witnesses[$this->nInput]);
227 18
                if ($witCount > 0) {
228 18
                    $witnessScript = new Script($witness[$witCount - 1]);
229 18
                    $vWitness = $witness->all();
230 18
                    if (count($vWitness) > 1) {
231 18
                        $vWitness = array_slice($witness->all(), 0, -1);
232 6
                    }
233
234 18
                    $type = $this->classifier->classify($witnessScript);
235 18
                    $this->extractFromValues($type, $witnessScript, $vWitness, 1);
236 18
                    $this->witnessScript = $witnessScript;
237 6
                }
238 6
            }
239 6
        }
240
241 84
        return $this;
242
    }
243
244
    /**
245
     * @param ScriptInterface $scriptCode
246
     * @param int $sigHashType
247
     * @param int $sigVersion
248
     * @return BufferInterface
249
     */
250 84
    public function calculateSigHash(ScriptInterface $scriptCode, $sigHashType, $sigVersion)
251
    {
252 84
        if ($sigVersion === 1) {
253 30
            $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
254 10
        } else {
255 54
            $hasher = new Hasher($this->tx);
256
        }
257
258 84
        return $hasher->calculate($scriptCode, $this->nInput, $sigHashType);
259
    }
260
261
    /**
262
     * @param PrivateKeyInterface $key
263
     * @param ScriptInterface $scriptCode
264
     * @param int $sigHashType
265
     * @param int $sigVersion
266
     * @return TransactionSignature
267
     */
268 84
    public function calculateSignature(PrivateKeyInterface $key, ScriptInterface $scriptCode, $sigHashType, $sigVersion)
269
    {
270 84
        $hash = $this->calculateSigHash($scriptCode, $sigHashType, $sigVersion);
271 84
        return new TransactionSignature(
272 84
            $this->ecAdapter,
273 84
            $this->ecAdapter->sign(
274 28
                $hash,
275 28
                $key,
276 84
                new Rfc6979(
277 84
                    $this->ecAdapter,
278 28
                    $key,
279 28
                    $hash,
280 56
                    'sha256'
281 28
                )
282 28
            ),
283
            $sigHashType
284 28
        );
285
    }
286
287
    /**
288
     * @return bool
289
     */
290 78
    public function isFullySigned()
291
    {
292 78
        return $this->requiredSigs !== 0 && $this->requiredSigs === count($this->signatures);
293
    }
294
295
    /**
296
     * The function only returns true when $scriptPubKey could be classified
297
     *
298
     * @param PrivateKeyInterface $key
299
     * @param ScriptInterface $scriptPubKey
300
     * @param string $outputType
301
     * @param BufferInterface[] $results
302
     * @param int $sigHashType
303
     * @param int $sigVersion
304
     * @return bool
305
     */
306 84
    private function doSignature(PrivateKeyInterface $key, ScriptInterface $scriptPubKey, &$outputType, array &$results, $sigHashType, $sigVersion = 0)
307
    {
308 84
        $return = [];
309 84
        $outputType = $this->classifier->classify($scriptPubKey, $return);
310 84
        if ($outputType === OutputClassifier::UNKNOWN) {
311
            throw new \RuntimeException('Cannot sign unknown script type');
312
        }
313
314 84
        if ($outputType === OutputClassifier::PAYTOPUBKEY) {
315
            /** @var BufferInterface $return */
316 12
            $results[] = $return;
317 12
            $this->requiredSigs = 1;
318 12
            if ($key->getPublicKey()->getBuffer()->equals($return)) {
0 ignored issues
show
Documentation introduced by
$return is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
319 12
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
320 4
            }
321
322 12
            return true;
323
        }
324
325 72
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH) {
326
            /** @var BufferInterface $return */
327 42
            $results[] = $return;
328 42
            $this->requiredSigs = 1;
329 42
            if ($key->getPublicKey()->getPubKeyHash()->equals($return)) {
0 ignored issues
show
Documentation introduced by
$return is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
330 36
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
331 36
                $this->publicKeys[0] = $key->getPublicKey();
332 12
            }
333
334 42
            return true;
335
        }
336
337 48
        if ($outputType === OutputClassifier::MULTISIG) {
338 30
            $info = new Multisig($scriptPubKey);
339 30
            $this->publicKeys = $info->getKeys();
340 30
            $this->requiredSigs = $info->getKeyCount();
341
342 30
            $myKey = $key->getPublicKey()->getBuffer();
343 30
            foreach ($info->getKeys() as $keyIdx => $publicKey) {
344 30
                $results[] = $publicKey->getBuffer();
345 30
                if ($publicKey->getBuffer()->equals($myKey)) {
0 ignored issues
show
Documentation introduced by
$myKey is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
346 30
                    $this->signatures[$keyIdx] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
347 10
                }
348 10
            }
349
350 30
            return true;
351
        }
352
353 42
        if ($outputType === OutputClassifier::PAYTOSCRIPTHASH) {
354
            /** @var BufferInterface $scriptHash */
355 24
            $scriptHash = $return;
356 24
            $results[] = $scriptHash;
357 24
            return true;
358
        }
359
360 30
        if ($outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
361
            /** @var BufferInterface $pubKeyHash */
362 12
            $pubKeyHash = $return;
363 12
            $results[] = $pubKeyHash;
364 12
            $this->requiredSigs = 1;
365
366 12
            if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) {
367 12
                $script = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
368 12
                $this->signatures[0] = $this->calculateSignature($key, $script, $sigHashType, 1);
369 12
                $this->publicKeys[0] = $key->getPublicKey();
370 4
            }
371
372 12
            return true;
373
        }
374
375 18
        if ($outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
376
            /** @var BufferInterface $scriptHash */
377 18
            $scriptHash = $return;
378 18
            $results[] = $scriptHash;
379
380 18
            return true;
381
        }
382
383
        return false;
384
    }
385
386
    /**
387
     * @param PrivateKeyInterface $key
388
     * @param ScriptInterface|null $redeemScript
389
     * @param ScriptInterface|null $witnessScript
390
     * @param int $sigHashType
391
     * @return bool
392
     */
393 84
    public function sign(PrivateKeyInterface $key, ScriptInterface $redeemScript = null, ScriptInterface $witnessScript = null, $sigHashType = SigHashInterface::ALL)
394
    {
395
        /** @var BufferInterface[] $return */
396 84
        $type = null;
397 84
        $return = [];
398 84
        $solved = $this->doSignature($key, $this->txOut->getScript(), $type, $return, $sigHashType, 0);
399
400 84
        if ($solved && $type === OutputClassifier::PAYTOSCRIPTHASH) {
401 24
            $redeemScriptBuffer = $return[0];
402 24
            if (!$redeemScript instanceof ScriptInterface) {
403
                throw new \InvalidArgumentException('Must provide redeem script for P2SH');
404
            }
405
406 24
            if (!$redeemScript->getScriptHash()->equals($redeemScriptBuffer)) {
0 ignored issues
show
Documentation introduced by
$redeemScriptBuffer is of type object<BitWasp\Buffertools\BufferInterface>, but the function expects a object<self>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
407
                throw new \InvalidArgumentException("Incorrect redeem script - hash doesn't match");
408
            }
409
410 24
            $results = []; // ???
411 24
            $solved = $solved && $this->doSignature($key, $redeemScript, $type, $results, $sigHashType, 0) && $type !== OutputClassifier::PAYTOSCRIPTHASH;
412 24
            if ($solved) {
413 24
                $this->redeemScript = $redeemScript;
414 8
            }
415 8
        }
416
417 84
        if ($solved && $type === OutputClassifier::WITNESS_V0_KEYHASH) {
418 12
            $pubKeyHash = $return[0];
419 12
            $witnessScript = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
420 12
            $subType = null;
421 12
            $subResults = [];
422 12
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, $sigHashType, 1);
423 76
        } else if ($solved && $type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
424 18
            $scriptHash = $return[0];
425
426 18
            if (!$witnessScript instanceof ScriptInterface) {
427
                throw new \InvalidArgumentException('Must provide witness script for witness v0 scripthash');
428
            }
429
430 18
            if (!Hash::sha256($witnessScript->getBuffer())->getBinary() === $scriptHash->getBinary()) {
431
                throw new \InvalidArgumentException("Incorrect witness script - hash doesn't match");
432
            }
433
434 18
            $subType = null;
435 18
            $subResults = [];
436
437 18
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, $sigHashType, 1)
438 18
                && $subType !== OutputClassifier::PAYTOSCRIPTHASH
439 18
                && $subType !== OutputClassifier::WITNESS_V0_SCRIPTHASH
440 18
                && $subType !== OutputClassifier::WITNESS_V0_KEYHASH;
441
442 18
            if ($solved) {
443 18
                $this->witnessScript = $witnessScript;
444 6
            }
445 6
        }
446
447 84
        return $solved;
448
    }
449
450
    /**
451
     * @param string $outputType
452
     * @param $answer
453
     * @return bool
454
     */
455 84
    private function serializeSimpleSig($outputType, &$answer)
456
    {
457 84
        if ($outputType === OutputClassifier::UNKNOWN) {
458
            throw new \RuntimeException('Cannot sign unknown script type');
459
        }
460
461 84
        if ($outputType === OutputClassifier::PAYTOPUBKEY && $this->isFullySigned()) {
462 12
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer()]), new ScriptWitness([]));
463 12
            return true;
464
        }
465
466 72
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH && $this->isFullySigned()) {
467 30
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]), new ScriptWitness([]));
468 30
            return true;
469
        }
470
471 48
        if ($outputType === OutputClassifier::MULTISIG) {
472 30
            $sequence = [Opcodes::OP_0];
473 30
            $nPubKeys = count($this->publicKeys);
474 30
            for ($i = 0; $i < $nPubKeys; $i++) {
475 30
                if (isset($this->signatures[$i])) {
476 30
                    $sequence[] = $this->signatures[$i]->getBuffer();
477 10
                }
478 10
            }
479
480 30
            $answer = new SigValues(ScriptFactory::sequence($sequence), new ScriptWitness([]));
481 30
            return true;
482
        }
483
484 42
        return false;
485
    }
486
487
    /**
488
     * @return SigValues
489
     */
490 84
    public function serializeSignatures()
491
    {
492 84
        static $emptyScript = null;
493 84
        static $emptyWitness = null;
494 84
        if (is_null($emptyScript) || is_null($emptyWitness)) {
495 6
            $emptyScript = new Script();
496 6
            $emptyWitness = new ScriptWitness([]);
497 2
        }
498
499
        /** @var BufferInterface[] $return */
500 84
        $outputType = $this->classifier->classify($this->txOut->getScript());
501
502
        /** @var SigValues $answer */
503 84
        $answer = new SigValues($emptyScript, $emptyWitness);
504 84
        $serialized = $this->serializeSimpleSig($outputType, $answer);
505
506 84
        $p2sh = false;
507 84
        if (!$serialized && $outputType === OutputClassifier::PAYTOSCRIPTHASH) {
508 24
            $p2sh = true;
509 24
            $outputType = $this->classifier->classify($this->redeemScript);
510 24
            $serialized = $this->serializeSimpleSig($outputType, $answer);
511 8
        }
512
513 84
        if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
514 12
            $answer = new SigValues($emptyScript, new ScriptWitness([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]));
515 76
        } else if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
516 18
            $outputType = $this->classifier->classify($this->witnessScript);
517 18
            $serialized = $this->serializeSimpleSig($outputType, $answer);
518 18
            if ($serialized) {
519 18
                $data = [];
520 18
                foreach ($answer->getScriptSig()->getScriptParser()->decode() as $o) {
521 18
                    $data[] = $o->getData();
522 6
                }
523
524 18
                $data[] = $this->witnessScript->getBuffer();
525 18
                $answer = new SigValues($emptyScript, new ScriptWitness($data));
526 6
            }
527 6
        }
528
529 84
        if ($p2sh) {
530 24
            $answer = new SigValues(
531 24
                ScriptFactory::create($answer->getScriptSig()->getBuffer())->push($this->redeemScript->getBuffer())->getScript(),
532 24
                $answer->getScriptWitness()
533 8
            );
534 8
        }
535
536 84
        return $answer;
537
    }
538
}
539