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

Signer::tolerateInvalidPublicKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 9.4285
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 109
    }
83
84
    /**
85
     * @return $this
86
     * @throws SignerException
87
     */
88 1
    public function redeemBitcoinCash()
89
    {
90 1
        $this->setCheckerCreator(new BitcoinCashCheckerCreator($this->ecAdapter, $this->sigSerializer, $this->pubKeySerializer));
91 1
        return $this;
92
    }
93
94
    /**
95
     * @param CheckerCreatorBase $checker
96
     * @return $this
97
     * @throws SignerException
98
     */
99 1
    public function setCheckerCreator(CheckerCreatorBase $checker)
100
    {
101 1
        if (empty($this->signatureCreator)) {
102 1
            $this->checkerCreator = $checker;
0 ignored issues
show
Documentation Bug introduced by
$checker is of type object<BitWasp\Bitcoin\T...ker\CheckerCreatorBase>, but the property $checkerCreator was declared to be of type object<BitWasp\Bitcoin\T...Checker\CheckerCreator>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
103 1
            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 14
    public function padUnsignedMultisigs(bool $setting)
114
    {
115 14
        $this->padUnsignedMultisigs = $setting;
116 14
        return $this;
117
    }
118
119
    /**
120
     * @param bool $setting
121
     * @return $this
122
     */
123 2
    public function tolerateInvalidPublicKey(bool $setting)
124
    {
125 2
        $this->tolerateInvalidPublicKey = $setting;
126 2
        return $this;
127
    }
128
129
    /**
130
     * @param bool $setting
131
     * @return $this
132
     */
133 33
    public function allowComplexScripts(bool $setting)
134
    {
135 33
        $this->allowComplexScripts = $setting;
136 33
        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 50
    public function sign(int $nIn, PrivateKeyInterface $key, TransactionOutputInterface $txOut, SignData $signData = null, int $sigHashType = SigHash::ALL)
148
    {
149 50
        $input = $this->input($nIn, $txOut, $signData);
150 50
        foreach ($input->getSteps() as $idx => $step) {
151 50
            $input->sign($key, $sigHashType);
152
        }
153
154 50
        return $this;
155
    }
156
157
    /**
158
     * @param int $nIn
159
     * @param TransactionOutputInterface $txOut
160
     * @param SignData|null $signData
161
     * @return InputSignerInterface
162
     */
163 108
    public function input(int $nIn, TransactionOutputInterface $txOut, SignData $signData = null): InputSignerInterface
164
    {
165 108
        if (null === $signData) {
166 11
            $signData = new SignData();
167
        }
168
169 108
        if (!isset($this->signatureCreator[$nIn])) {
170 108
            $checker = $this->checkerCreator->create($this->tx, $nIn, $txOut);
171 108
            $input = new InputSigner($this->ecAdapter, $this->tx, $nIn, $txOut, $signData, $checker, $this->sigSerializer, $this->pubKeySerializer);
172 108
            $input->padUnsignedMultisigs($this->padUnsignedMultisigs);
173 108
            $input->tolerateInvalidPublicKey($this->tolerateInvalidPublicKey);
174 108
            $input->allowComplexScripts($this->allowComplexScripts);
175 108
            $input->extract();
176
177 96
            $this->signatureCreator[$nIn] = $input;
178
        }
179
180 96
        return $this->signatureCreator[$nIn];
181
    }
182
183
    /**
184
     * @return TransactionInterface
185
     */
186 84
    public function get(): TransactionInterface
187
    {
188 84
        $mutable = TransactionFactory::mutate($this->tx);
189 84
        $witnesses = [];
190 84
        foreach ($mutable->inputsMutator() as $idx => $input) {
191 84
            if (isset($this->signatureCreator[$idx])) {
192 83
                $sig = $this->signatureCreator[$idx]->serializeSignatures();
193 83
                $input->script($sig->getScriptSig());
194 84
                $witnesses[$idx] = $sig->getScriptWitness();
195
            }
196
        }
197
198 84
        if (count($witnesses) > 0) {
199 83
            $mutable->witness($witnesses);
200
        }
201
202 84
        return $mutable->done();
203
    }
204
}
205