Skip to content

Commit

Permalink
penumbra-ibc: ⏎ invert early return condition
Browse files Browse the repository at this point in the history
this diff is best viewed ignoring whitespace; use `-w`, or the "_hide
whitespace_" option in github (the gear icon in the "_files changed_"
tab).

this inverts our early return, so that we do not need to wrap the whole
function body within a conditional block. this is a pure refactor that
should have no visible changes to behavior.
  • Loading branch information
cratelyn committed Jan 29, 2024
1 parent 5bea79b commit 227046b
Showing 1 changed file with 117 additions and 116 deletions.
233 changes: 117 additions & 116 deletions crates/core/component/ibc/src/component/msg_handler/update_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,124 +35,125 @@ impl MsgHandler for MsgUpdateClient {
// to Ok(()) rather than erroring to avoid having two "racing" relay
// transactions fail just because they both contain the same client
// update.
if !update_is_already_committed(&state, self).await? {
tracing::debug!(msg = ?self);

let client_state = client_is_present(&state, self).await?;

client_is_not_frozen(&client_state)?;
client_is_not_expired::<&S, HI>(&state, &self.client_id, &client_state).await?;

let trusted_client_state = client_state;

let untrusted_header =
ics02_validation::get_tendermint_header(self.client_message.clone())?;

header_revision_matches_client_state(&trusted_client_state, &untrusted_header)?;
header_height_is_consistent(&untrusted_header)?;

// The (still untrusted) header uses the `trusted_height` field to
// specify the trusted anchor data it is extending.
let trusted_height = untrusted_header.trusted_height;

// We use the specified trusted height to query the trusted
// consensus state the update extends.
let last_trusted_consensus_state = state
.get_verified_consensus_state(&trusted_height, &self.client_id)
.await?;

// We also have to convert from an IBC height, which has two
// components, to a Tendermint height, which has only one.
let trusted_height = trusted_height
.revision_height()
.try_into()
.context("invalid header height")?;

let trusted_validator_set =
verify_header_validator_set(&untrusted_header, &last_trusted_consensus_state)?;

// Now we build the trusted and untrusted states to feed to the Tendermint light client.

let trusted_state = TrustedBlockState {
// TODO(erwan): do we need an additional check on `chain_id`
chain_id: &trusted_client_state.chain_id.clone().into(),
header_time: last_trusted_consensus_state.timestamp,
height: trusted_height,
next_validators: trusted_validator_set,
next_validators_hash: last_trusted_consensus_state.next_validators_hash,
};

let untrusted_state = UntrustedBlockState {
signed_header: &untrusted_header.signed_header,
validators: &untrusted_header.validator_set,
next_validators: None, // TODO: do we need this?
};

let options = trusted_client_state.as_light_client_options()?;
let verifier = ProdVerifier::default();

let verdict = verifier.verify_update_header(
untrusted_state,
trusted_state,
&options,
HI::get_block_timestamp(&state).await?,
);

match verdict {
Verdict::Success => Ok(()),
Verdict::NotEnoughTrust(voting_power_tally) => Err(anyhow::anyhow!(
"not enough trust, voting power tally: {:?}",
voting_power_tally
)),
Verdict::Invalid(detail) => Err(anyhow::anyhow!(
"could not verify tendermint header: invalid: {:?}",
detail
)),
}?;

let trusted_header = untrusted_header;

// get the latest client state
let client_state = state
.get_client_state(&self.client_id)
.await
.context("unable to get client state")?;

// NOTE: next_tendermint_state will freeze the client on equivocation.
let (next_tm_client_state, next_tm_consensus_state) = state
.next_tendermint_state(
self.client_id.clone(),
client_state.clone(),
trusted_header.clone(),
)
.await;

// store the updated client and consensus states
state.put_client(&self.client_id, next_tm_client_state);
state
.put_verified_consensus_state::<HI>(
trusted_header.height(),
self.client_id.clone(),
next_tm_consensus_state,
)
.await?;

state.record(
UpdateClient {
client_id: self.client_id.clone(),
client_type: ibc_types::core::client::ClientType(
TENDERMINT_CLIENT_TYPE.to_string(),
), // TODO: hardcoded
consensus_height: trusted_header.height(),
header: <ibc_types::lightclients::tendermint::header::Header as ibc_proto::Protobuf<ibc_proto::ibc::lightclients::tendermint::v1::Header>>::encode_vec(trusted_header),
}
.into(),
);
return Ok(());
} else {
if update_is_already_committed(&state, self).await? {
tracing::debug!("skipping duplicate update");
return Ok(());
}

tracing::debug!(msg = ?self);

let client_state = client_is_present(&state, self).await?;

client_is_not_frozen(&client_state)?;
client_is_not_expired::<&S, HI>(&state, &self.client_id, &client_state).await?;

let trusted_client_state = client_state;

let untrusted_header =
ics02_validation::get_tendermint_header(self.client_message.clone())?;

header_revision_matches_client_state(&trusted_client_state, &untrusted_header)?;
header_height_is_consistent(&untrusted_header)?;

// The (still untrusted) header uses the `trusted_height` field to
// specify the trusted anchor data it is extending.
let trusted_height = untrusted_header.trusted_height;

// We use the specified trusted height to query the trusted
// consensus state the update extends.
let last_trusted_consensus_state = state
.get_verified_consensus_state(&trusted_height, &self.client_id)
.await?;

// We also have to convert from an IBC height, which has two
// components, to a Tendermint height, which has only one.
let trusted_height = trusted_height
.revision_height()
.try_into()
.context("invalid header height")?;

let trusted_validator_set =
verify_header_validator_set(&untrusted_header, &last_trusted_consensus_state)?;

// Now we build the trusted and untrusted states to feed to the Tendermint light client.

let trusted_state = TrustedBlockState {
// TODO(erwan): do we need an additional check on `chain_id`
chain_id: &trusted_client_state.chain_id.clone().into(),
header_time: last_trusted_consensus_state.timestamp,
height: trusted_height,
next_validators: trusted_validator_set,
next_validators_hash: last_trusted_consensus_state.next_validators_hash,
};

let untrusted_state = UntrustedBlockState {
signed_header: &untrusted_header.signed_header,
validators: &untrusted_header.validator_set,
next_validators: None, // TODO: do we need this?
};

let options = trusted_client_state.as_light_client_options()?;
let verifier = ProdVerifier::default();

let verdict = verifier.verify_update_header(
untrusted_state,
trusted_state,
&options,
HI::get_block_timestamp(&state).await?,
);

match verdict {
Verdict::Success => Ok(()),
Verdict::NotEnoughTrust(voting_power_tally) => Err(anyhow::anyhow!(
"not enough trust, voting power tally: {:?}",
voting_power_tally
)),
Verdict::Invalid(detail) => Err(anyhow::anyhow!(
"could not verify tendermint header: invalid: {:?}",
detail
)),
}?;

let trusted_header = untrusted_header;

// get the latest client state
let client_state = state
.get_client_state(&self.client_id)
.await
.context("unable to get client state")?;

// NOTE: next_tendermint_state will freeze the client on equivocation.
let (next_tm_client_state, next_tm_consensus_state) = state
.next_tendermint_state(
self.client_id.clone(),
client_state.clone(),
trusted_header.clone(),
)
.await;

// store the updated client and consensus states
state.put_client(&self.client_id, next_tm_client_state);
state
.put_verified_consensus_state::<HI>(
trusted_header.height(),
self.client_id.clone(),
next_tm_consensus_state,
)
.await?;

state.record(
UpdateClient {
client_id: self.client_id.clone(),
client_type: ibc_types::core::client::ClientType(
TENDERMINT_CLIENT_TYPE.to_string(),
), // TODO: hardcoded
consensus_height: trusted_header.height(),
header:
<ibc_types::lightclients::tendermint::header::Header as ibc_proto::Protobuf<
ibc_proto::ibc::lightclients::tendermint::v1::Header,
>>::encode_vec(trusted_header),
}
.into(),
);
Ok(())
}
}
Expand Down

0 comments on commit 227046b

Please sign in to comment.