Completed
Pull Request — master (#523)
by thomas
73:16
created

Signer::padUnsignedMultisigs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
ccs 2
cts 2
cp 1
crap 2
rs 9.6666
c 1
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Factory;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Crypto\EcAdapter\Adapter\EcAdapterInterface;
7
use BitWasp\Bitcoin\Crypto\EcAdapter\EcSerializer;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PrivateKeyInterface;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Key\PublicKeySerializerInterface;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Serializer\Signature\DerSignatureSerializerInterface;
11
use BitWasp\Bitcoin\Serializer\Signature\TransactionSignatureSerializer;
12
use BitWasp\Bitcoin\Transaction\SignatureHash\SigHash;
13
use BitWasp\Bitcoin\Transaction\TransactionFactory;
14
use BitWasp\Bitcoin\Transaction\TransactionInterface;
15
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
16
17
class Signer
18
{
19
    /**
20
     * @var EcAdapterInterface
21
     */
22
    private $ecAdapter;
23
24
    /**
25
     * @var TransactionInterface
26
     */
27
    private $tx;
28
29
    /**
30
     * @var TransactionSignatureSerializer
31
     */
32
    private $sigSerializer;
33
34
    /**
35
     * @var PublicKeySerializerInterface
36
     */
37
    private $pubKeySerializer;
38
39
    /**
40
     * @var bool
41
     */
42
    private $tolerateInvalidPublicKey = false;
43
44
    /**
45
     * @var bool
46
     */
47
    private $redeemBitcoinCash = false;
48
49
    /**
50
     * @var bool
51
     */
52
    private $padUnsignedMultisigs = false;
53
54
    /**
55
     * @var InputSignerInterface[]
56
     */
57
    private $signatureCreator = [];
58
59 66
    /**
60
     * TxWitnessSigner constructor.
61 66
     * @param TransactionInterface $tx
62 66
     * @param EcAdapterInterface $ecAdapter
63 66
     */
64 66
    public function __construct(TransactionInterface $tx, EcAdapterInterface $ecAdapter = null)
65 66
    {
66
        $this->tx = $tx;
67
        $this->ecAdapter = $ecAdapter ?: Bitcoin::getEcAdapter();
68
        $this->sigSerializer = new TransactionSignatureSerializer(EcSerializer::getSerializer(DerSignatureSerializerInterface::class, true, $this->ecAdapter));
69
        $this->pubKeySerializer = EcSerializer::getSerializer(PublicKeySerializerInterface::class, true, $this->ecAdapter);
70
    }
71 2
72
    /**
73 2
     * @param bool $setting
74
     * @return $this
75
     */
76
    public function redeemBitcoinCash($setting)
77 2
    {
78
        if (!is_bool($setting)) {
79 2
            throw new \InvalidArgumentException("Boolean value expected");
80
        }
81
82
        $this->redeemBitcoinCash = $setting;
83
        return $this;
84
    }
85
86 2
    /**
87
     * @param bool $setting
88 2
     * @return $this
89
     */
90
    public function padUnsignedMultisigs($setting)
91
    {
92 2
        if (!is_bool($setting)) {
93
            throw new \InvalidArgumentException("Boolean value expected");
94 2
        }
95
96
        $this->padUnsignedMultisigs = $setting;
97
        return $this;
98
    }
99
100
    /**
101
     * @param bool $setting
102
     * @return $this
103
     */
104
    public function tolerateInvalidPublicKey($setting)
105 50
    {
106
        if (!is_bool($setting)) {
107 50
            throw new \InvalidArgumentException("Boolean value expected");
108
        }
109
110
        $this->tolerateInvalidPublicKey = $setting;
111 50
        return $this;
112
    }
113
114
    /**
115
     * @param int $nIn
116
     * @param PrivateKeyInterface $key
117
     * @param TransactionOutputInterface $txOut
118
     * @param SignData $signData
119
     * @param int $sigHashType
120 66
     * @return $this
121
     */
122 66
    public function sign($nIn, PrivateKeyInterface $key, TransactionOutputInterface $txOut, SignData $signData = null, $sigHashType = SigHash::ALL)
123 16
    {
124
        if (!$this->input($nIn, $txOut, $signData)->sign($key, $sigHashType)) {
125
            throw new \RuntimeException('Unsignable script');
126 66
        }
127 66
128 66
        return $this;
129 66
    }
130 66
131
    /**
132 62
     * @param int $nIn
133
     * @param TransactionOutputInterface $txOut
134
     * @param SignData|null $signData
135 62
     * @return InputSignerInterface
136
     */
137
    public function input($nIn, TransactionOutputInterface $txOut, SignData $signData = null)
138
    {
139
        if (null === $signData) {
140
            $signData = new SignData();
141 52
        }
142
143 52
        if (!isset($this->signatureCreator[$nIn])) {
144 52
            $input = (new InputSigner($this->ecAdapter, $this->tx, $nIn, $txOut, $signData, $this->sigSerializer, $this->pubKeySerializer))
145 52
                ->padUnsignedMultisigs($this->padUnsignedMultisigs)
146 52
                ->tolerateInvalidPublicKey($this->tolerateInvalidPublicKey)
147 52
                ->redeemBitcoinCash($this->redeemBitcoinCash)
148 52
                ->extract();
149
150
            $this->signatureCreator[$nIn] = $input;
151 52
        }
152 52
153
        return $this->signatureCreator[$nIn];
154
    }
155 52
156 52
    /**
157
     * @return TransactionInterface
158
     */
159
    public function get()
160
    {
161
        $mutable = TransactionFactory::mutate($this->tx);
162
        $witnesses = [];
163
        foreach ($mutable->inputsMutator() as $idx => $input) {
164
            $sig = $this->signatureCreator[$idx]->serializeSignatures();
165
            $input->script($sig->getScriptSig());
166
            $witnesses[$idx] = $sig->getScriptWitness();
167
        }
168
169
        if (count($witnesses) > 0) {
170
            $mutable->witness($witnesses);
171
        }
172
173
        $new = $mutable->done();
174
        return $new;
175
    }
176
}
177