1
- use crate :: commitment:: { calculate_ibc_commitment_storage_key , decode_eip1184_rlp_proof} ;
1
+ use crate :: commitment:: { calculate_ibc_commitment_storage_location , decode_eip1184_rlp_proof} ;
2
2
use crate :: consensus_state:: { ConsensusState , TrustedConsensusState } ;
3
3
use crate :: errors:: Error ;
4
4
use crate :: header:: Header ;
@@ -22,6 +22,7 @@ use ibc::core::ics02_client::client_state::{ClientState as Ics2ClientState, Upda
22
22
use ibc:: core:: ics02_client:: client_type:: ClientType ;
23
23
use ibc:: core:: ics02_client:: consensus_state:: ConsensusState as Ics02ConsensusState ;
24
24
use ibc:: core:: ics02_client:: error:: ClientError ;
25
+ use ibc:: core:: ics03_connection:: connection:: ConnectionEnd ;
25
26
use ibc:: core:: ics24_host:: identifier:: { ChainId , ClientId } ;
26
27
use ibc:: core:: ics24_host:: path:: ClientConsensusStatePath ;
27
28
use ibc:: core:: ics24_host:: Path ;
@@ -43,29 +44,42 @@ pub const ETHEREUM_ACCOUNT_STORAGE_ROOT_INDEX: usize = 2;
43
44
44
45
#[ derive( Clone , Debug , Default , PartialEq , Eq , Serialize , Deserialize ) ]
45
46
pub struct ClientState < const SYNC_COMMITTEE_SIZE : usize > {
46
- /// Chain parameters
47
+ // Verification parameters
48
+ /// `genesis_validators_root` of the target beacon chain's BeaconState
47
49
pub genesis_validators_root : Root ,
50
+ /// https://github.com/ethereum/consensus-specs/blob/a09d0c321550c5411557674a981e2b444a1178c0/specs/altair/light-client/sync-protocol.md#misc
48
51
pub min_sync_committee_participants : U64 ,
52
+ /// `genesis_time` of the target beacon chain's BeaconState
49
53
pub genesis_time : U64 ,
54
+ /// fork parameters of the target beacon chain
50
55
pub fork_parameters : ForkParameters ,
56
+ /// https://github.com/ethereum/consensus-specs/blob/a09d0c321550c5411557674a981e2b444a1178c0/configs/mainnet.yaml#L69
51
57
pub seconds_per_slot : U64 ,
58
+ /// https://github.com/ethereum/consensus-specs/blob/a09d0c321550c5411557674a981e2b444a1178c0/presets/mainnet/phase0.yaml#L36
52
59
pub slots_per_epoch : Slot ,
60
+ /// https://github.com/ethereum/consensus-specs/blob/a09d0c321550c5411557674a981e2b444a1178c0/presets/mainnet/altair.yaml#L18
53
61
pub epochs_per_sync_committee_period : Epoch ,
54
62
55
- /// IBC Solidity parameters
63
+ /// An address of IBC contract on execution layer
56
64
pub ibc_address : Address ,
65
+ /// The IBC contract's base storage location for storing commitments
66
+ /// https://github.com/hyperledger-labs/yui-ibc-solidity/blob/0e83dc7aadf71380dae6e346492e148685510663/docs/architecture.md#L46
57
67
pub ibc_commitments_slot : H256 ,
58
68
59
- /// Light Client parameters
69
+ /// `trust_level` is threshold of sync committee participants to consider the attestation as valid. Highly recommended to be 2/3.
60
70
pub trust_level : Fraction ,
71
+ /// `trusting_period` is the period in which the consensus state is considered trusted
61
72
pub trusting_period : Duration ,
73
+ /// `max_clock_drift` defines how much new finalized header's time can drift into the future
62
74
pub max_clock_drift : Duration ,
63
75
64
- /// State
76
+ // State
77
+ /// The latest block number of the stored consensus state
65
78
pub latest_execution_block_number : U64 ,
79
+ /// `frozen_height` is the height at which the client is considered frozen. If `None`, the client is unfrozen.
66
80
pub frozen_height : Option < Height > ,
67
81
68
- /// Verifier
82
+ // Verifiers
69
83
#[ serde( skip) ]
70
84
pub consensus_verifier :
71
85
SyncProtocolVerifier < SYNC_COMMITTEE_SIZE , TrustedConsensusState < SYNC_COMMITTEE_SIZE > > ,
@@ -188,7 +202,8 @@ impl<const SYNC_COMMITTEE_SIZE: usize> ClientState<SYNC_COMMITTEE_SIZE> {
188
202
) ,
189
203
} ) ;
190
204
}
191
- let key = calculate_ibc_commitment_storage_key ( & self . ibc_commitments_slot , path. clone ( ) ) ;
205
+ let key =
206
+ calculate_ibc_commitment_storage_location ( & self . ibc_commitments_slot , path. clone ( ) ) ;
192
207
self . execution_verifier
193
208
. verify_membership (
194
209
root,
@@ -226,7 +241,8 @@ impl<const SYNC_COMMITTEE_SIZE: usize> ClientState<SYNC_COMMITTEE_SIZE> {
226
241
) ,
227
242
} ) ;
228
243
}
229
- let key = calculate_ibc_commitment_storage_key ( & self . ibc_commitments_slot , path. clone ( ) ) ;
244
+ let key =
245
+ calculate_ibc_commitment_storage_location ( & self . ibc_commitments_slot , path. clone ( ) ) ;
230
246
self . execution_verifier
231
247
. verify_non_membership ( root, key. as_bytes ( ) , proof. clone ( ) )
232
248
. map_err ( |e| ClientError :: ClientSpecific {
@@ -424,6 +440,12 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
424
440
}
425
441
let misbehaviour = Misbehaviour :: < SYNC_COMMITTEE_SIZE > :: try_from ( misbehaviour) ?;
426
442
misbehaviour. validate ( ) ?;
443
+ if misbehaviour. client_id != client_id {
444
+ return Err (
445
+ Error :: UnexpectedClientIdInMisbehaviour ( client_id, misbehaviour. client_id ) . into ( ) ,
446
+ ) ;
447
+ }
448
+
427
449
let consensus_state = match maybe_consensus_state (
428
450
ctx,
429
451
& ClientConsensusStatePath :: new ( & client_id, & misbehaviour. trusted_sync_committee . height ) ,
@@ -557,14 +579,15 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
557
579
558
580
fn verify_packet_data (
559
581
& self ,
560
- _ctx : & dyn ibc:: core:: ValidationContext ,
582
+ ctx : & dyn ibc:: core:: ValidationContext ,
561
583
proof_height : ibc:: Height ,
562
584
connection_end : & ibc:: core:: ics03_connection:: connection:: ConnectionEnd ,
563
585
proof : & ibc:: core:: ics23_commitment:: commitment:: CommitmentProofBytes ,
564
586
root : & ibc:: core:: ics23_commitment:: commitment:: CommitmentRoot ,
565
587
commitment_path : & ibc:: core:: ics24_host:: path:: CommitmentPath ,
566
588
commitment : ibc:: core:: ics04_channel:: commitment:: PacketCommitment ,
567
589
) -> Result < ( ) , ClientError > {
590
+ verify_delay_passed ( ctx, proof_height, connection_end) ?;
568
591
self . verify_membership (
569
592
proof_height,
570
593
connection_end. counterparty ( ) . prefix ( ) ,
@@ -577,14 +600,15 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
577
600
578
601
fn verify_packet_acknowledgement (
579
602
& self ,
580
- _ctx : & dyn ibc:: core:: ValidationContext ,
603
+ ctx : & dyn ibc:: core:: ValidationContext ,
581
604
proof_height : ibc:: Height ,
582
605
connection_end : & ibc:: core:: ics03_connection:: connection:: ConnectionEnd ,
583
606
proof : & ibc:: core:: ics23_commitment:: commitment:: CommitmentProofBytes ,
584
607
root : & ibc:: core:: ics23_commitment:: commitment:: CommitmentRoot ,
585
608
ack_path : & ibc:: core:: ics24_host:: path:: AckPath ,
586
609
ack : ibc:: core:: ics04_channel:: commitment:: AcknowledgementCommitment ,
587
610
) -> Result < ( ) , ClientError > {
611
+ verify_delay_passed ( ctx, proof_height, connection_end) ?;
588
612
self . verify_membership (
589
613
proof_height,
590
614
connection_end. counterparty ( ) . prefix ( ) ,
@@ -597,14 +621,15 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
597
621
598
622
fn verify_next_sequence_recv (
599
623
& self ,
600
- _ctx : & dyn ibc:: core:: ValidationContext ,
624
+ ctx : & dyn ibc:: core:: ValidationContext ,
601
625
proof_height : ibc:: Height ,
602
626
connection_end : & ibc:: core:: ics03_connection:: connection:: ConnectionEnd ,
603
627
proof : & ibc:: core:: ics23_commitment:: commitment:: CommitmentProofBytes ,
604
628
root : & ibc:: core:: ics23_commitment:: commitment:: CommitmentRoot ,
605
629
seq_recv_path : & ibc:: core:: ics24_host:: path:: SeqRecvPath ,
606
630
sequence : ibc:: core:: ics04_channel:: packet:: Sequence ,
607
631
) -> Result < ( ) , ClientError > {
632
+ verify_delay_passed ( ctx, proof_height, connection_end) ?;
608
633
let mut seq_bytes = Vec :: new ( ) ;
609
634
u64:: from ( sequence)
610
635
. encode ( & mut seq_bytes)
@@ -622,13 +647,14 @@ impl<const SYNC_COMMITTEE_SIZE: usize> Ics2ClientState for ClientState<SYNC_COMM
622
647
623
648
fn verify_packet_receipt_absence (
624
649
& self ,
625
- _ctx : & dyn ibc:: core:: ValidationContext ,
650
+ ctx : & dyn ibc:: core:: ValidationContext ,
626
651
proof_height : ibc:: Height ,
627
652
connection_end : & ibc:: core:: ics03_connection:: connection:: ConnectionEnd ,
628
653
proof : & ibc:: core:: ics23_commitment:: commitment:: CommitmentProofBytes ,
629
654
root : & ibc:: core:: ics23_commitment:: commitment:: CommitmentRoot ,
630
655
receipt_path : & ibc:: core:: ics24_host:: path:: ReceiptPath ,
631
656
) -> Result < ( ) , ClientError > {
657
+ verify_delay_passed ( ctx, proof_height, connection_end) ?;
632
658
self . verify_non_membership (
633
659
proof_height,
634
660
connection_end. counterparty ( ) . prefix ( ) ,
@@ -937,6 +963,58 @@ fn trim_left_zero(value: &[u8]) -> &[u8] {
937
963
& value[ pos..]
938
964
}
939
965
966
+ // A copy from https://github.com/cosmos/ibc-rs/blob/eea4f0e7a1887f2f1cb18a550d08bb805a08240a/crates/ibc/src/clients/ics07_tendermint/client_state.rs#L1031
967
+ fn verify_delay_passed (
968
+ ctx : & dyn ValidationContext ,
969
+ height : Height ,
970
+ connection_end : & ConnectionEnd ,
971
+ ) -> Result < ( ) , ClientError > {
972
+ let current_timestamp = ctx. host_timestamp ( ) . map_err ( |e| ClientError :: Other {
973
+ description : e. to_string ( ) ,
974
+ } ) ?;
975
+ let current_height = ctx. host_height ( ) . map_err ( |e| ClientError :: Other {
976
+ description : e. to_string ( ) ,
977
+ } ) ?;
978
+
979
+ let client_id = connection_end. client_id ( ) ;
980
+ let processed_time =
981
+ ctx. client_update_time ( client_id, & height)
982
+ . map_err ( |_| Error :: ProcessedTimeNotFound {
983
+ client_id : client_id. clone ( ) ,
984
+ height,
985
+ } ) ?;
986
+ let processed_height = ctx. client_update_height ( client_id, & height) . map_err ( |_| {
987
+ Error :: ProcessedHeightNotFound {
988
+ client_id : client_id. clone ( ) ,
989
+ height,
990
+ }
991
+ } ) ?;
992
+
993
+ let delay_period_time = connection_end. delay_period ( ) ;
994
+ let delay_period_height = ctx. block_delay ( & delay_period_time) ;
995
+
996
+ let earliest_time =
997
+ ( processed_time + delay_period_time) . map_err ( Error :: TimestampOverflowError ) ?;
998
+ if !( current_timestamp == earliest_time || current_timestamp. after ( & earliest_time) ) {
999
+ return Err ( Error :: NotEnoughTimeElapsed {
1000
+ current_timestamp,
1001
+ earliest_time,
1002
+ }
1003
+ . into ( ) ) ;
1004
+ }
1005
+
1006
+ let earliest_height = processed_height. add ( delay_period_height) ;
1007
+ if current_height < earliest_height {
1008
+ return Err ( Error :: NotEnoughBlocksElapsed {
1009
+ current_height,
1010
+ earliest_height,
1011
+ }
1012
+ . into ( ) ) ;
1013
+ }
1014
+
1015
+ Ok ( ( ) )
1016
+ }
1017
+
940
1018
#[ cfg( test) ]
941
1019
mod tests {
942
1020
use super :: * ;
0 commit comments