Completed
Push — master ( b4333d...f02c0d )
by thomas
14s
created

Bip69::sortInputsAndWitness()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 1 Features 1
Metric Value
cc 3
eloc 8
nc 3
nop 2
dl 0
loc 15
ccs 0
cts 9
cp 0
crap 12
rs 9.4285
c 2
b 1
f 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Transaction\Bip69;
4
5
use BitWasp\Bitcoin\Script\ScriptWitnessInterface;
6
use BitWasp\Bitcoin\Transaction\Mutator\TxMutator;
7
use BitWasp\Bitcoin\Transaction\TransactionInputInterface;
8
use BitWasp\Bitcoin\Transaction\TransactionInterface;
9
use BitWasp\Bitcoin\Transaction\TransactionOutputInterface;
10
11
class Bip69
12
{
13
    /**
14
     * @param TransactionInputInterface[] $vTxin
15
     * @return array
16
     */
17 6
    public function sortInputs(array $vTxin)
18
    {
19 6
        usort($vTxin, [$this, 'compareInputs']);
20 6
        return $vTxin;
21
    }
22
23
    /**
24
     * @param TransactionInputInterface $vin1
25
     * @param TransactionInputInterface $vin2
26
     * @return bool
27
     */
28 6
    public function compareInputs(TransactionInputInterface $vin1, TransactionInputInterface $vin2)
29
    {
30 6
        $outpoint1 = $vin1->getOutPoint();
31 6
        $outpoint2 = $vin2->getOutPoint();
32
33 6
        $cmpTxId = strcmp($outpoint1->getTxId()->getBinary(), $outpoint2->getTxId()->getBinary());
34
35 6
        return ($cmpTxId !== 0) ? $cmpTxId : $outpoint1->getVout() - $outpoint2->getVout();
36
    }
37
38
    /**
39
     * @param TransactionOutputInterface[] $vTxout
40
     * @return TransactionOutputInterface[]
41
     */
42 6
    public function sortOutputs($vTxout)
43
    {
44 6
        usort($vTxout, [$this, 'compareOutputs']);
45 6
        return $vTxout;
46
    }
47
48
    /**
49
     * @param TransactionOutputInterface $vout1
50
     * @param TransactionOutputInterface $vout2
51
     * @return bool
52
     */
53 6
    public function compareOutputs(TransactionOutputInterface $vout1, TransactionOutputInterface $vout2)
54
    {
55 6
        $value = $vout1->getValue() - $vout2->getValue();
56
57 6
        return ($value !== 0) ? $value : strcmp($vout1->getScript()->getBinary(), $vout2->getScript()->getBinary());
58
    }
59
60
    /**
61
     * @param TransactionInterface $tx
62
     * @return bool
63
     */
64 6
    public function check(TransactionInterface $tx)
65
    {
66 6
        $inputs = $tx->getInputs();
67 6
        $outputs = $tx->getOutputs();
68
69 6
        return $this->sortInputs($inputs) === $inputs && $this->sortOutputs($outputs) === $outputs;
70
    }
71
72
    /**
73
     * @param TransactionInputInterface[] $inputs
74
     * @param ScriptWitnessInterface[] $witnesses
75
     * @return array
76
     * @throws \Exception
77
     */
78
    public function sortInputsAndWitness(array $inputs, array $witnesses)
79
    {
80
        if (count($inputs) !== count($witnesses)) {
81
            throw new \Exception('Number of inputs must match witnesses');
82
        }
83
84
        uasort($inputs, [$this, 'compareInputs']);
85
86
        $vWitness = [];
87
        foreach ($inputs as $key => $input) {
88
            $vWitness[] = $witnesses[$key];
89
        }
90
91
        return [$inputs, $vWitness];
92
    }
93
94
    /**
95
     * @param TransactionInterface $tx
96
     * @return TransactionInterface
97
     */
98 3
    public function mutate(TransactionInterface $tx)
99
    {
100 3
        if (count($tx->getWitnesses()) > 0) {
101
            list ($vTxin, $vWit) = $this->sortInputsAndWitness($tx->getInputs(), $tx->getWitnesses());
102
        } else {
103 3
            $vTxin = $this->sortInputs($tx->getInputs());
104 3
            $vWit = [];
105
        }
106
107 3
        return (new TxMutator($tx))
108 3
            ->inputs($vTxin)
109 3
            ->outputs($this->sortOutputs($tx->getOutputs()))
110 3
            ->witness($vWit)
111 3
            ->done();
112
    }
113
}
114