Completed
Push — master ( d885db...3f1305 )
by thomas
30:43
created

Hasher::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
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\Script\Script;
8
use BitWasp\Bitcoin\Script\ScriptInterface;
9
use BitWasp\Bitcoin\Serializer\Transaction\TransactionSerializer;
10
use BitWasp\Bitcoin\Serializer\Transaction\TransactionSerializerInterface;
11
use BitWasp\Bitcoin\Transaction\Mutator\TxMutator;
12
use BitWasp\Bitcoin\Transaction\TransactionInterface;
13
use BitWasp\Buffertools\Buffer;
14
use BitWasp\Buffertools\BufferInterface;
15
16
class Hasher extends SigHash
17
{
18
    /**
19
     * @var TransactionSerializer
20
     */
21
    private $txSerializer;
22
23
    /**
24
     * Hasher constructor.
25
     * @param TransactionInterface $transaction
26
     * @param TransactionSerializerInterface|null $txSerializer
27
     */
28 86
    public function __construct(TransactionInterface $transaction, TransactionSerializerInterface $txSerializer = null)
29
    {
30 86
        $this->txSerializer = $txSerializer ?: new TransactionSerializer();
0 ignored issues
show
Documentation Bug introduced by
$txSerializer ?: new \Bi...TransactionSerializer() is of type object<BitWasp\Bitcoin\S...ionSerializerInterface>, but the property $txSerializer was declared to be of type object<BitWasp\Bitcoin\S...\TransactionSerializer>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
31 86
        parent::__construct($transaction);
32 86
    }
33
34
    /**
35
     * Calculate the hash of the current transaction, when you are looking to
36
     * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
37
     * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY
38
     * can be used.
39
     *
40
     * @param ScriptInterface $txOutScript
41
     * @param int $inputToSign
42
     * @param int $sighashType
43
     * @return BufferInterface
44
     * @throws \Exception
45
     */
46 86
    public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHash::ALL)
47
    {
48 86
        $math = Bitcoin::getMath();
49 86
        $tx = new TxMutator($this->tx);
50 86
        $inputs = $tx->inputsMutator();
51 86
        $outputs = $tx->outputsMutator();
52
53
        // Default SIGHASH_ALL procedure: null all input scripts
54 86
        foreach ($inputs as $input) {
55 86
            $input->script(new Script);
56
        }
57
58 86
        $inputs[$inputToSign]->script($txOutScript);
59
60 86
        if (($sighashType & 31) === SigHash::NONE) {
61
            // Set outputs to empty vector, and set sequence number of inputs to 0.
62 4
            $outputs->null();
63
64
            // Let the others update at will. Set sequence of inputs we're not signing to 0.
65 4
            foreach ($inputs as $i => $input) {
66 4
                if ($i !== $inputToSign) {
67 4
                    $input->sequence(0);
68
                }
69
            }
70 82
        } elseif (($sighashType & 31) === SigHash::SINGLE) {
71
            // Resize output array to $inputToSign + 1, set remaining scripts to null,
72
            // and set sequence's to zero.
73 8
            $nOutput = $inputToSign;
74 8
            if ($nOutput >= count($this->tx->getOutputs())) {
75 2
                return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000', 32, $math);
76
            }
77
78
            // Resize, set to null
79 8
            $outputs->slice(0, $nOutput + 1);
80 8
            for ($i = 0; $i < $nOutput; $i++) {
81 6
                $outputs[$i]->null();
82
            }
83
84
            // Let the others update at will. Set sequence of inputs we're not signing to 0
85 8
            foreach ($inputs as $i => $input) {
86 8
                if ($i !== $inputToSign) {
87 8
                    $input->sequence(0);
88
                }
89
            }
90
        }
91
92
        // This can happen regardless of whether it's ALL, NONE, or SINGLE
93 86
        if (($sighashType & SigHash::ANYONECANPAY) > 0) {
94 7
            $input = $inputs[$inputToSign]->done();
95 7
            $inputs->null()->add($input);
96
        }
97
98 86
        return Hash::sha256d(new Buffer(
99 86
            $this->txSerializer->serialize($tx->done(), TransactionSerializer::NO_WITNESS)->getBinary() .
100 86
            pack('V', $sighashType)
101
        ));
102
    }
103
}
104