Completed
Push — master ( 015b1e...e1c455 )
by thomas
67:33 queued 36:12
created

Bip69::compareOutputs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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