1 | <?php |
||
18 | class TxSignerContext |
||
19 | { |
||
20 | /** |
||
21 | * @var \BitWasp\Bitcoin\Script\ScriptInfo\ScriptInfoInterface |
||
22 | */ |
||
23 | private $scriptInfo; |
||
24 | |||
25 | /** |
||
26 | * @var null|ScriptInterface |
||
27 | */ |
||
28 | private $redeemScript; |
||
29 | |||
30 | /** |
||
31 | * @var ScriptInterface |
||
32 | */ |
||
33 | private $prevOutScript; |
||
34 | |||
35 | /** |
||
36 | * @var string |
||
37 | */ |
||
38 | private $prevOutType; |
||
39 | |||
40 | /** |
||
41 | * @var string |
||
42 | */ |
||
43 | private $scriptType; |
||
44 | |||
45 | /** |
||
46 | * @var array |
||
47 | */ |
||
48 | private $signatures = []; |
||
49 | |||
50 | /** |
||
51 | * @var PublicKeyInterface[] |
||
52 | */ |
||
53 | private $publicKeys = []; |
||
54 | |||
55 | /** |
||
56 | * @var EcAdapterInterface |
||
57 | */ |
||
58 | private $ecAdapter; |
||
59 | |||
60 | /** |
||
61 | * @param EcAdapterInterface $ecAdapter |
||
62 | * @param ScriptInterface $outputScript |
||
63 | * @param ScriptInterface $redeemScript |
||
64 | */ |
||
65 | 129 | public function __construct( |
|
101 | |||
102 | /** |
||
103 | * @return ScriptInterface |
||
104 | * @throws \RuntimeException |
||
105 | */ |
||
106 | 36 | public function getRedeemScript() |
|
114 | |||
115 | /** |
||
116 | * |
||
117 | * @return string |
||
118 | */ |
||
119 | 105 | public function getPrevOutType() |
|
123 | |||
124 | /** |
||
125 | * @return string |
||
126 | */ |
||
127 | 87 | public function getScriptType() |
|
131 | |||
132 | /** |
||
133 | * @param $publicKeys |
||
134 | * @return $this |
||
135 | */ |
||
136 | 39 | public function setPublicKeys($publicKeys) |
|
142 | |||
143 | /** |
||
144 | * @return array|\BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface[] |
||
145 | */ |
||
146 | 87 | public function getPublicKeys() |
|
150 | |||
151 | /** |
||
152 | * @return array |
||
153 | */ |
||
154 | 69 | public function getSignatures() |
|
158 | |||
159 | /** |
||
160 | * @param integer $idx |
||
161 | * @param TransactionSignatureInterface $signature |
||
162 | * @return $this |
||
163 | */ |
||
164 | 81 | public function setSignature($idx, TransactionSignatureInterface $signature = null) |
|
169 | |||
170 | /** |
||
171 | * @param TransactionInterface $tx |
||
172 | * @param $inputToExtract |
||
173 | * @return $this |
||
174 | */ |
||
175 | 81 | public function extractSigs(TransactionInterface $tx, $inputToExtract) |
|
176 | { |
||
177 | 81 | $inputs = $tx->getInputs(); |
|
178 | 81 | $parsed = $inputs[$inputToExtract] |
|
179 | 81 | ->getScript() |
|
180 | 81 | ->getScriptParser() |
|
181 | 81 | ->parse(); |
|
182 | |||
183 | 81 | $size = count($parsed); |
|
184 | |||
185 | 81 | switch ($this->getScriptType()) { |
|
186 | 81 | case OutputClassifier::PAYTOPUBKEYHASH: |
|
187 | // Supply signature and public key in scriptSig |
||
188 | 39 | if ($size === 2) { |
|
189 | 81 | $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getHex(), $this->ecAdapter)]; |
|
190 | $this->publicKeys = [PublicKeyFactory::fromHex($parsed[1]->getHex(), $this->ecAdapter)]; |
||
191 | } |
||
192 | |||
193 | 39 | break; |
|
194 | 42 | case OutputClassifier::PAYTOPUBKEY: |
|
195 | // Only has a signature in the scriptSig |
||
196 | 18 | if ($size === 1) { |
|
197 | $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getHex(), $this->ecAdapter)]; |
||
198 | } |
||
199 | |||
200 | 18 | break; |
|
201 | 24 | case OutputClassifier::MULTISIG: |
|
202 | 24 | $redeemScript = $this->getRedeemScript(); |
|
203 | 24 | $keys = $this->scriptInfo->getKeys(); |
|
204 | 24 | foreach ($keys as $idx => $key) { |
|
205 | 24 | $this->setSignature($idx, null); |
|
206 | 24 | } |
|
207 | |||
208 | 24 | if ($size > 2 && $size <= $this->scriptInfo->getKeyCount() + 2) { |
|
209 | 6 | $sigs = []; |
|
210 | 6 | foreach ($keys as $key) { |
|
211 | 6 | $sigs[$key->getPubKeyHash()->getHex()] = []; |
|
212 | 6 | } |
|
213 | |||
214 | // Extract Signatures (as buffers), then compile arrays of [pubkeyHash => signature] |
||
215 | 6 | $sigHash = new Hasher($tx); |
|
216 | |||
217 | 6 | foreach (array_slice($parsed, 1, -1) as $item) { |
|
218 | 6 | if ($item instanceof Buffer) { |
|
219 | 6 | $txSig = TransactionSignatureFactory::fromHex($item, $this->ecAdapter); |
|
220 | 6 | $linked = $this->ecAdapter->associateSigs( |
|
221 | 6 | [$txSig->getSignature()], |
|
222 | 6 | $sigHash->calculate( |
|
223 | 6 | $redeemScript, |
|
224 | 6 | $inputToExtract, |
|
225 | 6 | $txSig->getHashType() |
|
226 | 6 | ), |
|
227 | $keys |
||
228 | 6 | ); |
|
229 | |||
230 | 6 | if (count($linked)) { |
|
231 | 6 | $key = array_keys($linked)[0]; |
|
232 | 6 | $sigs[$key] = array_merge($sigs[$key], [$txSig]); |
|
233 | 6 | } |
|
234 | 6 | } |
|
235 | 6 | } |
|
236 | |||
237 | // We have all the signatures from the tx now. array_shift the sigs for a public key, as it's encountered. |
||
238 | 6 | foreach ($keys as $idx => $key) { |
|
239 | 6 | $hash = $key->getPubKeyHash()->getHex(); |
|
240 | 6 | $this->setSignature($idx, isset($sigs[$hash]) |
|
241 | 6 | ? array_shift($sigs[$hash]) |
|
242 | 6 | : null); |
|
243 | 6 | } |
|
244 | 6 | } |
|
245 | |||
246 | 24 | break; |
|
247 | 81 | } |
|
248 | |||
249 | 81 | return $this; |
|
250 | } |
||
251 | |||
252 | /** |
||
253 | * @return \BitWasp\Bitcoin\Script\Script |
||
254 | */ |
||
255 | 63 | public function regenerateScript() |
|
260 | |||
261 | /** |
||
262 | * @return int |
||
263 | */ |
||
264 | 48 | public function getRequiredSigCount() |
|
268 | |||
269 | /** |
||
270 | * @return int |
||
271 | */ |
||
272 | 54 | public function getSigCount() |
|
276 | |||
277 | /** |
||
278 | * @return bool |
||
279 | */ |
||
280 | 30 | public function isFullySigned() |
|
285 | } |
||
286 |