Airship\Engine\Keyggdrasil::updateChannel PHP Method

updateChannel() protected method

1. Identify a working URL for the channel. 2. Query server for updates. 3. For each update: 1. Verify that our trusted notaries see the same update. (Ed25519 signature of challenge nonce || Merkle root) 2. Add/remove the supplier's key.
protected updateChannel ( Channel $chan )
$chan Channel
    protected function updateChannel(Channel $chan)
    {
        // The original Merkle Tree (and root) from the last-known-good state.
        $originalTree = $this->getMerkleTree($chan);
        $originalRoot = $originalTree->getRoot();
        foreach ($chan->getAllURLs() as $url) {
            try {
                /**
                 * Fetch all the alleged updates from the server, which are to
                 * be treated with severe skepticism. The updates we see here
                 * are, at least, authenticated by the server API's signing key
                 * which means we're commmunicating with the correct channel.
                 *
                 * @var TreeUpdate[]
                 */
                $updates = $this->fetchTreeUpdates($chan, $url, $originalRoot);
                if (empty($updates)) {
                    // Nothing to do.
                    return;
                }
                /**
                 * We'll keep retrying until we're in a good state or we have
                 * no more candidate updates left to add to our tree.
                 */
                while (!empty($updates)) {
                    $merkleTree = $originalTree->getExpandedTree();
                    // Verify these updates with our Peers.
                    try {
                        if ($this->verifyResponseWithPeers($chan, $merkleTree, ...$updates)) {
                            // Apply these updates:
                            $this->processTreeUpdates($chan, ...$updates);
                            return;
                        }
                        // If we're here, verification failed
                    } catch (CouldNotUpdate $ex) {
                        /**
                         * Something bad happened. Possibilities:
                         *
                         * 1. One of our peers disagreed with the Merkle root
                         *    that we saw, so we aborted for safety.
                         * 2. Too many network failures occurred, so we aborted
                         *    to prevent a DoS to create a false consensus.
                         *
                         * Log the details, then the loop will continue.
                         */
                        $this->log($ex->getMessage(), LogLevel::ALERT, \Airship\throwableToArray($ex));
                        $subsequent = [];
                        foreach ($updates as $up) {
                            if ($up instanceof TreeUpdate) {
                                $subsequent[] = $this->getLogData($up);
                            }
                        }
                        self::$continuumLogger->store(LogLevel::ALERT, $ex->getMessage(), ['action' => 'KEYGGDRASIL', 'baseRoot' => $originalRoot, 'subsequent' => $subsequent]);
                    }
                    // If verification fails, pop off the last update and try again
                    \array_pop($updates);
                }
                // Received a successful API response.
                return;
            } catch (ChannelSignatureFailed $ex) {
                /**
                 * We can't even trust the channel's API response. An error
                 * occurred. We aborte entirely at this step.
                 *
                 * This may mean a MITM attacker with a valid CA certificate.
                 * This may mean a server-side error.
                 *
                 * Log and abort; don't try to automate any decisions based
                 * on a strange network state.
                 */
                $this->log('Invalid Channel Signature for ' . $chan->getName(), LogLevel::ALERT, \Airship\throwableToArray($ex));
                self::$continuumLogger->store(LogLevel::ALERT, 'Invalid Channel Signature for ' . $chan->getName(), ['action' => 'KEYGGDRASIL']);
            } catch (TransferException $ex) {
                /**
                 * Typical network error. Maybe an HTTP 5xx response code?
                 *
                 * Either way: log and abort.
                 */
                $this->log('Channel update error', LogLevel::NOTICE, \Airship\throwableToArray($ex));
            }
        }
        // IF we get HERE, we've run out of updates to try.
        $this->log('Channel update concluded with no changes', LogLevel::ALERT);
    }