|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Blocktrail\SDK\Address; |
|
4
|
|
|
|
|
5
|
|
|
use BitWasp\Bitcoin\Address\Base58AddressInterface; |
|
6
|
|
|
use BitWasp\Bitcoin\Address\PayToPubKeyHashAddress; |
|
7
|
|
|
use BitWasp\Bitcoin\Address\ScriptHashAddress; |
|
8
|
|
|
use BitWasp\Bitcoin\Bitcoin; |
|
9
|
|
|
use BitWasp\Bitcoin\Network\NetworkInterface; |
|
10
|
|
|
use BitWasp\Bitcoin\Script\Classifier\OutputClassifier; |
|
11
|
|
|
use BitWasp\Bitcoin\Script\ScriptInterface; |
|
12
|
|
|
use BitWasp\Bitcoin\Script\ScriptType; |
|
13
|
|
|
use BitWasp\Buffertools\Buffer; |
|
14
|
|
|
use BitWasp\Buffertools\BufferInterface; |
|
15
|
|
|
use Blocktrail\SDK\Exceptions\BlocktrailSDKException; |
|
16
|
|
|
use Blocktrail\SDK\Network\BitcoinCashNetworkInterface; |
|
17
|
|
|
|
|
18
|
|
|
class BitcoinCashAddressReader extends AddressReaderBase |
|
19
|
|
|
{ |
|
20
|
|
|
/** |
|
21
|
|
|
* @var bool |
|
22
|
|
|
*/ |
|
23
|
|
|
private $useNewCashAddress; |
|
24
|
|
|
|
|
25
|
|
|
/** |
|
26
|
|
|
* BitcoinCashAddressReader constructor. |
|
27
|
|
|
* @param bool $useNewCashAddress |
|
28
|
|
|
*/ |
|
29
|
7 |
|
public function __construct($useNewCashAddress) { |
|
30
|
7 |
|
$this->useNewCashAddress = (bool) $useNewCashAddress; |
|
31
|
7 |
|
} |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* @param string $strAddress |
|
35
|
|
|
* @param BitcoinCashNetworkInterface $network |
|
36
|
|
|
* @return CashAddress|null |
|
37
|
|
|
*/ |
|
38
|
5 |
|
protected function readCashAddress($strAddress, BitcoinCashNetworkInterface $network) { |
|
39
|
|
|
try { |
|
40
|
5 |
|
list ($prefix, $scriptType, $hash) = \CashAddr\CashAddress::decode($strAddress); |
|
41
|
5 |
|
if ($prefix !== $network->getCashAddressPrefix()) { |
|
42
|
1 |
|
return null; |
|
43
|
|
|
} |
|
44
|
4 |
|
if (!($scriptType === ScriptType::P2PKH || $scriptType === ScriptType::P2SH)) { |
|
45
|
|
|
return null; |
|
46
|
|
|
} |
|
47
|
|
|
|
|
48
|
4 |
|
return new CashAddress($scriptType, new Buffer($hash, 20)); |
|
49
|
|
|
} catch (\Exception $e) { |
|
50
|
|
|
// continue on |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
try { |
|
54
|
|
|
list ($prefix, $scriptType, $hash) = \CashAddr\CashAddress::decode( |
|
55
|
|
|
sprintf("%s:%s", $network->getCashAddressPrefix(), $strAddress) |
|
56
|
|
|
); |
|
57
|
|
|
|
|
58
|
|
|
if ($prefix !== $network->getCashAddressPrefix()) { |
|
59
|
|
|
return null; |
|
60
|
|
|
} |
|
61
|
|
|
if (!($scriptType === ScriptType::P2PKH || $scriptType === ScriptType::P2SH)) { |
|
62
|
|
|
return null; |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
return new CashAddress($scriptType, new Buffer($hash, 20)); |
|
66
|
|
|
} catch (\Exception $e) { |
|
67
|
|
|
// continue on |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
|
|
return null; |
|
71
|
|
|
} |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* @param string $strAddress |
|
75
|
|
|
* @param NetworkInterface|null $network |
|
76
|
|
|
* @return Base58AddressInterface|CashAddress |
|
77
|
|
|
* @throws BlocktrailSDKException |
|
78
|
|
|
*/ |
|
79
|
7 |
|
public function fromString($strAddress, NetworkInterface $network = null) { |
|
80
|
7 |
|
$network = $network ?: Bitcoin::getNetwork(); |
|
81
|
|
|
|
|
82
|
7 |
|
if (($base58Address = $this->readBase58($strAddress, $network))) { |
|
83
|
4 |
|
return $base58Address; |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
5 |
|
if ($this->useNewCashAddress && $network instanceof BitcoinCashNetworkInterface) { |
|
87
|
5 |
|
if (($base32Address = $this->readCashAddress($strAddress, $network))) { |
|
88
|
4 |
|
return $base32Address; |
|
89
|
|
|
} |
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
1 |
|
throw new BlocktrailSDKException("Address not recognized"); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
/** |
|
96
|
|
|
* @param ScriptInterface $script |
|
97
|
|
|
* @return Base58AddressInterface|CashAddress |
|
98
|
|
|
*/ |
|
99
|
2 |
|
public function fromOutputScript(ScriptInterface $script) { |
|
100
|
2 |
|
$decode = (new OutputClassifier())->decode($script); |
|
101
|
|
|
|
|
102
|
2 |
|
switch ($decode->getType()) { |
|
103
|
2 |
|
case ScriptType::P2PKH: |
|
104
|
|
|
/** @var BufferInterface $solution */ |
|
105
|
|
|
if ($this->useNewCashAddress) { |
|
106
|
|
|
return new CashAddress(ScriptType::P2PKH, $decode->getSolution()); |
|
107
|
|
|
} else { |
|
108
|
|
|
return new PayToPubKeyHashAddress($decode->getSolution()); |
|
109
|
|
|
} |
|
110
|
|
|
break; |
|
|
|
|
|
|
111
|
2 |
|
case ScriptType::P2SH: |
|
112
|
|
|
/** @var BufferInterface $solution */ |
|
113
|
2 |
|
if ($this->useNewCashAddress) { |
|
114
|
1 |
|
return new CashAddress(ScriptType::P2SH, $decode->getSolution()); |
|
115
|
|
|
} else { |
|
116
|
1 |
|
return new ScriptHashAddress($decode->getSolution()); |
|
117
|
|
|
} |
|
118
|
|
|
break; |
|
|
|
|
|
|
119
|
|
|
default: |
|
120
|
|
|
throw new \RuntimeException('Script type is not associated with an address'); |
|
121
|
|
|
} |
|
122
|
|
|
} |
|
123
|
|
|
} |
|
124
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return,dieorexitstatements that have been added for debug purposes.In the above example, the last
return falsewill never be executed, because a return statement has already been met in every possible execution path.