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

V1Hasher::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 4
nop 4
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Transaction\SignatureHash;
6
7
use BitWasp\Bitcoin\Crypto\Hash;
8
use BitWasp\Bitcoin\Script\ScriptInterface;
9
use BitWasp\Bitcoin\Serializer\Transaction\OutPointSerializer;
10
use BitWasp\Bitcoin\Serializer\Transaction\OutPointSerializerInterface;
11
use BitWasp\Bitcoin\Serializer\Transaction\TransactionOutputSerializer;
12
use BitWasp\Bitcoin\Transaction\TransactionInterface;
13
use BitWasp\Buffertools\Buffer;
14
use BitWasp\Buffertools\BufferInterface;
15
use BitWasp\Buffertools\Buffertools;
16
17
class V1Hasher extends SigHash
18
{
19
    /**
20
     * @var TransactionInterface
21
     */
22
    protected $transaction;
23
24
    /**
25
     * @var int
26
     */
27
    protected $amount;
28
29
    /**
30
     * @var TransactionOutputSerializer
31
     */
32
    protected $outputSerializer;
33
34
    /**
35
     * @var TransactionOutputSerializer
36
     */
37
    protected $outpointSerializer;
38
39
    /**
40
     * V1Hasher constructor.
41
     * @param TransactionInterface $transaction
42
     * @param int $amount
43
     * @param OutPointSerializerInterface $outpointSerializer
44
     * @param TransactionOutputSerializer|null $outputSerializer
45
     */
46 48
    public function __construct(
47
        TransactionInterface $transaction,
48
        int $amount,
49
        OutPointSerializerInterface $outpointSerializer = null,
50
        TransactionOutputSerializer $outputSerializer = null
51
    ) {
52 48
        $this->amount = $amount;
53 48
        $this->outputSerializer = $outputSerializer ?: new TransactionOutputSerializer();
54 48
        $this->outpointSerializer = $outpointSerializer ?: new OutPointSerializer();
0 ignored issues
show
Documentation Bug introduced by
It seems like $outpointSerializer ?: n...on\OutPointSerializer() of type object<BitWasp\Bitcoin\S...intSerializerInterface> is incompatible with the declared type object<BitWasp\Bitcoin\S...actionOutputSerializer> of property $outpointSerializer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
55 48
        parent::__construct($transaction);
56 48
    }
57
58
    /**
59
     * @param int $sighashType
60
     * @return BufferInterface
61
     */
62 48
    public function hashPrevOuts(int $sighashType): BufferInterface
63
    {
64 48
        if (!($sighashType & SigHash::ANYONECANPAY)) {
65 48
            $binary = '';
66 48
            foreach ($this->tx->getInputs() as $input) {
67 48
                $binary .= $this->outpointSerializer->serialize($input->getOutPoint())->getBinary();
0 ignored issues
show
Documentation introduced by
$input->getOutPoint() is of type object<BitWasp\Bitcoin\T...tion\OutPointInterface>, but the function expects a object<BitWasp\Bitcoin\T...sactionOutputInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
68
            }
69 48
            return Hash::sha256d(new Buffer($binary));
70
        }
71
72
        return new Buffer('', 32);
73
    }
74
75
    /**
76
     * @param int $sighashType
77
     * @return BufferInterface
78
     */
79 48
    public function hashSequences(int $sighashType): BufferInterface
80
    {
81 48
        if (!($sighashType & SigHash::ANYONECANPAY) && ($sighashType & 0x1f) !== SigHash::SINGLE && ($sighashType & 0x1f) !== SigHash::NONE) {
82 48
            $binary = '';
83 48
            foreach ($this->tx->getInputs() as $input) {
84 48
                $binary .= pack('V', $input->getSequence());
85
            }
86
87 48
            return Hash::sha256d(new Buffer($binary));
88
        }
89
90
        return new Buffer('', 32);
91
    }
92
93
    /**
94
     * @param int $sighashType
95
     * @param int $inputToSign
96
     * @return BufferInterface
97
     */
98 48
    public function hashOutputs(int $sighashType, int $inputToSign): BufferInterface
99
    {
100 48
        if (($sighashType & 0x1f) !== SigHash::SINGLE && ($sighashType & 0x1f) !== SigHash::NONE) {
101 48
            $binary = '';
102 48
            foreach ($this->tx->getOutputs() as $output) {
103 48
                $binary .= $this->outputSerializer->serialize($output)->getBinary();
104
            }
105 48
            return Hash::sha256d(new Buffer($binary));
106
        } elseif (($sighashType & 0x1f) === SigHash::SINGLE && $inputToSign < count($this->tx->getOutputs())) {
107
            return Hash::sha256d($this->outputSerializer->serialize($this->tx->getOutput($inputToSign)));
108
        }
109
110
        return new Buffer('', 32);
111
    }
112
113
    /**
114
     * Calculate the hash of the current transaction, when you are looking to
115
     * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
116
     * SIGHASH_ALL
117
     *
118
     * @param ScriptInterface $txOutScript
119
     * @param int $inputToSign
120
     * @param int $sighashType
121
     * @return BufferInterface
122
     * @throws \Exception
123
     */
124 48
    public function calculate(
125
        ScriptInterface $txOutScript,
126
        int $inputToSign,
127
        int $sighashType = SigHash::ALL
128
    ): BufferInterface {
129
130 48
        $sighashType = (int) $sighashType;
131 48
        $hashPrevOuts = $this->hashPrevOuts($sighashType);
132 48
        $hashSequence = $this->hashSequences($sighashType);
133 48
        $hashOutputs = $this->hashOutputs($sighashType, $inputToSign);
134 48
        $input = $this->tx->getInput($inputToSign);
135
136 48
        $scriptBuf = $txOutScript->getBuffer();
137 48
        $preimage = new Buffer(
138 48
            pack("V", $this->tx->getVersion()) .
139 48
            $hashPrevOuts->getBinary() .
140 48
            $hashSequence->getBinary() .
141 48
            $this->outpointSerializer->serialize($input->getOutPoint())->getBinary() .
0 ignored issues
show
Documentation introduced by
$input->getOutPoint() is of type object<BitWasp\Bitcoin\T...tion\OutPointInterface>, but the function expects a object<BitWasp\Bitcoin\T...sactionOutputInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
142 48
            Buffertools::numToVarInt($scriptBuf->getSize())->getBinary() . $scriptBuf->getBinary() .
143 48
            pack("P", $this->amount) .
144 48
            pack("V", $input->getSequence()) .
145 48
            $hashOutputs->getBinary() .
146 48
            pack("V", $this->tx->getLockTime()) .
147 48
            pack("V", $sighashType)
148
        );
149
150 48
        return Hash::sha256d($preimage);
151
    }
152
}
153