Attested header is stored instead of finalized header
Description
The function update_consensus_state
is used to return the updated consensus state, updated slot, and the updated client state, which is then stored in the storage. The function uses the slot/timestamp and root values of the attested header instead of the finalized header to update the storage. As per the specification of the sync protocol, the finalized header should be used to update the storage. Furthermore, the slot of the attested header is used to calculate the update_finalized_period
, as shown below:
let update_finalized_period = compute_sync_committee_period_at_slot(
current_client_state.slots_per_epoch,
current_client_state.epochs_per_sync_committee_period,
consensus_update.attested_header.beacon.slot,
);
//...
let updated_slot = core::cmp::max(trusted_slot, consensus_update.attested_header.beacon.slot);
if consensus_update.attested_header.beacon.slot > current_consensus_state.slot {
new_consensus_state.slot = consensus_update.attested_header.beacon.slot;
new_consensus_state.state_root = consensus_update.attested_header.execution.state_root;
new_consensus_state.storage_root = header.account_update.account_proof.storage_root;
new_consensus_state.timestamp = compute_timestamp_at_slot(
current_client_state.seconds_per_slot,
current_client_state.genesis_time,
consensus_update.attested_header.beacon.slot,
);
if current_client_state.latest_slot < consensus_update.attested_header.beacon.slot {
new_client_state = Some(ClientState {
latest_slot: consensus_update.attested_header.beacon.slot,
..current_client_state
});
}
}
Ok((updated_slot, new_consensus_state, new_client_state))
Similarly in verify.rs:verify_header
, the verify_account_storage_root
function should use the finalized header's state_root
instead of the attested header's state root.
Impact
The security guarantees of the attested header and the finalized header are different. The attested header represents a block that is highly likely to be a part of the canonical chain but has not reached finality. In the case of a chain reorg, the attested header cannot be trusted.
Recommendations
We recommend using the finalized header for the updates instead of attested header, as per the specification.
Remediation
This issue has been acknowledged by Interchain Labs, and a fix was implemented in commit 537b47c1↗.