Completed
Pull Request — master (#99)
by thomas
16:06
created

OutputsNormalizer::parseAddressOutput()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 3
dl 0
loc 16
ccs 9
cts 9
cp 1
crap 2
rs 9.4285
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 29
    public function __construct(AddressReaderBase $reader)
26
    {
27 29
        $this->reader = $reader;
28 29
    }
29
30
    /**
31
     * @param array $output
32
     * @return array
33
     * @throws BlocktrailSDKException
34
     */
35 9
    protected function readArrayFormat(array $output, Network $network) {
36 9
        if (array_key_exists("scriptPubKey", $output) && array_key_exists("value", $output)) {
37
            return [
38 2
                "scriptPubKey" => $output['scriptPubKey'],
39 2
                "value" => $output['value'],
40
            ];
41 7
        } else if (array_key_exists("address", $output) && array_key_exists("value", $output)) {
42 5
            return $this->parseAddressOutput($output['address'], $output['value'], $network);
43
        } else {
44 2
            $keys = array_keys($output);
45 2
            if (count($keys) === 2 && count($output) === 2 && $keys[0] === 0 && $keys[1] === 1) {
46 1
                return $this->parseAddressOutput($output[0], $output[1], $network);
47
            } else {
48 1
                throw new BlocktrailSDKException("Invalid transaction output for numerically indexed list");
49
            }
50
        }
51
    }
52
53
    /**
54
     * @param $address
55
     * @param $value
56
     * @return array
57
     */
58 24
    private function parseAddressOutput($address, $value, $network) {
59 24
        if ($address === "opreturn") {
60 1
            $data = new Buffer($value);
61 1
            $scriptPubKey = ScriptFactory::sequence([Opcodes::OP_RETURN, $data]);
62
            return [
63 1
                "value" => 0,
64 1
                "scriptPubKey" => $scriptPubKey,
65
            ];
66
        }
67
68 23
        $object = $this->reader->fromString($address, $network);
69
        return [
70 23
            "value" => $value,
71 23
            "scriptPubKey" => $object->getScriptPubKey(),
72
        ];
73
    }
74
75
    /**
76
     * @param array $outputs
77
     * @param NetworkInterface|null $network
78
     * @return array
79
     * @throws BlocktrailSDKException
80
     */
81 29
    public function normalize(array $outputs, NetworkInterface $network = null) {
82 29
        $network = $network ?: Bitcoin::getNetwork();
83 29
        if (empty($outputs)) {
84 1
            return [];
85
        }
86
87 28
        $keys = array_keys($outputs);
88 28
        $newOutputs = [];
89 28
        if (is_int($keys[0])) {
90 10
            foreach ($outputs as $i => $output) {
91 10
                if (!is_int($i)) {
92 1
                    throw new BlocktrailSDKException("Encountered invalid index while traversing numerically indexed list");
93
                }
94 10
                if (!is_array($output)) {
95 1
                    throw new BlocktrailSDKException("Encountered invalid output while traversing numerically indexed list");
96
                }
97 9
                $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...
98
            }
99 18
        } else if (is_string($keys[0])) {
100 18
            foreach ($outputs as $address => $value) {
101 18
                if (!is_string($address)) {
102 1
                    throw new BlocktrailSDKException("Encountered invalid address while traversing address keyed list..");
103
                }
104
105 18
                $newOutputs[] = $this->parseAddressOutput($address, $value, $network);
106
            }
107
        }
108
109 24
        foreach ($newOutputs as &$newOutput) {
110 24
            if (fmod($newOutput['value'], 1)) {
111 2
                throw new BlocktrailSDKException("Value should be in Satoshis");
112
            }
113
114 22
            if (is_string($newOutput['scriptPubKey'])) {
115 2
                $newOutput['scriptPubKey'] = ScriptFactory::fromHex($newOutput['scriptPubKey']);
116
            }
117
118 22
            if (strlen($newOutput['scriptPubKey']->getBinary()) < 1) {
119 1
                throw new BlocktrailSDKException("Script cannot be empty");
120
            }
121
122 21
            if ($newOutput['scriptPubKey']->getBinary()[0] !== "\x6a") {
123 20
                if (!$newOutput['value']) {
124 1
                    throw new BlocktrailSDKException("Values should be non zero");
125 19
                } else if ($newOutput['value'] < Blocktrail::DUST) {
126 20
                    throw new BlocktrailSDKException("Values should be more than dust (" . Blocktrail::DUST . ")");
127
                }
128
            }
129
        }
130
131 19
        return $newOutputs;
132
    }
133
}
134