Completed
Pull Request — master (#99)
by thomas
42:14 queued 39:21
created

OutputsNormalizer::readArrayFormat()   B

Complexity

Conditions 9
Paths 4

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 9

Importance

Changes 0
Metric Value
cc 9
eloc 13
nc 4
nop 2
dl 0
loc 17
ccs 10
cts 10
cp 1
crap 9
rs 7.756
c 0
b 0
f 0
1
<?php
2
3
namespace Blocktrail\SDK;
4
5
use BitWasp\Bitcoin\Bitcoin;
6
use BitWasp\Bitcoin\Network\Network;
7
use BitWasp\Bitcoin\Network\NetworkInterface;
8
use BitWasp\Bitcoin\Script\Opcodes;
9
use BitWasp\Bitcoin\Script\ScriptFactory;
10
use BitWasp\Buffertools\Buffer;
11
use Blocktrail\SDK\Address\AddressReaderBase;
12
use Blocktrail\SDK\Exceptions\BlocktrailSDKException;
13
14
class OutputsNormalizer
15
{
16
    /**
17
     * @var AddressReaderBase
18
     */
19
    private $reader;
20
21
    /**
22
     * OutputsNormalizer constructor.
23
     * @param AddressReaderBase $reader
24
     */
25 34
    public function __construct(AddressReaderBase $reader) {
26 34
        $this->reader = $reader;
27 34
    }
28
29
    /**
30
     * @param array $output
31
     * @return array
32
     * @throws BlocktrailSDKException
33
     */
34 22
    protected function readArrayFormat(array $output, Network $network) {
35 22
        if (array_key_exists("scriptPubKey", $output) && array_key_exists("value", $output)) {
36
            return [
37 15
                "scriptPubKey" => $output['scriptPubKey'],
38 15
                "value" => $output['value'],
39
            ];
40 7
        } else if (array_key_exists("address", $output) && array_key_exists("value", $output)) {
41 5
            return $this->parseAddressOutput($output['address'], $output['value'], $network);
42
        } else {
43 2
            $keys = array_keys($output);
44 2
            if (count($keys) === 2 && count($output) === 2 && $keys[0] === 0 && $keys[1] === 1) {
45 1
                return $this->parseAddressOutput($output[0], $output[1], $network);
46
            } else {
47 1
                throw new BlocktrailSDKException("Invalid transaction output for numerically indexed list");
48
            }
49
        }
50
    }
51
52
    /**
53
     * @param $address
54
     * @param $value
55
     * @return array
56
     */
57 25
    private function parseAddressOutput($address, $value, $network) {
58 25
        if ($address === "opreturn") {
59 1
            $data = new Buffer($value);
60 1
            $scriptPubKey = ScriptFactory::sequence([Opcodes::OP_RETURN, $data]);
61
            return [
62 1
                "value" => 0,
63 1
                "scriptPubKey" => $scriptPubKey,
64
            ];
65
        }
66
67 24
        $object = $this->reader->fromString($address, $network);
68
        return [
69 24
            "value" => $value,
70 24
            "scriptPubKey" => $object->getScriptPubKey(),
71
        ];
72
    }
73
74
    /**
75
     * @param array $outputs
76
     * @param NetworkInterface|null $network
77
     * @return array
78
     * @throws BlocktrailSDKException
79
     */
80 34
    public function normalize(array $outputs, NetworkInterface $network = null) {
81 34
        $network = $network ?: Bitcoin::getNetwork();
82 34
        if (empty($outputs)) {
83 1
            return [];
84
        }
85
86 33
        $keys = array_keys($outputs);
87 33
        $newOutputs = [];
88 33
        if (is_int($keys[0])) {
89 23
            foreach ($outputs as $i => $output) {
90 23
                if (!is_int($i)) {
91 1
                    throw new BlocktrailSDKException("Encountered invalid index while traversing numerically indexed list");
92
                }
93 23
                if (!is_array($output)) {
94 1
                    throw new BlocktrailSDKException("Encountered invalid output while traversing numerically indexed list");
95
                }
96 22
                $newOutputs[] = $this->readArrayFormat($output, $network);
0 ignored issues
show
Compatibility introduced by
$network of type object<BitWasp\Bitcoin\Network\NetworkInterface> is not a sub-type of object<BitWasp\Bitcoin\Network\Network>. It seems like you assume a concrete implementation of the interface BitWasp\Bitcoin\Network\NetworkInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
97
            }
98 19
        } else if (is_string($keys[0])) {
99 19
            foreach ($outputs as $address => $value) {
100 19
                if (!is_string($address)) {
101 1
                    throw new BlocktrailSDKException("Encountered invalid address while traversing address keyed list..");
102
                }
103
104 19
                $newOutputs[] = $this->parseAddressOutput($address, $value, $network);
105
            }
106
        }
107
108 29
        foreach ($newOutputs as &$newOutput) {
109 29
            if (fmod($newOutput['value'], 1)) {
110 2
                throw new BlocktrailSDKException("Value should be in Satoshis");
111
            }
112
113 27
            if (is_string($newOutput['scriptPubKey'])) {
114 13
                $newOutput['scriptPubKey'] = ScriptFactory::fromHex($newOutput['scriptPubKey']);
115
            }
116
117 27
            if (strlen($newOutput['scriptPubKey']->getBinary()) < 1) {
118 1
                throw new BlocktrailSDKException("Script cannot be empty");
119
            }
120
121 26
            if ($newOutput['scriptPubKey']->getBinary()[0] !== "\x6a") {
122 25
                if (!$newOutput['value']) {
123 1
                    throw new BlocktrailSDKException("Values should be non zero");
124 24
                } else if ($newOutput['value'] < Blocktrail::DUST) {
125 25
                    throw new BlocktrailSDKException("Values should be more than dust (" . Blocktrail::DUST . ")");
126
                }
127
            }
128
        }
129
130 24
        return $newOutputs;
131
    }
132
}
133