BlockchainResult.php
1 <?php 2 3 namespace BitcoindRPC\Blockchain; 4 5 use BitcoindRPC\RpcResponse; 6 7 class BlockchainResult 8 { 9 private RpcResponse $response; 10 11 public function __construct(RpcResponse $response) 12 { 13 $this->response = $response; 14 } 15 16 public function isSuccess(): bool 17 { 18 return $this->response->isSuccess(); 19 } 20 21 public function getData(): mixed 22 { 23 return $this->response->getData(); 24 } 25 26 public function getError(): ?string 27 { 28 return $this->response->getError(); 29 } 30 31 public function getStatusCode(): int 32 { 33 return $this->response->getStatusCode(); 34 } 35 36 public function toArray(): array 37 { 38 return $this->response->toArray(); 39 } 40 41 // Block specific methods 42 public function getBlockData(): ?array 43 { 44 $data = $this->getData(); 45 return is_array($data) ? $data : null; 46 } 47 48 public function getBlockHash(): ?string 49 { 50 $data = $this->getData(); 51 52 if (is_string($data)) { 53 return $data; 54 } 55 if (is_array($data) && isset($data['hash'])) { 56 return $data['hash']; 57 } 58 59 return null; 60 } 61 62 public function getBlockHeight(): ?int 63 { 64 $block = $this->getBlockData(); 65 return $block['height'] ?? null; 66 } 67 68 public function getBlockSize(): ?int 69 { 70 $block = $this->getBlockData(); 71 return $block['size'] ?? null; 72 } 73 74 public function getBlockWeight(): ?int 75 { 76 $block = $this->getBlockData(); 77 return $block['weight'] ?? null; 78 } 79 80 public function getBlockTime(): ?int 81 { 82 $block = $this->getBlockData(); 83 return $block['time'] ?? null; 84 } 85 86 public function getBlockMedianTime(): ?int 87 { 88 $block = $this->getBlockData(); 89 return $block['mediantime'] ?? null; 90 } 91 92 public function getBlockNonce(): ?int 93 { 94 $block = $this->getBlockData(); 95 return $block['nonce'] ?? null; 96 } 97 98 public function getBlockBits(): ?string 99 { 100 $block = $this->getBlockData(); 101 return $block['bits'] ?? null; 102 } 103 104 public function getBlockDifficulty(): ?float 105 { 106 $block = $this->getBlockData(); 107 return $block['difficulty'] ?? null; 108 } 109 110 public function getBlockTransactionCount(): ?int 111 { 112 $block = $this->getBlockData(); 113 114 if (isset($block['tx']) && is_array($block['tx'])) { 115 return count($block['tx']); 116 } 117 118 return null; 119 } 120 121 public function getBlockTransactions(): ?array 122 { 123 $block = $this->getBlockData(); 124 return $block['tx'] ?? null; 125 } 126 127 // Blockchain info methods 128 public function getBlockchainInfo(): ?array 129 { 130 $data = $this->getData(); 131 return is_array($data) ? $data : null; 132 } 133 134 public function getChain(): ?string 135 { 136 $info = $this->getBlockchainInfo(); 137 return $info['chain'] ?? null; 138 } 139 140 public function getBlocks(): ?int 141 { 142 $info = $this->getBlockchainInfo(); 143 return $info['blocks'] ?? null; 144 } 145 146 public function getHeaders(): ?int 147 { 148 $info = $this->getBlockchainInfo(); 149 return $info['headers'] ?? null; 150 } 151 152 public function getBestBlockHashFromInfo(): ?string 153 { 154 $info = $this->getBlockchainInfo(); 155 return $info['bestblockhash'] ?? null; 156 } 157 158 public function getVerificationProgress(): ?float 159 { 160 $info = $this->getBlockchainInfo(); 161 return $info['verificationprogress'] ?? null; 162 } 163 164 public function isInitialBlockDownload(): ?bool 165 { 166 $info = $this->getBlockchainInfo(); 167 return $info['initialblockdownload'] ?? null; 168 } 169 170 // Mempool methods 171 public function getMempoolInfo(): ?array 172 { 173 $data = $this->getData(); 174 return is_array($data) ? $data : null; 175 } 176 177 public function getMempoolSize(): ?int 178 { 179 $info = $this->getMempoolInfo(); 180 return $info['size'] ?? null; 181 } 182 183 public function getMempoolBytes(): ?int 184 { 185 $info = $this->getMempoolInfo(); 186 return $info['bytes'] ?? null; 187 } 188 189 public function getMempoolUsage(): ?int 190 { 191 $info = $this->getMempoolInfo(); 192 return $info['usage'] ?? null; 193 } 194 195 public function getMempoolTransactions(): ?array 196 { 197 $data = $this->getData(); 198 return is_array($data) ? $data : null; 199 } 200 201 public function getMempoolTransactionIds(): ?array 202 { 203 $data = $this->getData(); 204 205 if (is_array($data)) { 206 // If verbose is false, data is an array of txids 207 if (!empty($data) && is_string(reset($data))) { 208 return $data; 209 } 210 // If verbose is true, data is an associative array with txids as keys 211 else { 212 return array_keys($data); 213 } 214 } 215 216 return null; 217 } 218 219 public function getMempoolTransactionCount(): ?int 220 { 221 $txs = $this->getMempoolTransactions(); 222 return is_array($txs) ? count($txs) : null; 223 } 224 225 // Transaction methods 226 public function getTransactionData(): ?array 227 { 228 $data = $this->getData(); 229 return is_array($data) ? $data : null; 230 } 231 232 public function getTransactionConfirmations(): ?int 233 { 234 $tx = $this->getTransactionData(); 235 return $tx['confirmations'] ?? null; 236 } 237 238 public function getTransactionBlockHash(): ?string 239 { 240 $tx = $this->getTransactionData(); 241 return $tx['blockhash'] ?? null; 242 } 243 244 public function getTransactionBlockHeight(): ?int 245 { 246 $tx = $this->getTransactionData(); 247 return $tx['blockheight'] ?? null; 248 } 249 250 public function getTransactionBlockTime(): ?int 251 { 252 $tx = $this->getTransactionData(); 253 return $tx['blocktime'] ?? null; 254 } 255 256 public function getTransactionSize(): ?int 257 { 258 $tx = $this->getTransactionData(); 259 return $tx['size'] ?? null; 260 } 261 262 public function getTransactionVsize(): ?int 263 { 264 $tx = $this->getTransactionData(); 265 return $tx['vsize'] ?? null; 266 } 267 268 public function getTransactionWeight(): ?int 269 { 270 $tx = $this->getTransactionData(); 271 return $tx['weight'] ?? null; 272 } 273 274 public function getTransactionFee(): ?float 275 { 276 $tx = $this->getTransactionData(); 277 return $tx['fee'] ?? null; 278 } 279 280 // UTXO methods 281 public function getTxOutSetInfo(): ?array 282 { 283 $data = $this->getData(); 284 return is_array($data) ? $data : null; 285 } 286 287 public function getUTXOCount(): ?int 288 { 289 $info = $this->getTxOutSetInfo(); 290 return $info['txouts'] ?? null; 291 } 292 293 public function getUTXOTotalAmount(): ?float 294 { 295 $info = $this->getTxOutSetInfo(); 296 return $info['total_amount'] ?? null; 297 } 298 299 public function getUTXOHeight(): ?int 300 { 301 $info = $this->getTxOutSetInfo(); 302 return $info['height'] ?? null; 303 } 304 305 public function getUTXOBestBlock(): ?string 306 { 307 $info = $this->getTxOutSetInfo(); 308 return $info['bestblock'] ?? null; 309 } 310 311 // Chain tips methods 312 public function getChainTips(): ?array 313 { 314 $data = $this->getData(); 315 return is_array($data) ? $data : null; 316 } 317 318 public function getChainTipCount(): ?int 319 { 320 $tips = $this->getChainTips(); 321 return is_array($tips) ? count($tips) : null; 322 } 323 324 // Block stats methods 325 public function getBlockStats(): ?array 326 { 327 $data = $this->getData(); 328 return is_array($data) ? $data : null; 329 } 330 331 public function getBlockStatsHeight(): ?int 332 { 333 $stats = $this->getBlockStats(); 334 return $stats['height'] ?? null; 335 } 336 337 public function getBlockStatsTxCount(): ?int 338 { 339 $stats = $this->getBlockStats(); 340 return $stats['txs'] ?? null; 341 } 342 343 public function getBlockStatsTotalFee(): ?float 344 { 345 $stats = $this->getBlockStats(); 346 return $stats['totalfee'] ?? null; 347 } 348 349 public function getBlockStatsTotalSize(): ?int 350 { 351 $stats = $this->getBlockStats(); 352 return $stats['totalsize'] ?? null; 353 } 354 355 // Utility methods 356 public function getBlockchainSummary(): array 357 { 358 $summary = [ 359 'success' => $this->isSuccess(), 360 'error' => $this->getError(), 361 'status_code' => $this->getStatusCode(), 362 'type' => 'unknown' 363 ]; 364 365 if ($this->isSuccess()) { 366 $data = $this->getData(); 367 368 if (is_array($data)) { 369 // Blockchain info response 370 if (isset($data['chain'])) { 371 $summary['type'] = 'blockchain_info'; 372 $summary['chain'] = $data['chain']; 373 $summary['blocks'] = $data['blocks']; 374 $summary['headers'] = $data['headers']; 375 $summary['best_block_hash'] = $data['bestblockhash']; 376 $summary['difficulty'] = $data['difficulty'] ?? null; 377 $summary['verification_progress'] = $data['verificationprogress'] ?? null; 378 } 379 // Block response 380 elseif (isset($data['hash']) && isset($data['height'])) { 381 $summary['type'] = 'block'; 382 $summary['hash'] = $data['hash']; 383 $summary['height'] = $data['height']; 384 $summary['size'] = $data['size'] ?? null; 385 $summary['time'] = $data['time'] ?? null; 386 $summary['tx_count'] = count($data['tx'] ?? []); 387 } 388 // Mempool info response 389 elseif (isset($data['size']) && isset($data['bytes'])) { 390 $summary['type'] = 'mempool_info'; 391 $summary['size'] = $data['size']; 392 $summary['bytes'] = $data['bytes']; 393 $summary['usage'] = $data['usage'] ?? null; 394 } 395 // Transaction response 396 elseif (isset($data['txid']) && isset($data['size'])) { 397 $summary['type'] = 'transaction'; 398 $summary['txid'] = $data['txid']; 399 $summary['size'] = $data['size']; 400 $summary['vsize'] = $data['vsize'] ?? null; 401 $summary['confirmations'] = $data['confirmations'] ?? 0; 402 $summary['block_hash'] = $data['blockhash'] ?? null; 403 } 404 // UTXO set info response 405 elseif (isset($data['height']) && isset($data['txouts'])) { 406 $summary['type'] = 'utxo_set_info'; 407 $summary['height'] = $data['height']; 408 $summary['txouts'] = $data['txouts']; 409 $summary['total_amount'] = $data['total_amount'] ?? null; 410 $summary['best_block'] = $data['bestblock'] ?? null; 411 } 412 // Chain tips response 413 elseif (is_array($data) && !empty($data) && isset($data[0]['height'])) { 414 $summary['type'] = 'chain_tips'; 415 $summary['tip_count'] = count($data); 416 } 417 // Block stats response 418 elseif (isset($data['height']) && isset($data['txs'])) { 419 $summary['type'] = 'block_stats'; 420 $summary['height'] = $data['height']; 421 $summary['tx_count'] = $data['txs']; 422 $summary['total_fee'] = $data['totalfee'] ?? null; 423 $summary['total_size'] = $data['totalsize'] ?? null; 424 } 425 // Mempool transactions response 426 elseif (is_array($data) && !empty($data)) { 427 if (is_string(reset($data))) { 428 $summary['type'] = 'mempool_txids'; 429 $summary['tx_count'] = count($data); 430 } else { 431 $summary['type'] = 'mempool_tx_details'; 432 $summary['tx_count'] = count($data); 433 } 434 } 435 } elseif (is_string($data)) { 436 // Block hash or hex data response 437 if (strlen($data) === 64) { 438 $summary['type'] = 'block_hash'; 439 $summary['hash'] = $data; 440 } else { 441 $summary['type'] = 'hex_data'; 442 $summary['data_length'] = strlen($data); 443 } 444 } elseif (is_numeric($data)) { 445 // Block count or difficulty response 446 $summary['type'] = 'numeric'; 447 $summary['value'] = $data; 448 } elseif (is_bool($data)) { 449 // Verification result 450 $summary['type'] = 'verification'; 451 $summary['verified'] = $data; 452 } 453 } 454 455 return $summary; 456 } 457 458 public function isBlockConfirmed(): ?bool 459 { 460 return $this->getBlockHeight() !== null; 461 } 462 463 public function isTransactionConfirmed(): ?bool 464 { 465 return $this->getTransactionConfirmations() > 0; 466 } 467 468 public function getTransactionFeeRate(): ?float 469 { 470 $fee = $this->getTransactionFee(); 471 $vsize = $this->getTransactionVsize(); 472 473 if ($fee !== null && $vsize !== null && $vsize > 0) { 474 return ($fee * 100000000) / $vsize; // Convert to sat/vbyte 475 } 476 477 return null; 478 } 479 }