Completed
Pull Request — master (#593)
by thomas
15:02
created

Signer::setCheckerCreator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 9
ccs 0
cts 5
cp 0
crap 6
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Transaction\Factory;
6
7
use BitWasp\Bitcoin\Bitcoin;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\EcSerializer;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Key\PublicKeySerializerInterface;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
13
use BitWasp\Bitcoin\Exceptions\SignerException;
14
use BitWasp\Bitcoin\Serializer\Signature\TransactionSignatureSerializer;
15
use BitWasp\Bitcoin\Transaction\Factory\Checker\BitcoinCashCheckerCreator;
16
use BitWasp\Bitcoin\Transaction\Factory\Checker\CheckerCreator;
17
use BitWasp\Bitcoin\Transaction\Factory\Checker\CheckerCreatorBase;
18
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
19
use BitWasp\Bitcoin\Transaction\TransactionFactory;
20
use BitWasp\Bitcoin\Transaction\TransactionInterface;
21
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
22
23
class Signer
24
{
25
    /**
26
     * @var EcAdapterInterface
27
     */
28
    private $ecAdapter;
29
30
    /**
31
     * @var TransactionInterface
32
     */
33
    private $tx;
34
35
    /**
36
     * @var TransactionSignatureSerializer
37
     */
38
    private $sigSerializer;
39
40
    /**
41
     * @var PublicKeySerializerInterface
42
     */
43
    private $pubKeySerializer;
44
45
    /**
46
     * @var bool
47
     */
48
    private $tolerateInvalidPublicKey = false;
49
50
    /**
51
     * @var bool
52
     */
53
    private $padUnsignedMultisigs = false;
54
55
    /**
56
     * @var bool
57
     */
58
    private $allowComplexScripts = false;
59
60
    /**
61
     * @var CheckerCreator
62
     */
63
    private $checkerCreator;
64
65
    /**
66
     * @var InputSignerInterface[]
67
     */
68
    private $signatureCreator = [];
69
70
    /**
71
     * TxWitnessSigner constructor.
72
     * @param TransactionInterface $tx
73
     * @param EcAdapterInterface $ecAdapter
74
     */
75 109
    public function __construct(TransactionInterface $tx, EcAdapterInterface $ecAdapter = null)
76
    {
77 109
        $this->tx = $tx;
78 109
        $this->ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
79 109
        $this->sigSerializer = new TransactionSignatureSerializer(EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter));
80 109
        $this->pubKeySerializer = EcSerializer::getSerializer(PublicKeySerializerInterface::class, true, $this->ecAdapter);
81 109
        $this->checkerCreator = new CheckerCreator($this->ecAdapter, $this->sigSerializer, $this->pubKeySerializer);
82
    }
83
84
    /**
85
     * @return $this
86
     * @throws SignerException
87
     */
88
    public function redeemBitcoinCash()
89
    {
90
        $this->setCheckerCreator(new BitcoinCashCheckerCreator($this->ecAdapter, $this->sigSerializer, $this->pubKeySerializer));
91
        return $this;
92
    }
93
94
    /**
95
     * @param CheckerCreatorBase $checker
96
     * @return $this
97
     * @throws SignerException
98
     */
99
    public function setCheckerCreator(CheckerCreatorBase $checker)
100
    {
101
        if (empty($this->signatureCreator)) {
102
            $this->checkerCreator = $checker;
0 ignored issues
show
Documentation Bug introduced by
It seems like $checker of type object<BitWasp\Bitcoin\T...ker\CheckerCreatorBase> is incompatible with the declared type object<BitWasp\Bitcoin\T...Checker\CheckerCreator> of property $checkerCreator.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
103
            return $this;
104
        } else {
105
            throw new SignerException("Cannot change CheckerCreator after inputs have been parsed");
106
        }
107
    }
108
109
    /**
110
     * @param bool $setting
111
     * @return $this
112
     */
113
    public function padUnsignedMultisigs(bool $setting)
114
    {
115
        $this->padUnsignedMultisigs = $setting;
116
        return $this;
117
    }
118
119
    /**
120
     * @param bool $setting
121
     * @return $this
122
     */
123
    public function tolerateInvalidPublicKey(bool $setting)
124
    {
125
        $this->tolerateInvalidPublicKey = $setting;
126
        return $this;
127
    }
128
129
    /**
130
     * @param bool $setting
131
     * @return $this
132
     */
133
    public function allowComplexScripts(bool $setting)
134
    {
135
        $this->allowComplexScripts = $setting;
136
        return $this;
137
    }
138
139
    /**
140
     * @param int $nIn
141
     * @param PrivateKeyInterface $key
142
     * @param TransactionOutputInterface $txOut
143
     * @param SignData $signData
144
     * @param int $sigHashType
145
     * @return $this
146
     */
147
    public function sign(int $nIn, PrivateKeyInterface $key, TransactionOutputInterface $txOut, SignData $signData = null, int $sigHashType = SigHash::ALL)
148
    {
149
        $input = $this->input($nIn, $txOut, $signData);
150
        foreach ($input->getSteps() as $idx => $step) {
151
            $input->sign($key, $sigHashType);
152
        }
153
154
        return $this;
155
    }
156
157
    /**
158
     * @param int $nIn
159
     * @param TransactionOutputInterface $txOut
160
     * @param SignData|null $signData
161
     * @return InputSignerInterface
162
     */
163
    public function input(int $nIn, TransactionOutputInterface $txOut, SignData $signData = null): InputSignerInterface
164
    {
165
        if (null === $signData) {
166
            $signData = new SignData();
167
        }
168
169
        if (!isset($this->signatureCreator[$nIn])) {
170
            $checker = $this->checkerCreator->create($this->tx, $nIn, $txOut);
171
            $input = new InputSigner($this->ecAdapter, $this->tx, $nIn, $txOut, $signData, $checker, $this->sigSerializer, $this->pubKeySerializer);
172
            $input->padUnsignedMultisigs($this->padUnsignedMultisigs);
173
            $input->tolerateInvalidPublicKey($this->tolerateInvalidPublicKey);
174
            $input->allowComplexScripts($this->allowComplexScripts);
175
            $input->extract();
176
177
            $this->signatureCreator[$nIn] = $input;
178
        }
179
180
        return $this->signatureCreator[$nIn];
181
    }
182
183
    /**
184
     * @return TransactionInterface
185
     */
186
    public function get(): TransactionInterface
187
    {
188
        $mutable = TransactionFactory::mutate($this->tx);
189
        $witnesses = [];
190
        foreach ($mutable->inputsMutator() as $idx => $input) {
191
            if (isset($this->signatureCreator[$idx])) {
192
                $sig = $this->signatureCreator[$idx]->serializeSignatures();
193
                $input->script($sig->getScriptSig());
194
                $witnesses[$idx] = $sig->getScriptWitness();
195
            }
196
        }
197
198
        if (count($witnesses) > 0) {
199
            $mutable->witness($witnesses);
200
        }
201
202
        return $mutable->done();
203
    }
204
}
205