ledgerModel = model(BlockchainLedgerModel::class); } /** * @param array $payload * @return array{index:int,hash:string,previous_hash:string} */ public function appendBlock(string $txType, array $payload, ?string $entityUuid, int $entityVersion, ?int $actorIdx, ?int $lgIdx): array { $latest = $this->ledgerModel->orderBy('bl_idx', 'DESC')->first(); // 원장이 비어 있으면 $latest 가 null — $latest->bl_hash 는 PHP 8에서 치명 오류(? 는 ?? 와 달리 속성 접근 자체가 먼저 평가됨) $previousHash = ($latest === null || ! isset($latest->bl_hash) || (string) $latest->bl_hash === '') ? str_repeat('0', 64) : (string) $latest->bl_hash; $now = date('Y-m-d H:i:s'); $normalizedPayload = $this->normalizeArray($payload); $payloadJson = json_encode($normalizedPayload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}'; $hashInput = implode('|', [ $now, $txType, $entityUuid ?? '', (string) $entityVersion, $payloadJson, $previousHash, '0', ]); $currentHash = hash('sha256', $hashInput); $this->ledgerModel->insert([ 'bl_created_at' => $now, 'bl_tx_type' => $txType, 'bl_entity_uuid' => $entityUuid, 'bl_entity_version' => $entityVersion, 'bl_payload' => $payloadJson, 'bl_previous_hash' => $previousHash, 'bl_hash' => $currentHash, 'bl_nonce' => 0, 'bl_actor_idx' => $actorIdx, 'bl_lg_idx' => $lgIdx, ]); return [ 'index' => (int) $this->ledgerModel->getInsertID(), 'hash' => $currentHash, 'previous_hash' => $previousHash, ]; } /** * @param array $data * @return array */ private function normalizeArray(array $data): array { ksort($data); foreach ($data as $key => $value) { if (is_array($value)) { if ($this->isAssoc($value)) { /** @var array $assoc */ $assoc = $value; $data[$key] = $this->normalizeArray($assoc); } else { $normalizedList = []; foreach ($value as $item) { if (is_array($item) && $this->isAssoc($item)) { /** @var array $assoc */ $assoc = $item; $normalizedList[] = $this->normalizeArray($assoc); } else { $normalizedList[] = $item; } } $data[$key] = $normalizedList; } } } return $data; } /** * @param array $array */ private function isAssoc(array $array): bool { if ($array === []) { return false; } return array_keys($array) !== range(0, count($array) - 1); } }