Passed
Push — master ( 61f277...d02c79 )
by thomas
27:07
created

Signer::setCheckerCreator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 7
ccs 0
cts 5
cp 0
crap 6
rs 10
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\CheckerCreator;
16
use BitWasp\Bitcoin\Transaction\Factory\Checker\CheckerCreatorBase;
17
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
18
use BitWasp\Bitcoin\Transaction\TransactionFactory;
19
use BitWasp\Bitcoin\Transaction\TransactionInterface;
20
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
21
22
class Signer
23
{
24
    /**
25
     * @var EcAdapterInterface
26
     */
27
    private $ecAdapter;
28
29
    /**
30
     * @var TransactionInterface
31
     */
32
    private $tx;
33
34
    /**
35
     * @var TransactionSignatureSerializer
36
     */
37
    private $sigSerializer;
38
39
    /**
40
     * @var PublicKeySerializerInterface
41
     */
42
    private $pubKeySerializer;
43
44
    /**
45
     * @var bool
46
     */
47
    private $tolerateInvalidPublicKey = false;
48
49
    /**
50
     * @var bool
51
     */
52
    private $padUnsignedMultisigs = false;
53
54
    /**
55
     * @var bool
56
     */
57
    private $allowComplexScripts = false;
58
59
    /**
60
     * @var CheckerCreatorBase
61
     */
62
    private $checkerCreator;
63
64
    /**
65
     * @var InputSignerInterface[]
66
     */
67
    private $signatureCreator = [];
68
69
    /**
70
     * TxWitnessSigner constructor.
71
     * @param TransactionInterface $tx
72
     * @param EcAdapterInterface $ecAdapter
73
     */
74 114
    public function __construct(TransactionInterface $tx, EcAdapterInterface $ecAdapter = null)
75
    {
76 114
        $this->tx = $tx;
77 114
        $this->ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
78 114
        $this->sigSerializer = new TransactionSignatureSerializer(EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter));
79 114
        $this->pubKeySerializer = EcSerializer::getSerializer(PublicKeySerializerInterface::class, true, $this->ecAdapter);
80 114
        $this->checkerCreator = new CheckerCreator($this->ecAdapter, $this->sigSerializer, $this->pubKeySerializer);
81 114
    }
82
83
    /**
84
     * @param CheckerCreatorBase $checker
85
     * @return $this
86
     * @throws SignerException
87
     */
88
    public function setCheckerCreator(CheckerCreatorBase $checker)
89
    {
90
        if (null === $this->signatureCreator) {
91
            $this->checkerCreator = $checker;
92
            return $this;
93
        } else {
94
            throw new SignerException("Cannot change CheckerCreator after inputs have been parsed");
95
        }
96
    }
97
98
    /**
99
     * @param bool $setting
100
     * @return $this
101
     */
102 14
    public function padUnsignedMultisigs(bool $setting)
103
    {
104 14
        $this->padUnsignedMultisigs = $setting;
105 14
        return $this;
106
    }
107
108
    /**
109
     * @param bool $setting
110
     * @return $this
111
     */
112 2
    public function tolerateInvalidPublicKey(bool $setting)
113
    {
114 2
        $this->tolerateInvalidPublicKey = $setting;
115 2
        return $this;
116
    }
117
118
    /**
119
     * @param bool $setting
120
     * @return $this
121
     */
122 33
    public function allowComplexScripts(bool $setting)
123
    {
124 33
        $this->allowComplexScripts = $setting;
125 33
        return $this;
126
    }
127
128
    /**
129
     * @param int $nIn
130
     * @param PrivateKeyInterface $key
131
     * @param TransactionOutputInterface $txOut
132
     * @param SignData $signData
133
     * @param int $sigHashType
134
     * @return $this
135
     */
136 50
    public function sign(int $nIn, PrivateKeyInterface $key, TransactionOutputInterface $txOut, SignData $signData = null, int $sigHashType = SigHash::ALL)
137
    {
138 50
        $input = $this->input($nIn, $txOut, $signData);
139 50
        foreach ($input->getSteps() as $idx => $step) {
140 50
            $input->sign($key, $sigHashType);
141
        }
142
143 50
        return $this;
144
    }
145
146
    /**
147
     * @param int $nIn
148
     * @param TransactionOutputInterface $txOut
149
     * @param SignData|null $signData
150
     * @return InputSignerInterface
151
     */
152 113
    public function input(int $nIn, TransactionOutputInterface $txOut, SignData $signData = null): InputSignerInterface
153
    {
154 113
        if (null === $signData) {
155 10
            $signData = new SignData();
156
        }
157
158 113
        if (!isset($this->signatureCreator[$nIn])) {
159 113
            $checker = $this->checkerCreator->create($this->tx, $nIn, $txOut);
160 113
            $input = new InputSigner($this->ecAdapter, $this->tx, $nIn, $txOut, $signData, $checker, $this->sigSerializer, $this->pubKeySerializer);
161 113
            $input->padUnsignedMultisigs($this->padUnsignedMultisigs);
162 113
            $input->tolerateInvalidPublicKey($this->tolerateInvalidPublicKey);
163 113
            $input->allowComplexScripts($this->allowComplexScripts);
164 113
            $input->extract();
165
166 101
            $this->signatureCreator[$nIn] = $input;
167
        }
168
169 101
        return $this->signatureCreator[$nIn];
170
    }
171
172
    /**
173
     * @return TransactionInterface
174
     */
175 83
    public function get(): TransactionInterface
176
    {
177 83
        $mutable = TransactionFactory::mutate($this->tx);
178 83
        $witnesses = [];
179 83
        foreach ($mutable->inputsMutator() as $idx => $input) {
180 83
            if (isset($this->signatureCreator[$idx])) {
181 82
                $sig = $this->signatureCreator[$idx]->serializeSignatures();
182 82
                $input->script($sig->getScriptSig());
183 83
                $witnesses[$idx] = $sig->getScriptWitness();
184
            }
185
        }
186
187 83
        if (count($witnesses) > 0) {
188 82
            $mutable->witness($witnesses);
189
        }
190
191 83
        return $mutable->done();
192
    }
193
}
194