Skip to content

Commit 71204f3

Browse files
authored
feat: dedupe sealevel transaction hashes (#7555)
1 parent 9a5dd7a commit 71204f3

3 files changed

Lines changed: 148 additions & 2 deletions

File tree

rust/main/hyperlane-core/src/rpc_clients/fallback.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ where
183183
info!(
184184
provider_index=%priority.index,
185185
provider=?self.inner.providers[priority.index],
186+
reason="Block height low",
186187
"Deprioritizing an inner provider in FallbackProvider",
187188
);
188189
} else {
@@ -201,6 +202,7 @@ where
201202
info!(
202203
provider_index=%new_priority.index,
203204
provider=?self.inner.providers[new_priority.index],
205+
reason="Too many errors",
204206
"Deprioritizing an inner provider in FallbackProvider",
205207
);
206208
}

rust/main/lander/src/adapter/chains/sealevel/transaction/update.rs

Lines changed: 139 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashSet;
2+
13
use hyperlane_core::H512;
24

35
use crate::{
@@ -11,11 +13,147 @@ pub trait Update {
1113

1214
impl Update for Transaction {
1315
fn update_after_submission(&mut self, hash: H512, precursor: SealevelTxPrecursor) -> &mut Self {
14-
self.tx_hashes.push(hash);
16+
// only push hash if it doesn't exist in tx_hashes
17+
if !self.tx_hashes.contains(&hash) {
18+
self.tx_hashes.push(hash);
19+
}
1520

1621
// Data is updated since transaction is re-estimated before submission
1722
self.vm_specific_data = VmSpecificTxData::Svm(Box::new(precursor));
1823

1924
self
2025
}
2126
}
27+
28+
#[cfg(test)]
29+
mod tests {
30+
use super::*;
31+
use crate::{
32+
adapter::chains::sealevel::SealevelTxPrecursor,
33+
payload::PayloadDetails,
34+
transaction::{Transaction, VmSpecificTxData},
35+
};
36+
use hyperlane_core::{H256, H512};
37+
use hyperlane_sealevel::SealevelTxCostEstimate;
38+
use solana_sdk::{instruction::Instruction as SealevelInstruction, pubkey::Pubkey};
39+
40+
fn create_test_precursor() -> SealevelTxPrecursor {
41+
let instruction = SealevelInstruction::new_with_bytes(Pubkey::new_unique(), &[], vec![]);
42+
let estimate = SealevelTxCostEstimate {
43+
compute_units: 200_000,
44+
compute_unit_price_micro_lamports: 1000,
45+
};
46+
SealevelTxPrecursor {
47+
instruction,
48+
estimate,
49+
}
50+
}
51+
52+
fn create_test_transaction() -> Transaction {
53+
let precursor = create_test_precursor();
54+
let payload_details = vec![PayloadDetails {
55+
uuid: hyperlane_core::identifiers::UniqueIdentifier::random(),
56+
metadata: "test-payload".to_string(),
57+
success_criteria: None,
58+
}];
59+
Transaction::new(precursor, payload_details)
60+
}
61+
62+
#[test]
63+
fn test_update_after_submission_adds_hash() {
64+
let mut tx = create_test_transaction();
65+
assert_eq!(tx.tx_hashes.len(), 0);
66+
67+
let hash1 = H512::random();
68+
let precursor = create_test_precursor();
69+
tx.update_after_submission(hash1, precursor);
70+
71+
assert_eq!(tx.tx_hashes.len(), 1);
72+
assert_eq!(tx.tx_hashes[0], hash1);
73+
}
74+
75+
#[test]
76+
fn test_update_after_submission_deduplicates_hashes() {
77+
let mut tx = create_test_transaction();
78+
79+
let hash1 = H512::random();
80+
let hash2 = H512::random();
81+
82+
// Add first hash
83+
let precursor1 = create_test_precursor();
84+
tx.update_after_submission(hash1, precursor1);
85+
assert_eq!(tx.tx_hashes.len(), 1);
86+
87+
// Add second hash
88+
let precursor2 = create_test_precursor();
89+
tx.update_after_submission(hash2, precursor2);
90+
assert_eq!(tx.tx_hashes.len(), 2);
91+
92+
// Add duplicate of first hash - should deduplicate
93+
let precursor3 = create_test_precursor();
94+
tx.update_after_submission(hash1, precursor3);
95+
96+
// Should still have 2 unique hashes, not 3
97+
assert_eq!(tx.tx_hashes.len(), 2);
98+
assert!(tx.tx_hashes.contains(&hash1));
99+
assert!(tx.tx_hashes.contains(&hash2));
100+
}
101+
102+
#[test]
103+
fn test_update_after_submission_deduplicates_multiple_duplicates() {
104+
let mut tx = create_test_transaction();
105+
106+
let hash1 = H512::random();
107+
let hash2 = H512::random();
108+
let hash3 = H512::random();
109+
110+
// Add multiple hashes
111+
tx.update_after_submission(hash1, create_test_precursor());
112+
tx.update_after_submission(hash2, create_test_precursor());
113+
tx.update_after_submission(hash3, create_test_precursor());
114+
assert_eq!(tx.tx_hashes.len(), 3);
115+
116+
// Add duplicates
117+
tx.update_after_submission(hash1, create_test_precursor());
118+
tx.update_after_submission(hash2, create_test_precursor());
119+
tx.update_after_submission(hash1, create_test_precursor());
120+
121+
// Should still have 3 unique hashes
122+
assert_eq!(tx.tx_hashes.len(), 3);
123+
assert!(tx.tx_hashes.contains(&hash1));
124+
assert!(tx.tx_hashes.contains(&hash2));
125+
assert!(tx.tx_hashes.contains(&hash3));
126+
}
127+
128+
#[test]
129+
fn test_update_after_submission_updates_vm_specific_data() {
130+
let mut tx = create_test_transaction();
131+
let _original_precursor = match &tx.vm_specific_data {
132+
VmSpecificTxData::Svm(p) => p.clone(),
133+
_ => panic!("Expected Svm variant"),
134+
};
135+
136+
let hash = H512::random();
137+
let new_precursor = SealevelTxPrecursor {
138+
instruction: SealevelInstruction::new_with_bytes(
139+
Pubkey::new_unique(),
140+
&[1, 2, 3],
141+
vec![],
142+
),
143+
estimate: SealevelTxCostEstimate {
144+
compute_units: 300_000,
145+
compute_unit_price_micro_lamports: 2000,
146+
},
147+
};
148+
149+
tx.update_after_submission(hash, new_precursor.clone());
150+
151+
match &tx.vm_specific_data {
152+
VmSpecificTxData::Svm(p) => {
153+
assert_eq!(p.estimate.compute_units, 300_000);
154+
assert_eq!(p.estimate.compute_unit_price_micro_lamports, 2000);
155+
}
156+
_ => panic!("Expected Svm variant"),
157+
}
158+
}
159+
}

rust/main/lander/src/tests/svm/tests_inclusion_stage.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,17 @@ async fn test_svm_inclusion_gas_spike() {
167167
status: TransactionStatus::Mempool,
168168
retries: 3,
169169
},
170+
ExpectedSvmTxState {
171+
compute_units: 1400000,
172+
compute_unit_price_micro_lamports: 605,
173+
status: TransactionStatus::Mempool,
174+
retries: 4,
175+
},
170176
ExpectedSvmTxState {
171177
compute_units: 1400000,
172178
compute_unit_price_micro_lamports: 605,
173179
status: TransactionStatus::Finalized,
174-
retries: 3,
180+
retries: 4,
175181
},
176182
];
177183

0 commit comments

Comments
 (0)