@@ -5,8 +5,10 @@ use core::time::Duration;
5
5
6
6
use ibc_proto:: google:: protobuf:: Any ;
7
7
use ibc_proto:: ibc:: core:: client:: v1:: Height as RawHeight ;
8
- use ibc_proto:: ibc:: core:: commitment:: v1:: MerkleProof as RawMerkleProof ;
9
- use ibc_proto:: ibc:: lightclients:: tendermint:: v1:: ClientState as RawTmClientState ;
8
+ use ibc_proto:: ibc:: core:: commitment:: v1:: { MerklePath , MerkleProof as RawMerkleProof } ;
9
+ use ibc_proto:: ibc:: lightclients:: tendermint:: v1:: {
10
+ ClientState as RawTmClientState , ConsensusState as RawTmConsensusState ,
11
+ } ;
10
12
use ibc_proto:: protobuf:: Protobuf ;
11
13
use prost:: Message ;
12
14
use tendermint:: chain:: id:: MAX_LENGTH as MaxChainIdLen ;
@@ -15,13 +17,12 @@ use tendermint_light_client_verifier::options::Options;
15
17
use tendermint_light_client_verifier:: types:: { TrustedBlockState , UntrustedBlockState } ;
16
18
use tendermint_light_client_verifier:: { ProdVerifier , Verifier } ;
17
19
20
+ use crate :: clients:: ics07_tendermint:: client_state:: ClientState as TmClientState ;
18
21
use crate :: clients:: ics07_tendermint:: consensus_state:: ConsensusState as TmConsensusState ;
19
22
use crate :: clients:: ics07_tendermint:: error:: { Error , IntoResult } ;
20
23
use crate :: clients:: ics07_tendermint:: header:: { Header as TmHeader , Header } ;
21
24
use crate :: clients:: ics07_tendermint:: misbehaviour:: Misbehaviour as TmMisbehaviour ;
22
- use crate :: core:: ics02_client:: client_state:: {
23
- ClientState as Ics2ClientState , UpdatedState , UpgradeOptions as CoreUpgradeOptions ,
24
- } ;
25
+ use crate :: core:: ics02_client:: client_state:: { ClientState as Ics2ClientState , UpdatedState } ;
25
26
use crate :: core:: ics02_client:: client_type:: ClientType ;
26
27
use crate :: core:: ics02_client:: consensus_state:: ConsensusState ;
27
28
use crate :: core:: ics02_client:: context:: ClientReader ;
@@ -38,8 +39,8 @@ use crate::core::ics23_commitment::merkle::{apply_prefix, MerkleProof};
38
39
use crate :: core:: ics23_commitment:: specs:: ProofSpecs ;
39
40
use crate :: core:: ics24_host:: identifier:: { ChainId , ChannelId , ClientId , ConnectionId , PortId } ;
40
41
use crate :: core:: ics24_host:: path:: {
41
- AcksPath , ChannelEndsPath , ClientConsensusStatePath , ClientStatePath , CommitmentsPath ,
42
- ConnectionsPath , ReceiptsPath , SeqRecvsPath ,
42
+ AcksPath , ChannelEndsPath , ClientConsensusStatePath , ClientStatePath , ClientUpgradePath ,
43
+ CommitmentsPath , ConnectionsPath , ReceiptsPath , SeqRecvsPath ,
43
44
} ;
44
45
use crate :: core:: ics24_host:: Path ;
45
46
use crate :: timestamp:: { Timestamp , ZERO_DURATION } ;
@@ -351,14 +352,6 @@ impl ClientState {
351
352
}
352
353
}
353
354
354
- #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
355
- #[ derive( Clone , Debug , PartialEq , Eq ) ]
356
- pub struct UpgradeOptions {
357
- pub unbonding_period : Duration ,
358
- }
359
-
360
- impl CoreUpgradeOptions for UpgradeOptions { }
361
-
362
355
impl Ics2ClientState for ClientState {
363
356
fn chain_id ( & self ) -> ChainId {
364
357
self . chain_id . clone ( )
@@ -376,29 +369,14 @@ impl Ics2ClientState for ClientState {
376
369
self . frozen_height
377
370
}
378
371
379
- fn upgrade (
380
- & mut self ,
381
- upgrade_height : Height ,
382
- upgrade_options : & dyn CoreUpgradeOptions ,
383
- chain_id : ChainId ,
384
- ) {
385
- let upgrade_options = upgrade_options
386
- . as_any ( )
387
- . downcast_ref :: < UpgradeOptions > ( )
388
- . expect ( "UpgradeOptions not of type Tendermint" ) ;
389
-
372
+ fn zero_custom_fields ( & mut self ) {
390
373
// Reset custom fields to zero values
391
374
self . trusting_period = ZERO_DURATION ;
392
375
self . trust_level = TrustThreshold :: ZERO ;
393
376
self . allow_update . after_expiry = false ;
394
377
self . allow_update . after_misbehaviour = false ;
395
378
self . frozen_height = None ;
396
379
self . max_clock_drift = ZERO_DURATION ;
397
-
398
- // Upgrade the client state
399
- self . latest_height = upgrade_height;
400
- self . unbonding_period = upgrade_options. unbonding_period ;
401
- self . chain_id = chain_id;
402
380
}
403
381
404
382
fn expired ( & self , elapsed : Duration ) -> bool {
@@ -876,13 +854,154 @@ impl Ics2ClientState for ClientState {
876
854
} )
877
855
}
878
856
879
- fn verify_upgrade_and_update_state (
857
+ /// Perform client-specific verifications and check all data in the new
858
+ /// client state to be the same across all valid Tendermint clients for the
859
+ /// new chain.
860
+ ///
861
+ /// You can learn more about how to upgrade IBC-connected SDK chains in
862
+ /// [this](https://ibc.cosmos.network/main/ibc/upgrades/quick-guide.html)
863
+ /// guide
864
+ fn verify_upgrade_client (
865
+ & self ,
866
+ upgraded_client_state : Any ,
867
+ upgraded_consensus_state : Any ,
868
+ proof_upgrade_client : RawMerkleProof ,
869
+ proof_upgrade_consensus_state : RawMerkleProof ,
870
+ root : & CommitmentRoot ,
871
+ ) -> Result < ( ) , ClientError > {
872
+ // Make sure that the client type is of Tendermint type `ClientState`
873
+ let mut upgraded_tm_client_state = TmClientState :: try_from ( upgraded_client_state) ?;
874
+
875
+ // Make sure that the consensus type is of Tendermint type `ConsensusState`
876
+ let upgraded_tm_cons_state = TmConsensusState :: try_from ( upgraded_consensus_state) ?;
877
+
878
+ // Note: verification of proofs that unmarshalled correctly has been done
879
+ // while decoding the proto message into a `MsgEnvelope` domain type
880
+ let merkle_proof_upgrade_client = MerkleProof :: from ( proof_upgrade_client) ;
881
+ let merkle_proof_upgrade_cons_state = MerkleProof :: from ( proof_upgrade_consensus_state) ;
882
+
883
+ // Make sure the latest height of the current client is not greater then
884
+ // the upgrade height This condition checks both the revision number and
885
+ // the height
886
+ if self . latest_height ( ) >= upgraded_tm_client_state. latest_height ( ) {
887
+ return Err ( ClientError :: LowUpgradeHeight {
888
+ upgraded_height : self . latest_height ( ) ,
889
+ client_height : upgraded_tm_client_state. latest_height ( ) ,
890
+ } ) ;
891
+ }
892
+
893
+ // Check to see if the upgrade path is set
894
+ let mut upgrade_path = self . upgrade_path . clone ( ) ;
895
+ if upgrade_path. pop ( ) . is_none ( ) {
896
+ return Err ( ClientError :: ClientSpecific {
897
+ description : "cannot upgrade client as no upgrade path has been set" . to_string ( ) ,
898
+ } ) ;
899
+ } ;
900
+
901
+ let last_height = self . latest_height ( ) . revision_height ( ) ;
902
+
903
+ // Construct the merkle path for the client state
904
+ let mut client_upgrade_path = upgrade_path. clone ( ) ;
905
+ client_upgrade_path. push ( ClientUpgradePath :: UpgradedClientState ( last_height) . to_string ( ) ) ;
906
+
907
+ let client_upgrade_merkle_path = MerklePath {
908
+ key_path : client_upgrade_path,
909
+ } ;
910
+
911
+ upgraded_tm_client_state. zero_custom_fields ( ) ;
912
+ let client_state_value =
913
+ Protobuf :: < RawTmClientState > :: encode_vec ( & upgraded_tm_client_state)
914
+ . map_err ( ClientError :: Encode ) ?;
915
+
916
+ // Verify the proof of the upgraded client state
917
+ merkle_proof_upgrade_client
918
+ . verify_membership (
919
+ & self . proof_specs ,
920
+ root. clone ( ) . into ( ) ,
921
+ client_upgrade_merkle_path,
922
+ client_state_value,
923
+ 0 ,
924
+ )
925
+ . map_err ( ClientError :: Ics23Verification ) ?;
926
+
927
+ // Construct the merkle path for the consensus state
928
+ let mut cons_upgrade_path = upgrade_path;
929
+ cons_upgrade_path
930
+ . push ( ClientUpgradePath :: UpgradedClientConsensusState ( last_height) . to_string ( ) ) ;
931
+ let cons_upgrade_merkle_path = MerklePath {
932
+ key_path : cons_upgrade_path,
933
+ } ;
934
+
935
+ let cons_state_value = Protobuf :: < RawTmConsensusState > :: encode_vec ( & upgraded_tm_cons_state)
936
+ . map_err ( ClientError :: Encode ) ?;
937
+
938
+ // Verify the proof of the upgraded consensus state
939
+ merkle_proof_upgrade_cons_state
940
+ . verify_membership (
941
+ & self . proof_specs ,
942
+ root. clone ( ) . into ( ) ,
943
+ cons_upgrade_merkle_path,
944
+ cons_state_value,
945
+ 0 ,
946
+ )
947
+ . map_err ( ClientError :: Ics23Verification ) ?;
948
+
949
+ Ok ( ( ) )
950
+ }
951
+
952
+ // Commit the new client state and consensus state to the store
953
+ fn update_state_with_upgrade_client (
880
954
& self ,
881
- _consensus_state : Any ,
882
- _proof_upgrade_client : RawMerkleProof ,
883
- _proof_upgrade_consensus_state : RawMerkleProof ,
955
+ upgraded_client_state : Any ,
956
+ upgraded_consensus_state : Any ,
884
957
) -> Result < UpdatedState , ClientError > {
885
- unimplemented ! ( )
958
+ let upgraded_tm_client_state = TmClientState :: try_from ( upgraded_client_state) ?;
959
+ let upgraded_tm_cons_state = TmConsensusState :: try_from ( upgraded_consensus_state) ?;
960
+
961
+ // Frozen height is set to None fo the new client state
962
+ let new_frozen_height = None ;
963
+
964
+ // Construct new client state and consensus state relayer chosen client
965
+ // parameters are ignored. All chain-chosen parameters come from
966
+ // committed client, all client-chosen parameters come from current
967
+ // client.
968
+ let new_client_state = TmClientState :: new (
969
+ upgraded_tm_client_state. chain_id ,
970
+ self . trust_level ,
971
+ self . trusting_period ,
972
+ upgraded_tm_client_state. unbonding_period ,
973
+ self . max_clock_drift ,
974
+ upgraded_tm_client_state. latest_height ,
975
+ upgraded_tm_client_state. proof_specs ,
976
+ upgraded_tm_client_state. upgrade_path ,
977
+ self . allow_update ,
978
+ new_frozen_height,
979
+ ) ?;
980
+
981
+ // The new consensus state is merely used as a trusted kernel against
982
+ // which headers on the new chain can be verified. The root is just a
983
+ // stand-in sentinel value as it cannot be known in advance, thus no
984
+ // proof verification will pass. The timestamp and the
985
+ // NextValidatorsHash of the consensus state is the blocktime and
986
+ // NextValidatorsHash of the last block committed by the old chain. This
987
+ // will allow the first block of the new chain to be verified against
988
+ // the last validators of the old chain so long as it is submitted
989
+ // within the TrustingPeriod of this client.
990
+ // NOTE: We do not set processed time for this consensus state since
991
+ // this consensus state should not be used for packet verification as
992
+ // the root is empty. The next consensus state submitted using update
993
+ // will be usable for packet-verification.
994
+ let sentinel_root = "sentinel_root" . as_bytes ( ) . to_vec ( ) ;
995
+ let new_consensus_state = TmConsensusState :: new (
996
+ sentinel_root. into ( ) ,
997
+ upgraded_tm_cons_state. timestamp ,
998
+ upgraded_tm_cons_state. next_validators_hash ,
999
+ ) ;
1000
+
1001
+ Ok ( UpdatedState {
1002
+ client_state : new_client_state. into_box ( ) ,
1003
+ consensus_state : new_consensus_state. into_box ( ) ,
1004
+ } )
886
1005
}
887
1006
888
1007
fn verify_client_consensus_state (
0 commit comments