|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace BitWasp\Bitcoin\Transaction\SignatureHash; |
|
4
|
|
|
|
|
5
|
|
|
use BitWasp\Bitcoin\Bitcoin; |
|
6
|
|
|
use BitWasp\Bitcoin\Crypto\Hash; |
|
7
|
|
|
use BitWasp\Bitcoin\Transaction\Mutator\TxMutator; |
|
8
|
|
|
use BitWasp\Buffertools\Buffer; |
|
9
|
|
|
use BitWasp\Buffertools\BufferInterface; |
|
10
|
|
|
use BitWasp\Buffertools\Buffertools; |
|
11
|
|
|
use BitWasp\Bitcoin\Script\Script; |
|
12
|
|
|
use BitWasp\Bitcoin\Script\ScriptInterface; |
|
13
|
|
|
|
|
14
|
|
|
class Hasher extends SigHash |
|
15
|
|
|
{ |
|
16
|
|
|
/** |
|
17
|
|
|
* Calculate the hash of the current transaction, when you are looking to |
|
18
|
|
|
* spend $txOut, and are signing $inputToSign. The SigHashType defaults to |
|
19
|
|
|
* SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY |
|
20
|
|
|
* can be used. |
|
21
|
|
|
* |
|
22
|
|
|
* @param ScriptInterface $txOutScript |
|
23
|
|
|
* @param int $inputToSign |
|
24
|
|
|
* @param int $sighashType |
|
25
|
|
|
* @return BufferInterface |
|
26
|
|
|
* @throws \Exception |
|
27
|
|
|
*/ |
|
28
|
254 |
|
public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHashInterface::ALL) |
|
29
|
|
|
{ |
|
30
|
254 |
|
$math = Bitcoin::getMath(); |
|
31
|
254 |
|
$tx = new TxMutator($this->tx); |
|
32
|
254 |
|
$inputs = $tx->inputsMutator(); |
|
33
|
254 |
|
$outputs = $tx->outputsMutator(); |
|
34
|
|
|
|
|
35
|
|
|
// Default SIGHASH_ALL procedure: null all input scripts |
|
36
|
254 |
|
foreach ($inputs as $input) { |
|
37
|
254 |
|
$input->script(new Script); |
|
38
|
114 |
|
} |
|
39
|
|
|
|
|
40
|
254 |
|
$inputs[$inputToSign]->script($txOutScript); |
|
41
|
|
|
|
|
42
|
248 |
|
if (($sighashType & 31) === SigHashInterface::NONE) { |
|
43
|
|
|
// Set outputs to empty vector, and set sequence number of inputs to 0. |
|
44
|
6 |
|
$outputs->null(); |
|
45
|
|
|
|
|
46
|
|
|
// Let the others update at will. Set sequence of inputs we're not signing to 0. |
|
47
|
6 |
|
foreach ($inputs as $i => $input) { |
|
48
|
6 |
|
if ($i !== $inputToSign) { |
|
49
|
6 |
|
$input->sequence(0); |
|
50
|
2 |
|
} |
|
51
|
2 |
|
} |
|
52
|
248 |
|
} elseif (($sighashType & 31) === SigHashInterface::SINGLE) { |
|
53
|
|
|
// Resize output array to $inputToSign + 1, set remaining scripts to null, |
|
54
|
|
|
// and set sequence's to zero. |
|
55
|
12 |
|
$nOutput = $inputToSign; |
|
56
|
12 |
|
if ($nOutput >= count($this->tx->getOutputs())) { |
|
57
|
6 |
|
return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000', 32, $math); |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
// Resize, set to null |
|
61
|
12 |
|
$outputs->slice(0, $nOutput + 1); |
|
62
|
12 |
|
for ($i = 0; $i < $nOutput; $i++) { |
|
63
|
6 |
|
$outputs[$i]->null(); |
|
64
|
2 |
|
} |
|
65
|
|
|
|
|
66
|
|
|
// Let the others update at will. Set sequence of inputs we're not signing to 0 |
|
67
|
12 |
|
foreach ($inputs as $i => $input) { |
|
68
|
12 |
|
if ($i !== $inputToSign) { |
|
69
|
10 |
|
$input->sequence(0); |
|
70
|
2 |
|
} |
|
71
|
4 |
|
} |
|
72
|
4 |
|
} |
|
73
|
|
|
|
|
74
|
|
|
// This can happen regardless of whether it's ALL, NONE, or SINGLE |
|
75
|
248 |
|
if (($sighashType & SigHashInterface::ANYONECANPAY) > 0) { |
|
76
|
10 |
|
$input = $inputs[$inputToSign]->done(); |
|
77
|
10 |
|
$inputs->null()->add($input); |
|
78
|
4 |
|
} |
|
79
|
|
|
|
|
80
|
248 |
|
return Hash::sha256d( |
|
81
|
248 |
|
Buffertools::concat( |
|
82
|
|
|
$tx |
|
83
|
248 |
|
->done() |
|
84
|
248 |
|
->getBuffer(), |
|
85
|
248 |
|
Buffertools::flipBytes(Buffer::int($sighashType, 4, $math)) |
|
|
|
|
|
|
86
|
112 |
|
) |
|
87
|
112 |
|
); |
|
88
|
|
|
} |
|
89
|
|
|
} |
|
90
|
|
|
|
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.