Completed
Pull Request — master (#239)
by thomas
49:01 queued 45:29
created

V1Hasher   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 10
c 3
b 0
f 1
lcom 1
cbo 12
dl 0
loc 88
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
D calculate() 0 40 9
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\SignatureHash;
4
5
use BitWasp\Bitcoin\Crypto\Hash;
6
use BitWasp\Bitcoin\Script\ScriptFactory;
7
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
8
use BitWasp\Bitcoin\Transaction\TransactionInterface;
9
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
10
use BitWasp\Buffertools\Buffer;
11
use BitWasp\Buffertools\BufferInterface;
12
use BitWasp\Bitcoin\Script\ScriptInterface;
13
14
class V1Hasher
15
{
16
    /**
17
     * @var TransactionInterface
18
     */
19
    private $transaction;
20
21
    /**
22
     * @var int
23
     */
24
    private $nInputs;
25
26
    /**
27
     * @var int
28
     */
29
    private $nOutputs;
30
31
    /**
32
     * @var int|string
33
     */
34
    private $amount;
35
36
    /**
37
     * V1Hasher constructor.
38
     * @param TransactionInterface $transaction
39
     * @param int|string $amount
40
     */
41
    public function __construct(TransactionInterface $transaction, $amount)
42
    {
43
        $this->transaction = $transaction;
44
        $this->nInputs = count($this->transaction->getInputs());
45
        $this->nOutputs = count($this->transaction->getOutputs());
46
        $this->amount = $amount;
47
    }
48
49
    /**
50
     * Calculate the hash of the current transaction, when you are looking to
51
     * spend $txOut, and are signing $inputToSign. The SigHashType defaults to
52
     * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY
53
     * can be used.
54
     *
55
     * @param ScriptInterface $txOutScript
56
     * @param int $inputToSign
57
     * @param int $sighashType
58
     * @return BufferInterface
59
     * @throws \Exception
60
     */
61
    public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHash::ALL)
62
    {
63
        $sighashType = (int) $sighashType;
64
        $hashSequence = $hashOutputs = $hashPrevOuts = new Buffer('', 32);
65
66
        if (!($sighashType & SigHash::ANYONECANPAY)) {
67
            $hashPrevOuts = Hash::sha256d(new Buffer(implode("", array_map(function (TransactionInputInterface $input) {
68
                return $input->getOutPoint()->getBinary();
69
            }, $this->transaction->getInputs()->all()))));
70
        }
71
72
        if (!($sighashType & SigHash::ANYONECANPAY) && ($sighashType & 0x1f) != SigHash::SINGLE && ($sighashType & 0x1f) != SigHash::NONE) {
73
            $hashSequence = Hash::sha256d(new Buffer(implode("", array_map(function (TransactionInputInterface $input) {
74
                return Buffer::int($input->getSequence())->flip()->getBinary();
75
            }, $this->transaction->getInputs()->all()))));
76
        }
77
78
        if (($sighashType & 0x1f) !== SigHash::SINGLE && ($sighashType & 0x1f) != SigHash::NONE) {
79
            $hashOutputs = Hash::sha256d(new Buffer(implode("", array_map(function (TransactionOutputInterface $input) {
80
                return $input->getBinary();
81
            }, $this->transaction->getOutputs()->all()))));
82
        } elseif (($sighashType & 0x1f) == SigHash::SINGLE && $inputToSign < count($this->transaction->getOutputs())) {
83
            $hashOutputs = Hash::sha256($this->transaction->getOutput($inputToSign)->getBuffer());
84
        }
85
86
        $input = $this->transaction->getInput($inputToSign);
87
88
        return Hash::sha256d(new Buffer(
89
            pack("V", $this->transaction->getVersion()) .
90
            $hashPrevOuts->getBinary() .
91
            $hashSequence->getBinary() .
92
            $input->getOutPoint()->getBinary() .
93
            ScriptFactory::create()->push($txOutScript->getBuffer())->getScript()->getBinary() .
94
            Buffer::int($this->amount, 8)->flip()->getBinary() .
95
            pack("V", $input->getSequence()) .
96
            $hashOutputs->getBinary() .
97
            pack("V", $this->transaction->getLockTime()) .
98
            pack("V", $sighashType)
99
        ));
100
    }
101
}
102