Completed
Pull Request — master (#384)
by thomas
66:15 queued 63:52
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 8
        } 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 16
        }
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 8
            }
148 20
        }
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 4
            }
155 8
        }
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 16
                }
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 16
                }
173 16
            }
174 16
        }
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
188 84
        if ($type === OutputClassifier::PAYTOPUBKEYHASH || $type === OutputClassifier::PAYTOPUBKEY || $type === OutputClassifier::MULTISIG) {
189 42
            $values = [];
190 42
            foreach ($scriptSig->getScriptParser()->decode() as $o) {
191 18
                $values[] = $o->getData();
192 28
            }
193
194 66
            $this->extractFromValues($type, $scriptPubKey, $values, 0);
195 28
        }
196
197 84
        if ($type === OutputClassifier::PAYTOSCRIPTHASH) {
198 24
            $decodeSig = $scriptSig->getScriptParser()->decode();
199 24
            if (count($decodeSig) > 0) {
200 18
                $redeemScript = new Script(end($decodeSig)->getData());
201 18
                $p2shType = $this->classifier->classify($redeemScript);
202
203 18
                if (count($decodeSig) > 1) {
204 6
                    $decodeSig = array_slice($decodeSig, 0, -1);
205 4
                }
206
207 18
                $internalSig = [];
208 18
                foreach ($decodeSig as $operation) {
209 18
                    $internalSig[] = $operation->getData();
210 12
                }
211
212 18
                $this->redeemScript = $redeemScript;
213 18
                $this->extractFromValues($p2shType, $redeemScript, $internalSig, 0);
214
215 18
                $type = $p2shType;
216 12
            }
217 16
        }
218
219 84
        $witnesses = $this->tx->getWitnesses();
220 84
        if ($type === OutputClassifier::WITNESS_V0_KEYHASH) {
221 12
            $this->requiredSigs = 1;
222 12
            if (isset($witnesses[$this->nInput])) {
223 12
                $witness = $witnesses[$this->nInput];
224 12
                $this->signatures = [TransactionSignatureFactory::fromHex($witness[0], $this->ecAdapter)];
225 12
                $this->publicKeys = [PublicKeyFactory::fromHex($witness[1], $this->ecAdapter)];
226 8
            }
227 82
        } else if ($type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
228 18
            if (isset($witnesses[$this->nInput])) {
229 18
                $witness = $witnesses[$this->nInput];
230 18
                $witCount = count($witnesses[$this->nInput]);
231 18
                if ($witCount > 0) {
232 18
                    $witnessScript = new Script($witness[$witCount - 1]);
233 18
                    $vWitness = $witness->all();
234 18
                    if (count($vWitness) > 1) {
235 18
                        $vWitness = array_slice($witness->all(), 0, -1);
236 12
                    }
237
238 18
                    $witnessType = $this->classifier->classify($witnessScript);
239 18
                    $this->extractFromValues($witnessType, $witnessScript, $vWitness, 1);
240 18
                    $this->witnessScript = $witnessScript;
241 12
                }
242 12
            }
243 12
        }
244
245 84
        return $this;
246
    }
247
248
    /**
249
     * @param ScriptInterface $scriptCode
250
     * @param int $sigHashType
251
     * @param int $sigVersion
252
     * @return BufferInterface
253
     */
254 84
    public function calculateSigHash(ScriptInterface $scriptCode, $sigHashType, $sigVersion)
255
    {
256 84
        if ($sigVersion === 1) {
257 30
            $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
258 20
        } else {
259 54
            $hasher = new Hasher($this->tx);
260
        }
261
262 84
        return $hasher->calculate($scriptCode, $this->nInput, $sigHashType);
263
    }
264
265
    /**
266
     * @param PrivateKeyInterface $key
267
     * @param ScriptInterface $scriptCode
268
     * @param int $sigHashType
269
     * @param int $sigVersion
270
     * @return TransactionSignature
271
     */
272 84
    public function calculateSignature(PrivateKeyInterface $key, ScriptInterface $scriptCode, $sigHashType, $sigVersion)
273
    {
274 84
        $hash = $this->calculateSigHash($scriptCode, $sigHashType, $sigVersion);
275 84
        return new TransactionSignature(
276 84
            $this->ecAdapter,
277 84
            $this->ecAdapter->sign(
278 56
                $hash,
279 56
                $key,
280 84
                new Rfc6979(
281 84
                    $this->ecAdapter,
282 56
                    $key,
283 56
                    $hash,
284 28
                    'sha256'
285 56
                )
286 56
            ),
287
            $sigHashType
288 56
        );
289
    }
290
291
    /**
292
     * @return bool
293
     */
294 78
    public function isFullySigned()
295
    {
296 78
        return $this->requiredSigs !== 0 && $this->requiredSigs === count($this->signatures);
297
    }
298
299
    /**
300
     * The function only returns true when $scriptPubKey could be classified
301
     *
302
     * @param PrivateKeyInterface $key
303
     * @param ScriptInterface $scriptPubKey
304
     * @param string $outputType
305
     * @param BufferInterface[] $results
306
     * @param int $sigHashType
307
     * @param int $sigVersion
308
     * @return bool
309
     */
310 84
    private function doSignature(PrivateKeyInterface $key, ScriptInterface $scriptPubKey, &$outputType, array &$results, $sigHashType, $sigVersion = 0)
311
    {
312 84
        $return = [];
313 84
        $outputType = $this->classifier->classify($scriptPubKey, $return);
314 84
        if ($outputType === OutputClassifier::UNKNOWN) {
315
            throw new \RuntimeException('Cannot sign unknown script type');
316
        }
317
318 84
        if ($outputType === OutputClassifier::PAYTOPUBKEY) {
319
            /** @var BufferInterface $return */
320 12
            $results[] = $return;
321 12
            $this->requiredSigs = 1;
322 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...
323 12
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
324 8
            }
325
326 12
            return true;
327
        }
328
329 72
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH) {
330
            /** @var BufferInterface $return */
331 42
            $results[] = $return;
332 42
            $this->requiredSigs = 1;
333 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...
334 36
                $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
335 36
                $this->publicKeys[0] = $key->getPublicKey();
336 24
            }
337
338 42
            return true;
339
        }
340
341 48
        if ($outputType === OutputClassifier::MULTISIG) {
342 30
            $info = new Multisig($scriptPubKey);
343 30
            $this->publicKeys = $info->getKeys();
344 30
            $this->requiredSigs = $info->getKeyCount();
345
346 30
            $myKey = $key->getPublicKey()->getBuffer();
347 30
            foreach ($info->getKeys() as $keyIdx => $publicKey) {
348 30
                $results[] = $publicKey->getBuffer();
349 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...
350 30
                    $this->signatures[$keyIdx] = $this->calculateSignature($key, $scriptPubKey, $sigHashType, $sigVersion);
351 20
                }
352 20
            }
353
354 30
            return true;
355
        }
356
357 42
        if ($outputType === OutputClassifier::PAYTOSCRIPTHASH) {
358
            /** @var BufferInterface $scriptHash */
359 24
            $scriptHash = $return;
360 24
            $results[] = $scriptHash;
361 24
            return true;
362
        }
363
364 30
        if ($outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
365
            /** @var BufferInterface $pubKeyHash */
366 12
            $pubKeyHash = $return;
367 12
            $results[] = $pubKeyHash;
368 12
            $this->requiredSigs = 1;
369
370 12
            if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) {
371 12
                $script = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
372 12
                $this->signatures[0] = $this->calculateSignature($key, $script, $sigHashType, 1);
373 12
                $this->publicKeys[0] = $key->getPublicKey();
374 8
            }
375
376 12
            return true;
377
        }
378
379 18
        if ($outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
380
            /** @var BufferInterface $scriptHash */
381 18
            $scriptHash = $return;
382 18
            $results[] = $scriptHash;
383
384 18
            return true;
385
        }
386
387
        return false;
388
    }
389
390
    /**
391
     * @param PrivateKeyInterface $key
392
     * @param ScriptInterface|null $redeemScript
393
     * @param ScriptInterface|null $witnessScript
394
     * @param int $sigHashType
395
     * @return bool
396
     */
397 84
    public function sign(PrivateKeyInterface $key, ScriptInterface $redeemScript = null, ScriptInterface $witnessScript = null, $sigHashType = SigHashInterface::ALL)
398
    {
399
        /** @var BufferInterface[] $return */
400 84
        $type = null;
401 84
        $return = [];
402 84
        $solved = $this->doSignature($key, $this->txOut->getScript(), $type, $return, $sigHashType, 0);
403
404 84
        if ($solved && $type === OutputClassifier::PAYTOSCRIPTHASH) {
405 24
            $redeemScriptBuffer = $return[0];
406
407 24
            if (!$redeemScript instanceof ScriptInterface) {
408
                throw new \InvalidArgumentException('Must provide redeem script for P2SH');
409
            }
410
411 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...
412
                throw new \InvalidArgumentException("Incorrect redeem script - hash doesn't match");
413
            }
414
415 24
            $results = []; // ???
416 24
            $solved = $solved && $this->doSignature($key, $redeemScript, $type, $results, $sigHashType, 0) && $type !== OutputClassifier::PAYTOSCRIPTHASH;
417 24
            if ($solved) {
418 24
                $this->redeemScript = $redeemScript;
419 16
            }
420 16
        }
421
422 84
        if ($solved && $type === OutputClassifier::WITNESS_V0_KEYHASH) {
423 12
            $pubKeyHash = $return[0];
424 12
            $witnessScript = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]);
425 12
            $subType = null;
426 12
            $subResults = [];
427 12
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, $sigHashType, 1);
428 80
        } else if ($solved && $type === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
429 18
            $scriptHash = $return[0];
430
431 18
            if (!$witnessScript instanceof ScriptInterface) {
432
                throw new \InvalidArgumentException('Must provide witness script for witness v0 scripthash');
433
            }
434
435 18
            if (!Hash::sha256($witnessScript->getBuffer())->getBinary() === $scriptHash->getBinary()) {
436
                throw new \InvalidArgumentException("Incorrect witness script - hash doesn't match");
437
            }
438
439 18
            $subType = null;
440 18
            $subResults = [];
441
442 18
            $solved = $solved && $this->doSignature($key, $witnessScript, $subType, $subResults, $sigHashType, 1)
443 18
                && $subType !== OutputClassifier::PAYTOSCRIPTHASH
444 18
                && $subType !== OutputClassifier::WITNESS_V0_SCRIPTHASH
445 18
                && $subType !== OutputClassifier::WITNESS_V0_KEYHASH;
446
447 18
            if ($solved) {
448 18
                $this->witnessScript = $witnessScript;
449 12
            }
450 12
        }
451
452 84
        return $solved;
453
    }
454
455
    /**
456
     * @param string $outputType
457
     * @param $answer
458
     * @return bool
459
     */
460 84
    private function serializeSimpleSig($outputType, &$answer)
461
    {
462 84
        if ($outputType === OutputClassifier::UNKNOWN) {
463
            throw new \RuntimeException('Cannot sign unknown script type');
464
        }
465
466 84
        if ($outputType === OutputClassifier::PAYTOPUBKEY && $this->isFullySigned()) {
467 12
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer()]), new ScriptWitness([]));
468 12
            return true;
469
        }
470
471 72
        if ($outputType === OutputClassifier::PAYTOPUBKEYHASH && $this->isFullySigned()) {
472 30
            $answer = new SigValues(ScriptFactory::sequence([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]), new ScriptWitness([]));
473 30
            return true;
474
        }
475
476 48
        if ($outputType === OutputClassifier::MULTISIG) {
477 30
            $sequence = [Opcodes::OP_0];
478 30
            $nPubKeys = count($this->publicKeys);
479 30
            for ($i = 0; $i < $nPubKeys; $i++) {
480 30
                if (isset($this->signatures[$i])) {
481 30
                    $sequence[] = $this->signatures[$i]->getBuffer();
482 20
                }
483 20
            }
484
485 30
            $answer = new SigValues(ScriptFactory::sequence($sequence), new ScriptWitness([]));
486 30
            return true;
487
        }
488
489 42
        return false;
490
    }
491
492
    /**
493
     * @return SigValues
494
     */
495 84
    public function serializeSignatures()
496
    {
497 84
        static $emptyScript = null;
498 84
        static $emptyWitness = null;
499 84
        if (is_null($emptyScript) || is_null($emptyWitness)) {
500 6
            $emptyScript = new Script();
501 6
            $emptyWitness = new ScriptWitness([]);
502 4
        }
503
504
        /** @var BufferInterface[] $return */
505 84
        $outputType = $this->classifier->classify($this->txOut->getScript());
506
507
        /** @var SigValues $answer */
508 84
        $answer = new SigValues($emptyScript, $emptyWitness);
509 84
        $serialized = $this->serializeSimpleSig($outputType, $answer);
510
511 84
        $p2sh = false;
512 84
        if (!$serialized && $outputType === OutputClassifier::PAYTOSCRIPTHASH) {
513 24
            $p2sh = true;
514 24
            $outputType = $this->classifier->classify($this->redeemScript);
515 24
            $serialized = $this->serializeSimpleSig($outputType, $answer);
516 16
        }
517
518 84
        if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_KEYHASH) {
519 12
            $answer = new SigValues($emptyScript, new ScriptWitness([$this->signatures[0]->getBuffer(), $this->publicKeys[0]->getBuffer()]));
520 80
        } else if (!$serialized && $outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) {
521 18
            $outputType = $this->classifier->classify($this->witnessScript);
522 18
            $serialized = $this->serializeSimpleSig($outputType, $answer);
523
524 18
            if ($serialized) {
525 18
                $data = [];
526 18
                foreach ($answer->getScriptSig()->getScriptParser()->decode() as $o) {
527 18
                    $data[] = $o->getData();
528 12
                }
529
530 18
                $data[] = $this->witnessScript->getBuffer();
531 18
                $answer = new SigValues($emptyScript, new ScriptWitness($data));
532 12
            }
533 12
        }
534
535 84
        if ($p2sh) {
536 24
            $answer = new SigValues(
537 24
                ScriptFactory::create($answer->getScriptSig()->getBuffer())->push($this->redeemScript->getBuffer())->getScript(),
538 24
                $answer->getScriptWitness()
539 16
            );
540 16
        }
541
542 84
        return $answer;
543
    }
544
}
545