diff --git a/contracts/script/SP1ICS07Tendermint.s.sol b/contracts/script/SP1ICS07Tendermint.s.sol index 27397aa..be3e2ed 100644 --- a/contracts/script/SP1ICS07Tendermint.s.sol +++ b/contracts/script/SP1ICS07Tendermint.s.sol @@ -56,11 +56,10 @@ contract SP1TendermintScript is Script { ICS07Tendermint.ClientState memory clientState = ics07Tendermint .getClientState(); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); - assert(clientState.is_frozen == false); + assert( + keccak256(abi.encode(clientState)) == + keccak256(genesis.trustedClientState) + ); bytes32 consensusHash = ics07Tendermint.getConsensusStateHash( clientState.latest_height.revision_height diff --git a/contracts/test/SP1ICS07TendermintTest.sol b/contracts/test/SP1ICS07TendermintTest.sol index c30e091..709c9d1 100644 --- a/contracts/test/SP1ICS07TendermintTest.sol +++ b/contracts/test/SP1ICS07TendermintTest.sol @@ -78,15 +78,9 @@ abstract contract SP1ICS07TendermintTest is Test { ICS07Tendermint.ClientState memory clientState = mockIcs07Tendermint .getClientState(); assert( - keccak256(bytes(clientState.chain_id)) == - keccak256(bytes("mocha-4")) + keccak256(abi.encode(clientState)) == + keccak256(mockGenesisFixture.trustedClientState) ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); - assert(clientState.is_frozen == false); bytes32 consensusHash = mockIcs07Tendermint.getConsensusStateHash( clientState.latest_height.revision_height diff --git a/contracts/test/UcAndMembership.t.sol b/contracts/test/UcAndMembership.t.sol index b824ea0..109f037 100644 --- a/contracts/test/UcAndMembership.t.sol +++ b/contracts/test/UcAndMembership.t.sol @@ -110,18 +110,9 @@ contract SP1ICS07UpdateClientAndMembershipTest is SP1ICS07TendermintTest { ICS07Tendermint.ClientState memory clientState = ics07Tendermint .getClientState(); - assert( - keccak256(bytes(clientState.chain_id)) == - keccak256(bytes("mocha-4")) - ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); assert( clientState.latest_height.revision_height == fixture.targetHeight ); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); assert(clientState.is_frozen == false); bytes32 consensusHash = ics07Tendermint.getConsensusStateHash( @@ -158,14 +149,9 @@ contract SP1ICS07UpdateClientAndMembershipTest is SP1ICS07TendermintTest { keccak256(bytes(clientState.chain_id)) == keccak256(bytes("mocha-4")) ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); assert( clientState.latest_height.revision_height == fixture.targetHeight ); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); assert(clientState.is_frozen == false); bytes32 consensusHash = mockIcs07Tendermint.getConsensusStateHash( @@ -210,14 +196,9 @@ contract SP1ICS07UpdateClientAndMembershipTest is SP1ICS07TendermintTest { keccak256(bytes(clientState.chain_id)) == keccak256(bytes("mocha-4")) ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); assert( clientState.latest_height.revision_height == fixture.targetHeight ); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); assert(clientState.is_frozen == false); bytes32 consensusHash = ics07Tendermint.getConsensusStateHash( diff --git a/contracts/test/UpdateClient.t.sol b/contracts/test/UpdateClient.t.sol index e8407f3..9f7fd0f 100644 --- a/contracts/test/UpdateClient.t.sol +++ b/contracts/test/UpdateClient.t.sol @@ -104,14 +104,9 @@ contract SP1ICS07UpdateClientTest is SP1ICS07TendermintTest { keccak256(bytes(clientState.chain_id)) == keccak256(bytes("mocha-4")) ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); assert( clientState.latest_height.revision_height == fixture.targetHeight ); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); assert(clientState.is_frozen == false); bytes32 consensusHash = ics07Tendermint.getConsensusStateHash( @@ -169,19 +164,10 @@ contract SP1ICS07UpdateClientTest is SP1ICS07TendermintTest { assert(res == UpdateClientProgram.UpdateResult.Update); ICS07Tendermint.ClientState memory clientState = mockIcs07Tendermint .getClientState(); - assert( - keccak256(bytes(clientState.chain_id)) == - keccak256(bytes("mocha-4")) - ); - assert(clientState.trust_level.numerator == 1); - assert(clientState.trust_level.denominator == 3); - assert(clientState.latest_height.revision_number == 4); assert( clientState.latest_height.revision_height == mockFixture.targetHeight ); - assert(clientState.trusting_period == 1_209_600); - assert(clientState.unbonding_period == 1_209_600); assert(clientState.is_frozen == false); bytes32 consensusHash = mockIcs07Tendermint.getConsensusStateHash( diff --git a/e2e/interchaintestv8/sp1_ics07_test.go b/e2e/interchaintestv8/sp1_ics07_test.go index 7088ac6..c5fb1a2 100644 --- a/e2e/interchaintestv8/sp1_ics07_test.go +++ b/e2e/interchaintestv8/sp1_ics07_test.go @@ -67,7 +67,7 @@ func (s *SP1ICS07TendermintTestSuite) SetupSuite(ctx context.Context) { })) s.Require().True(s.Run("Deploy contracts", func() { - s.Require().NoError(operator.RunGenesis()) + s.Require().NoError(operator.RunGenesis("--trust-level", testvalues.DefaultTrustLevel.String())) stdout, _, err := eth.ForgeScript(ctx, s.UserA.KeyName(), ethereum.ForgeScriptOpts{ ContractRootDir: "contracts", @@ -108,8 +108,8 @@ func (s *SP1ICS07TendermintTestSuite) TestDeploy() { s.Require().NoError(err) s.Require().Equal(simd.Config().ChainID, clientState.ChainId) - s.Require().Equal(uint8(1), clientState.TrustLevel.Numerator) - s.Require().Equal(uint8(3), clientState.TrustLevel.Denominator) + s.Require().Equal(uint8(testvalues.DefaultTrustLevel.Numerator), clientState.TrustLevel.Numerator) + s.Require().Equal(uint8(testvalues.DefaultTrustLevel.Denominator), clientState.TrustLevel.Denominator) s.Require().Equal(uint32(1_209_600), clientState.TrustingPeriod) s.Require().Equal(uint32(1_209_600), clientState.UnbondingPeriod) s.Require().False(clientState.IsFrozen) @@ -135,8 +135,8 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClient() { s.Require().NoError(err) s.Require().Equal(simd.Config().ChainID, clientState.ChainId) - s.Require().Equal(uint8(1), clientState.TrustLevel.Numerator) - s.Require().Equal(uint8(3), clientState.TrustLevel.Denominator) + s.Require().Equal(uint8(testvalues.DefaultTrustLevel.Numerator), clientState.TrustLevel.Numerator) + s.Require().Equal(uint8(testvalues.DefaultTrustLevel.Denominator), clientState.TrustLevel.Denominator) s.Require().Equal(uint32(1_209_600), clientState.TrustingPeriod) s.Require().Equal(uint32(1_209_600), clientState.UnbondingPeriod) s.Require().False(clientState.IsFrozen) diff --git a/e2e/interchaintestv8/testvalues/values.go b/e2e/interchaintestv8/testvalues/values.go index 8c67869..3760e5f 100644 --- a/e2e/interchaintestv8/testvalues/values.go +++ b/e2e/interchaintestv8/testvalues/values.go @@ -5,6 +5,8 @@ import ( "cosmossdk.io/math" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" ) @@ -36,4 +38,7 @@ var ( // StartingEthBalance is the amount of ETH to give to each user at the start of the test. StartingEthBalance = math.NewInt(2 * ethereum.ETHER) + + // DefaultTrustLevel is the trust level used by the SP1ICS07Tendermint contract. + DefaultTrustLevel = ibctm.Fraction{Numerator: 2, Denominator: 3}.ToTendermint() ) diff --git a/elf/membership-riscv32im-succinct-zkvm-elf b/elf/membership-riscv32im-succinct-zkvm-elf index dfdd4e0..d4c445a 100755 Binary files a/elf/membership-riscv32im-succinct-zkvm-elf and b/elf/membership-riscv32im-succinct-zkvm-elf differ diff --git a/elf/uc-and-membership-riscv32im-succinct-zkvm-elf b/elf/uc-and-membership-riscv32im-succinct-zkvm-elf index 66d2a86..bf1ef34 100755 Binary files a/elf/uc-and-membership-riscv32im-succinct-zkvm-elf and b/elf/uc-and-membership-riscv32im-succinct-zkvm-elf differ diff --git a/elf/update-client-riscv32im-succinct-zkvm-elf b/elf/update-client-riscv32im-succinct-zkvm-elf index 80bc58b..1e3f3b9 100755 Binary files a/elf/update-client-riscv32im-succinct-zkvm-elf and b/elf/update-client-riscv32im-succinct-zkvm-elf differ diff --git a/operator/src/cli/command.rs b/operator/src/cli/command.rs index 04e5514..e4cbab2 100644 --- a/operator/src/cli/command.rs +++ b/operator/src/cli/command.rs @@ -1,6 +1,7 @@ //! Contains the command line interface for the application. use clap::{command, Parser}; +use tendermint_light_client_verifier::types::TrustThreshold; /// The command line interface for the operator. #[derive(Clone, Debug, Parser)] @@ -29,12 +30,20 @@ pub mod genesis { /// The arguments for the `genesis` executable. #[derive(Parser, Debug, Clone)] pub struct Args { - /// Trusted block. + /// Trusted block height. [default: latest] #[clap(long)] pub trusted_block: Option, /// Genesis path. #[clap(long, default_value = "../contracts/script")] pub genesis_path: String, + /// Trust level. + #[clap( + long, + default_value = "1/3", + value_parser = super::parse_trust_threshold, + help = "Trust level as a fraction, e.g. '2/3'", + )] + pub trust_level: super::TrustThreshold, } } @@ -89,6 +98,15 @@ pub mod fixtures { /// Fixture path. #[clap(long, short = 'o')] pub output_path: String, + + /// Trust level. + #[clap( + long, + default_value = "1/3", + value_parser = super::parse_trust_threshold, + help = "Trust level as a fraction, e.g. '2/3'", + )] + pub trust_level: super::TrustThreshold, } /// The arguments for the `Membership` fixture executable. @@ -106,6 +124,15 @@ pub mod fixtures { /// Fixture path. #[clap(long, short = 'o')] pub output_path: String, + + /// Trust level. + #[clap( + long, + default_value = "1/3", + value_parser = super::parse_trust_threshold, + help = "Trust level as a fraction, e.g. '2/3'", + )] + pub trust_level: super::TrustThreshold, } /// The arguments for the `UpdateClientAndMembership` fixture executable. @@ -127,5 +154,30 @@ pub mod fixtures { /// Fixture path. #[clap(long, short = 'o')] pub output_path: String, + + /// Trust level. + #[clap( + long, + default_value = "1/3", + value_parser = super::parse_trust_threshold, + help = "Trust level as a fraction, e.g. '2/3'", + )] + pub trust_level: super::TrustThreshold, } } + +fn parse_trust_threshold(input: &str) -> anyhow::Result { + let (num_part, denom_part) = input.split_once('/').ok_or_else(|| { + anyhow::anyhow!("invalid trust threshold fraction: expected format 'numerator/denominator'") + })?; + let numerator = num_part + .trim() + .parse() + .map_err(|_| anyhow::anyhow!("invalid numerator for the fraction"))?; + let denominator = denom_part + .trim() + .parse() + .map_err(|_| anyhow::anyhow!("invalid denominator for the fraction"))?; + TrustThreshold::new(numerator, denominator) + .map_err(|e| anyhow::anyhow!("invalid trust threshold: {}", e)) +} diff --git a/operator/src/helpers/light_block.rs b/operator/src/helpers/light_block.rs index 662ecc5..31895d1 100644 --- a/operator/src/helpers/light_block.rs +++ b/operator/src/helpers/light_block.rs @@ -16,7 +16,7 @@ pub trait LightBlockExt { /// /// # Errors /// Returns an error if the chain identifier or height cannot be parsed. - fn to_sol_client_state(&self) -> anyhow::Result; + fn to_sol_client_state(&self, trust_level: TrustThreshold) -> anyhow::Result; /// Convert the [`LightBlock`] to a new [`ConsensusState`]. #[must_use] fn to_consensus_state(&self) -> ConsensusState; @@ -34,15 +34,12 @@ pub trait LightBlockExt { } impl LightBlockExt for LightBlock { - fn to_sol_client_state(&self) -> anyhow::Result { + fn to_sol_client_state(&self, trust_level: TrustThreshold) -> anyhow::Result { let chain_id = ChainId::from_str(self.signed_header.header.chain_id.as_str())?; let two_weeks_in_seconds = 14 * 24 * 60 * 60; Ok(ClientState { chain_id: chain_id.to_string(), - trust_level: TrustThreshold { - numerator: 1, - denominator: 3, - }, + trust_level, latest_height: Height { revision_number: chain_id.revision_number().try_into()?, revision_height: self.height().value().try_into()?, diff --git a/operator/src/runners/fixtures/membership.rs b/operator/src/runners/fixtures/membership.rs index 0726b67..21e5e0e 100644 --- a/operator/src/runners/fixtures/membership.rs +++ b/operator/src/runners/fixtures/membership.rs @@ -58,7 +58,8 @@ pub async fn run(args: MembershipCmd) -> anyhow::Result<()> { .get_light_block(Some(args.trusted_block)) .await?; - let trusted_client_state = trusted_light_block.to_sol_client_state()?; + let trusted_client_state = + trusted_light_block.to_sol_client_state(args.trust_level.try_into()?)?; let trusted_consensus_state = trusted_light_block.to_consensus_state(); let commitment_root_bytes = trusted_consensus_state.root.as_bytes().to_vec(); diff --git a/operator/src/runners/fixtures/uc_and_mem.rs b/operator/src/runners/fixtures/uc_and_mem.rs index a390d48..67b07aa 100644 --- a/operator/src/runners/fixtures/uc_and_mem.rs +++ b/operator/src/runners/fixtures/uc_and_mem.rs @@ -62,7 +62,8 @@ pub async fn run(args: UpdateClientAndMembershipCmd) -> anyhow::Result<()> { .get_light_block(Some(args.target_block)) .await?; - let trusted_client_state = trusted_light_block.to_sol_client_state()?; + let trusted_client_state = + trusted_light_block.to_sol_client_state(args.trust_level.try_into()?)?; let trusted_consensus_state = trusted_light_block.to_consensus_state().into(); let proposed_header = target_light_block.into_header(&trusted_light_block); let contract_env = Env { diff --git a/operator/src/runners/fixtures/update_client.rs b/operator/src/runners/fixtures/update_client.rs index f64c432..f3fa977 100644 --- a/operator/src/runners/fixtures/update_client.rs +++ b/operator/src/runners/fixtures/update_client.rs @@ -58,7 +58,8 @@ pub async fn run(args: UpdateClientCmd) -> anyhow::Result<()> { .get_light_block(Some(args.target_block)) .await?; - let trusted_client_state = trusted_light_block.to_sol_client_state()?; + let trusted_client_state = + trusted_light_block.to_sol_client_state(args.trust_level.try_into()?)?; let trusted_consensus_state = trusted_light_block.to_consensus_state().into(); let proposed_header = target_light_block.into_header(&trusted_light_block); let contract_env = Env { diff --git a/operator/src/runners/genesis.rs b/operator/src/runners/genesis.rs index 5391a6a..64ccb85 100644 --- a/operator/src/runners/genesis.rs +++ b/operator/src/runners/genesis.rs @@ -50,7 +50,8 @@ pub async fn run(args: Args) -> anyhow::Result<()> { ); } - let trusted_client_state = trusted_light_block.to_sol_client_state()?; + let trusted_client_state = + trusted_light_block.to_sol_client_state(args.trust_level.try_into()?)?; let trusted_consensus_state = trusted_light_block.to_consensus_state(); let genesis = SP1ICS07TendermintGenesis { trusted_consensus_state: hex::encode( diff --git a/packages/solidity/src/lib.rs b/packages/solidity/src/lib.rs index c50b387..d9fe1cd 100644 --- a/packages/solidity/src/lib.rs +++ b/packages/solidity/src/lib.rs @@ -40,6 +40,17 @@ impl From for TendermintTrustThreshold { } } +impl TryFrom for sp1_ics07_tendermint::TrustThreshold { + type Error = >::Error; + + fn try_from(trust_threshold: TendermintTrustThreshold) -> Result { + Ok(Self { + numerator: trust_threshold.numerator().try_into()?, + denominator: trust_threshold.denominator().try_into()?, + }) + } +} + #[allow(clippy::fallible_impl_from)] impl From for sp1_ics07_tendermint::ConsensusState { fn from(ics07_tendermint_consensus_state: ICS07TendermintConsensusState) -> Self {