@layerzerolabs/protocol-stellar-v2 0.2.34 → 0.2.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +250 -251
- package/.turbo/turbo-lint.log +226 -231
- package/.turbo/turbo-test.log +1994 -1731
- package/Cargo.lock +10 -10
- package/Cargo.toml +1 -1
- package/contracts/common-macros/src/storage.rs +7 -5
- package/contracts/common-macros/src/tests/storage/snapshots/common_macros__tests__storage__generate_storage__snapshot_generated_storage_code.snap +3 -3
- package/contracts/endpoint-v2/src/endpoint_v2.rs +5 -4
- package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +7 -8
- package/contracts/endpoint-v2/src/messaging_channel.rs +78 -45
- package/contracts/endpoint-v2/src/storage.rs +8 -3
- package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +2 -2
- package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -15
- package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +46 -9
- package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +7 -23
- package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +23 -20
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +94 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +17 -15
- package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +48 -13
- package/contracts/endpoint-v2/src/tests/messaging_channel/pending_inbound_nonces.rs +111 -0
- package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +15 -25
- package/contracts/layerzero-views/src/layerzero_view.rs +2 -2
- package/contracts/layerzero-views/src/tests/layerzero_view_tests.rs +3 -4
- package/contracts/layerzero-views/src/tests/setup.rs +0 -21
- package/contracts/message-libs/blocked-message-lib/src/lib.rs +4 -4
- package/contracts/message-libs/uln-302/src/send_uln.rs +5 -5
- package/contracts/oapps/counter/src/counter.rs +6 -0
- package/contracts/oapps/oapp/src/oapp_sender.rs +3 -2
- package/contracts/oapps/oft/src/extensions/oft_fee.rs +5 -0
- package/contracts/oapps/oft/src/oft.rs +5 -4
- package/docs/layerzero-v2-on-stellar.md +46 -2
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +312 -316
- package/sdk/dist/generated/bml.d.ts +3 -3
- package/sdk/dist/generated/bml.js +3 -3
- package/sdk/dist/generated/counter.d.ts +32 -3
- package/sdk/dist/generated/counter.js +6 -3
- package/sdk/dist/generated/dvn.d.ts +3 -3
- package/sdk/dist/generated/dvn.js +3 -3
- package/sdk/dist/generated/dvn_fee_lib.d.ts +2 -2
- package/sdk/dist/generated/dvn_fee_lib.js +2 -2
- package/sdk/dist/generated/endpoint.d.ts +12 -13
- package/sdk/dist/generated/endpoint.js +7 -7
- package/sdk/dist/generated/executor.d.ts +3 -3
- package/sdk/dist/generated/executor.js +3 -3
- package/sdk/dist/generated/executor_fee_lib.d.ts +2 -2
- package/sdk/dist/generated/executor_fee_lib.js +2 -2
- package/sdk/dist/generated/executor_helper.d.ts +2 -2
- package/sdk/dist/generated/executor_helper.js +2 -2
- package/sdk/dist/generated/layerzero_view.d.ts +3 -3
- package/sdk/dist/generated/layerzero_view.js +3 -3
- package/sdk/dist/generated/oft.d.ts +32 -3
- package/sdk/dist/generated/oft.js +6 -3
- package/sdk/dist/generated/price_feed.d.ts +3 -3
- package/sdk/dist/generated/price_feed.js +3 -3
- package/sdk/dist/generated/sac_manager.d.ts +24 -3
- package/sdk/dist/generated/sac_manager.js +4 -3
- package/sdk/dist/generated/sml.d.ts +2 -2
- package/sdk/dist/generated/sml.js +2 -2
- package/sdk/dist/generated/treasury.d.ts +2 -2
- package/sdk/dist/generated/treasury.js +2 -2
- package/sdk/dist/generated/uln302.d.ts +3 -3
- package/sdk/dist/generated/uln302.js +3 -3
- package/sdk/dist/generated/upgrader.d.ts +2 -2
- package/sdk/dist/generated/upgrader.js +2 -2
- package/sdk/package.json +1 -1
- package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +0 -39
|
@@ -84,9 +84,6 @@ fn test_burn_success_with_stored_payload() {
|
|
|
84
84
|
let nonce = 1u64;
|
|
85
85
|
let payload_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
86
86
|
|
|
87
|
-
// Boundary condition: burn requires nonce <= lazy_nonce.
|
|
88
|
-
context.set_lazy_inbound_nonce(&receiver, src_eid, &sender, nonce);
|
|
89
|
-
|
|
90
87
|
// Store a payload hash first.
|
|
91
88
|
context.inbound_as_verified(&receiver, src_eid, &sender, nonce, &payload_hash);
|
|
92
89
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), Some(payload_hash.clone()));
|
|
@@ -128,9 +125,6 @@ fn test_burn_with_delegate() {
|
|
|
128
125
|
// Set delegate for receiver.
|
|
129
126
|
env.as_contract(&endpoint_client.address, || storage::EndpointStorage::set_delegate(env, &receiver, &delegate));
|
|
130
127
|
|
|
131
|
-
// Burn requires nonce <= lazy_nonce.
|
|
132
|
-
context.set_lazy_inbound_nonce(&receiver, src_eid, &sender, 1);
|
|
133
|
-
|
|
134
128
|
// Store a payload hash first.
|
|
135
129
|
context.inbound_as_verified(&receiver, src_eid, &sender, nonce, &payload_hash);
|
|
136
130
|
|
|
@@ -169,9 +163,6 @@ fn test_burn_multiple_payloads() {
|
|
|
169
163
|
let nonce1 = 1;
|
|
170
164
|
let nonce2 = 2;
|
|
171
165
|
|
|
172
|
-
// Burn requires nonce <= lazy_nonce.
|
|
173
|
-
context.set_lazy_inbound_nonce(&receiver, src_eid, &sender, 2);
|
|
174
|
-
|
|
175
166
|
// Store multiple payload hashes.
|
|
176
167
|
context.inbound_as_verified(&receiver, src_eid, &sender, nonce1, &payload_hash1);
|
|
177
168
|
context.inbound_as_verified(&receiver, src_eid, &sender, nonce2, &payload_hash2);
|
|
@@ -203,12 +194,6 @@ fn test_burn_different_paths() {
|
|
|
203
194
|
let nonce = 1;
|
|
204
195
|
let payload_hash = BytesN::from_array(env, &[0xefu8; 32]);
|
|
205
196
|
|
|
206
|
-
// Burn requires nonce <= lazy_nonce.
|
|
207
|
-
context.set_lazy_inbound_nonce(&receiver1, src_eid1, &sender1, 1);
|
|
208
|
-
context.set_lazy_inbound_nonce(&receiver2, src_eid1, &sender1, 1);
|
|
209
|
-
context.set_lazy_inbound_nonce(&receiver1, src_eid2, &sender1, 1);
|
|
210
|
-
context.set_lazy_inbound_nonce(&receiver1, src_eid1, &sender2, 1);
|
|
211
|
-
|
|
212
197
|
// Store payload hashes for different paths.
|
|
213
198
|
context.inbound_as_verified(&receiver1, src_eid1, &sender1, nonce, &payload_hash);
|
|
214
199
|
context.inbound_as_verified(&receiver2, src_eid1, &sender1, nonce, &payload_hash);
|
|
@@ -247,9 +232,6 @@ fn test_burn_payload_hash_not_found_when_mismatch() {
|
|
|
247
232
|
let payload_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
248
233
|
let wrong_payload_hash = BytesN::from_array(env, &[0x11u8; 32]);
|
|
249
234
|
|
|
250
|
-
// Burn requires nonce <= lazy_nonce.
|
|
251
|
-
context.set_lazy_inbound_nonce(&receiver, src_eid, &sender, nonce);
|
|
252
|
-
|
|
253
235
|
// Store a payload hash first.
|
|
254
236
|
context.inbound_as_verified(&receiver, src_eid, &sender, nonce, &payload_hash);
|
|
255
237
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), Some(payload_hash.clone()));
|
|
@@ -270,8 +252,8 @@ fn test_burn_payload_hash_not_found_when_storage_none() {
|
|
|
270
252
|
let nonce = 1u64;
|
|
271
253
|
let payload_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
272
254
|
|
|
273
|
-
//
|
|
274
|
-
context.
|
|
255
|
+
// Burn must fail without a stored payload hash.
|
|
256
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, nonce);
|
|
275
257
|
let result = try_burn_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce, &payload_hash);
|
|
276
258
|
assert_eq!(result.err().unwrap().ok().unwrap(), EndpointError::PayloadHashNotFound.into());
|
|
277
259
|
}
|
|
@@ -288,9 +270,11 @@ fn test_burn_invalid_nonce_when_greater_than_lazy_nonce() {
|
|
|
288
270
|
let nonce = 2u64;
|
|
289
271
|
let payload_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
290
272
|
|
|
291
|
-
//
|
|
292
|
-
context.
|
|
293
|
-
|
|
273
|
+
// inbound nonce is 1, trying to burn nonce 2 should fail (even if a payload hash exists).
|
|
274
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 1);
|
|
275
|
+
env.as_contract(&context.endpoint_client.address, || {
|
|
276
|
+
storage::EndpointStorage::set_inbound_payload_hash(env, &receiver, src_eid, &sender, nonce, &payload_hash);
|
|
277
|
+
});
|
|
294
278
|
|
|
295
279
|
let result = try_burn_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce, &payload_hash);
|
|
296
280
|
assert_eq!(result.err().unwrap().ok().unwrap(), EndpointError::InvalidNonce.into());
|
|
@@ -36,7 +36,7 @@ fn clear_payload(
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
// Internal clear_payload() removes verified payload and
|
|
39
|
+
// Internal clear_payload() removes verified payload and does not change inbound nonce
|
|
40
40
|
#[test]
|
|
41
41
|
fn test_clear_payload_success() {
|
|
42
42
|
let context = setup();
|
|
@@ -55,11 +55,11 @@ fn test_clear_payload_success() {
|
|
|
55
55
|
clear_payload(&context, &receiver, src_eid, &sender, nonce, &payload);
|
|
56
56
|
|
|
57
57
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), None);
|
|
58
|
-
assert_eq!(endpoint_client.
|
|
58
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), nonce);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
#[test]
|
|
62
|
-
fn
|
|
62
|
+
fn test_clear_payload_keeps_other_payload_hashes_intact() {
|
|
63
63
|
let context = setup();
|
|
64
64
|
let env = &context.env;
|
|
65
65
|
let endpoint_client = &context.endpoint_client;
|
|
@@ -76,21 +76,21 @@ fn test_clear_payload_with_lazy_nonce_update_skipping_intermediate() {
|
|
|
76
76
|
let hash2 = inbound_as_verified_from_payload(&context, &receiver, src_eid, &sender, 2, &payload2);
|
|
77
77
|
let hash3 = inbound_as_verified_from_payload(&context, &receiver, src_eid, &sender, 3, &payload3);
|
|
78
78
|
|
|
79
|
-
assert_eq!(endpoint_client.
|
|
79
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
80
80
|
|
|
81
|
-
// Clearing nonce 3
|
|
81
|
+
// Clearing nonce 3 removes only nonce 3's payload hash.
|
|
82
82
|
clear_payload(&context, &receiver, src_eid, &sender, 3, &payload3);
|
|
83
83
|
|
|
84
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
85
84
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &3), None);
|
|
86
85
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1), Some(hash1));
|
|
87
86
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2), Some(hash2));
|
|
87
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
88
88
|
let _ = hash3; // hash3 is only used to ensure it was computed and stored for nonce 3.
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
// Clearing a nonce <=
|
|
91
|
+
// Clearing a nonce <= inbound nonce does not update inbound nonce
|
|
92
92
|
#[test]
|
|
93
|
-
fn
|
|
93
|
+
fn test_clear_payload_does_not_update_inbound_nonce_when_nonce_is_not_greater() {
|
|
94
94
|
let context = setup();
|
|
95
95
|
let env = &context.env;
|
|
96
96
|
let endpoint_client = &context.endpoint_client;
|
|
@@ -99,22 +99,25 @@ fn test_clear_payload_does_not_update_lazy_nonce_when_nonce_is_not_greater() {
|
|
|
99
99
|
let src_eid = 2;
|
|
100
100
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
101
101
|
|
|
102
|
-
// Pretend we already
|
|
102
|
+
// Pretend we already advanced inbound nonce to 5.
|
|
103
103
|
env.as_contract(&endpoint_client.address, || {
|
|
104
|
-
storage::EndpointStorage::
|
|
104
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &5u64)
|
|
105
105
|
});
|
|
106
|
-
assert_eq!(endpoint_client.
|
|
106
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
107
107
|
|
|
108
108
|
// Store a payload hash at nonce 3, then clear it.
|
|
109
109
|
let nonce = 3u64;
|
|
110
110
|
let payload = Bytes::from_array(env, &[0xaa, 0xbb, 0xcc]);
|
|
111
|
-
let payload_hash =
|
|
112
|
-
|
|
111
|
+
let payload_hash = BytesN::from_array(env, &env.crypto().keccak256(&payload).to_array());
|
|
112
|
+
env.as_contract(&endpoint_client.address, || {
|
|
113
|
+
storage::EndpointStorage::set_inbound_payload_hash(env, &receiver, src_eid, &sender, nonce, &payload_hash)
|
|
114
|
+
});
|
|
115
|
+
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), Some(payload_hash.clone()));
|
|
113
116
|
|
|
114
117
|
clear_payload(&context, &receiver, src_eid, &sender, nonce, &payload);
|
|
115
118
|
|
|
116
|
-
// Clearing an older nonce should not mutate
|
|
117
|
-
assert_eq!(endpoint_client.
|
|
119
|
+
// Clearing an older nonce should not mutate inbound_nonce.
|
|
120
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
118
121
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), None);
|
|
119
122
|
}
|
|
120
123
|
|
|
@@ -132,9 +135,9 @@ fn test_clear_payload_payload_hash_not_found_when_nonce_is_checkpointed_but_miss
|
|
|
132
135
|
// nonce <= lazy_nonce, so clear_payload will NOT run the "has_payload for all intermediate nonces" check.
|
|
133
136
|
// It should fail at the payload hash check instead.
|
|
134
137
|
env.as_contract(&endpoint_client.address, || {
|
|
135
|
-
storage::EndpointStorage::
|
|
138
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &5u64)
|
|
136
139
|
});
|
|
137
|
-
assert_eq!(endpoint_client.
|
|
140
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
138
141
|
|
|
139
142
|
// No payload hash is stored for nonce 3.
|
|
140
143
|
let nonce = 3u64;
|
|
@@ -188,16 +191,16 @@ fn test_clear_payload_missing_intermediate_nonce() {
|
|
|
188
191
|
let src_eid = 2;
|
|
189
192
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
190
193
|
|
|
191
|
-
// Store only nonce 1 and 3, skip nonce 2
|
|
194
|
+
// Store only nonce 1 and 3, skip nonce 2.
|
|
192
195
|
let payload1 = Bytes::from_array(env, &[0x01]);
|
|
193
196
|
let payload3 = Bytes::from_array(env, &[0x03]);
|
|
194
197
|
|
|
195
198
|
let _ = inbound_as_verified_from_payload(&context, &receiver, src_eid, &sender, 1, &payload1);
|
|
196
199
|
let _ = inbound_as_verified_from_payload(&context, &receiver, src_eid, &sender, 3, &payload3);
|
|
197
200
|
|
|
198
|
-
// Clearing nonce 1
|
|
201
|
+
// Clearing nonce 1 succeeds.
|
|
199
202
|
clear_payload(&context, &receiver, src_eid, &sender, 1, &payload1);
|
|
200
203
|
|
|
201
|
-
// Try to clear nonce 3 - should panic because nonce
|
|
204
|
+
// Try to clear nonce 3 - should panic because inbound_nonce is still 1 (nonce 3 is out-of-order).
|
|
202
205
|
clear_payload(&context, &receiver, src_eid, &sender, 3, &payload3);
|
|
203
206
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use soroban_sdk::{testutils::Address as _, Address, BytesN};
|
|
2
2
|
|
|
3
|
-
use crate::{endpoint_v2::EndpointV2, tests::endpoint_setup::setup};
|
|
3
|
+
use crate::{endpoint_v2::EndpointV2, storage, tests::endpoint_setup::setup};
|
|
4
4
|
|
|
5
5
|
// Internal inbound() stores payload hash per nonce and rejects empty payload hash
|
|
6
6
|
#[test]
|
|
@@ -92,3 +92,96 @@ fn test_inbound_rejects_empty_payload_hash() {
|
|
|
92
92
|
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, nonce, &empty_hash)
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
#[test]
|
|
97
|
+
fn test_inbound_out_of_order_populates_pending_and_drains_when_gap_closed() {
|
|
98
|
+
let context = setup();
|
|
99
|
+
let env = &context.env;
|
|
100
|
+
let endpoint_client = &context.endpoint_client;
|
|
101
|
+
|
|
102
|
+
let receiver = Address::generate(env);
|
|
103
|
+
let src_eid = 2;
|
|
104
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
105
|
+
|
|
106
|
+
let hash_2 = BytesN::from_array(env, &[0x22u8; 32]);
|
|
107
|
+
env.as_contract(&endpoint_client.address, || {
|
|
108
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 2, &hash_2)
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
112
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), soroban_sdk::vec![env, 2u64]);
|
|
113
|
+
|
|
114
|
+
let hash_1 = BytesN::from_array(env, &[0x11u8; 32]);
|
|
115
|
+
env.as_contract(&endpoint_client.address, || {
|
|
116
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 1, &hash_1)
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Gap is closed, so pending drains and inbound nonce advances to 2.
|
|
120
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
121
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
122
|
+
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1u64), Some(hash_1));
|
|
123
|
+
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2u64), Some(hash_2));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[test]
|
|
127
|
+
#[should_panic(expected = "Error(Contract, #11)")] // EndpointError::InvalidNonce
|
|
128
|
+
fn test_inbound_rejects_nonce_beyond_pending_window() {
|
|
129
|
+
let context = setup();
|
|
130
|
+
let env = &context.env;
|
|
131
|
+
let endpoint_client = &context.endpoint_client;
|
|
132
|
+
|
|
133
|
+
let receiver = Address::generate(env);
|
|
134
|
+
let src_eid = 2;
|
|
135
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
136
|
+
let hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
137
|
+
|
|
138
|
+
// inbound_nonce is 0, so nonce 257 is out of range (max is 256).
|
|
139
|
+
env.as_contract(&endpoint_client.address, || {
|
|
140
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 257, &hash)
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[test]
|
|
145
|
+
#[should_panic(expected = "Error(Contract, #11)")] // EndpointError::InvalidNonce
|
|
146
|
+
fn test_inbound_rejects_reverify_when_nonce_leq_inbound_and_payload_missing() {
|
|
147
|
+
let context = setup();
|
|
148
|
+
let env = &context.env;
|
|
149
|
+
let endpoint_client = &context.endpoint_client;
|
|
150
|
+
|
|
151
|
+
let receiver = Address::generate(env);
|
|
152
|
+
let src_eid = 2;
|
|
153
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
154
|
+
|
|
155
|
+
// Force inbound_nonce to 1 without storing any payload hashes.
|
|
156
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 1);
|
|
157
|
+
|
|
158
|
+
let hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
159
|
+
env.as_contract(&endpoint_client.address, || {
|
|
160
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 1, &hash)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#[test]
|
|
165
|
+
fn test_inbound_allows_reverify_when_nonce_leq_inbound_and_payload_exists() {
|
|
166
|
+
let context = setup();
|
|
167
|
+
let env = &context.env;
|
|
168
|
+
let endpoint_client = &context.endpoint_client;
|
|
169
|
+
|
|
170
|
+
let receiver = Address::generate(env);
|
|
171
|
+
let src_eid = 2;
|
|
172
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
173
|
+
|
|
174
|
+
let old_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
175
|
+
env.as_contract(&endpoint_client.address, || {
|
|
176
|
+
storage::EndpointStorage::set_inbound_payload_hash(env, &receiver, src_eid, &sender, 1u64, &old_hash);
|
|
177
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &1u64);
|
|
178
|
+
});
|
|
179
|
+
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1u64), Some(old_hash));
|
|
180
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 1);
|
|
181
|
+
|
|
182
|
+
let new_hash = BytesN::from_array(env, &[0xcdu8; 32]);
|
|
183
|
+
env.as_contract(&endpoint_client.address, || {
|
|
184
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 1u64, &new_hash)
|
|
185
|
+
});
|
|
186
|
+
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1u64), Some(new_hash));
|
|
187
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use soroban_sdk::{testutils::Address as _, Address, BytesN};
|
|
1
|
+
use soroban_sdk::{testutils::Address as _, vec, Address, BytesN};
|
|
2
2
|
|
|
3
3
|
use crate::tests::endpoint_setup::{setup, TestSetup};
|
|
4
4
|
|
|
@@ -25,13 +25,13 @@ fn test_inbound_nonce_initially_zero() {
|
|
|
25
25
|
let src_eid = 2;
|
|
26
26
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
27
27
|
|
|
28
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
29
28
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
29
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// Stored inbound nonce is the baseline when there are no pending nonces
|
|
33
33
|
#[test]
|
|
34
|
-
fn
|
|
34
|
+
fn test_inbound_nonce_equals_stored_value_when_no_pending_nonces() {
|
|
35
35
|
let context = setup();
|
|
36
36
|
let env = &context.env;
|
|
37
37
|
let endpoint_client = &context.endpoint_client;
|
|
@@ -40,9 +40,9 @@ fn test_inbound_nonce_equals_lazy_nonce_when_no_payload_hashes() {
|
|
|
40
40
|
let src_eid = 2;
|
|
41
41
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
42
42
|
|
|
43
|
-
context.
|
|
44
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
43
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 5);
|
|
45
44
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
45
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// The inbound_nonce advances through the longest gapless consecutive sequence
|
|
@@ -56,13 +56,14 @@ fn test_inbound_nonce_advances_through_consecutive_verified_payload_hashes() {
|
|
|
56
56
|
let src_eid = 2;
|
|
57
57
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
58
58
|
|
|
59
|
-
// Start from
|
|
60
|
-
context.
|
|
59
|
+
// Start from inbound_nonce = 2 and add payloads at 3,4,5.
|
|
60
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 2);
|
|
61
61
|
inbound_as_verified_with_fixed_hash(&context, &receiver, src_eid, &sender, 3);
|
|
62
62
|
inbound_as_verified_with_fixed_hash(&context, &receiver, src_eid, &sender, 4);
|
|
63
63
|
inbound_as_verified_with_fixed_hash(&context, &receiver, src_eid, &sender, 5);
|
|
64
64
|
|
|
65
65
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 5);
|
|
66
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
#[test]
|
|
@@ -75,12 +76,13 @@ fn test_inbound_nonce_stops_at_first_gap() {
|
|
|
75
76
|
let src_eid = 2;
|
|
76
77
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
77
78
|
|
|
78
|
-
// Start from
|
|
79
|
-
context.
|
|
79
|
+
// Start from inbound_nonce = 2 and add payloads at 3 and 5 (gap at 4).
|
|
80
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 2);
|
|
80
81
|
inbound_as_verified_with_fixed_hash(&context, &receiver, src_eid, &sender, 3);
|
|
81
82
|
inbound_as_verified_with_fixed_hash(&context, &receiver, src_eid, &sender, 5);
|
|
82
83
|
|
|
83
84
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
85
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 5u64]);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
// Path isolation (receiver/src_eid/sender are isolated)
|
|
@@ -97,22 +99,22 @@ fn test_inbound_nonce_isolated_by_path() {
|
|
|
97
99
|
let sender_a = BytesN::from_array(env, &[1u8; 32]);
|
|
98
100
|
let sender_b = BytesN::from_array(env, &[2u8; 32]);
|
|
99
101
|
|
|
100
|
-
// Path A:
|
|
101
|
-
context.
|
|
102
|
+
// Path A: inbound 10 + payload at 11 => inbound_nonce 11.
|
|
103
|
+
context.set_inbound_nonce(&receiver_a, src_eid_a, &sender_a, 10);
|
|
102
104
|
inbound_as_verified_with_fixed_hash(&context, &receiver_a, src_eid_a, &sender_a, 11);
|
|
103
105
|
assert_eq!(endpoint_client.inbound_nonce(&receiver_a, &src_eid_a, &sender_a), 11);
|
|
104
106
|
|
|
105
107
|
// Path B: different receiver => independent.
|
|
106
|
-
context.
|
|
108
|
+
context.set_inbound_nonce(&receiver_b, src_eid_a, &sender_a, 20);
|
|
107
109
|
assert_eq!(endpoint_client.inbound_nonce(&receiver_b, &src_eid_a, &sender_a), 20);
|
|
108
110
|
|
|
109
111
|
// Path C: different src_eid => independent (two consecutive payloads).
|
|
110
|
-
context.
|
|
112
|
+
context.set_inbound_nonce(&receiver_a, src_eid_b, &sender_a, 30);
|
|
111
113
|
inbound_as_verified_with_fixed_hash(&context, &receiver_a, src_eid_b, &sender_a, 31);
|
|
112
114
|
inbound_as_verified_with_fixed_hash(&context, &receiver_a, src_eid_b, &sender_a, 32);
|
|
113
115
|
assert_eq!(endpoint_client.inbound_nonce(&receiver_a, &src_eid_b, &sender_a), 32);
|
|
114
116
|
|
|
115
117
|
// Path D: different sender => independent.
|
|
116
|
-
context.
|
|
118
|
+
context.set_inbound_nonce(&receiver_a, src_eid_a, &sender_b, 40);
|
|
117
119
|
assert_eq!(endpoint_client.inbound_nonce(&receiver_a, &src_eid_a, &sender_b), 40);
|
|
118
120
|
}
|
|
@@ -128,9 +128,9 @@ fn test_nilify_success_with_empty_payload() {
|
|
|
128
128
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
129
129
|
let nonce = 2;
|
|
130
130
|
|
|
131
|
-
// Set
|
|
131
|
+
// Set inbound nonce to 1 so nonce 2 is the next expected nonce.
|
|
132
132
|
env.as_contract(&endpoint_client.address, || {
|
|
133
|
-
storage::EndpointStorage::
|
|
133
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &1)
|
|
134
134
|
});
|
|
135
135
|
|
|
136
136
|
// Nilify with None.
|
|
@@ -147,6 +147,7 @@ fn test_nilify_success_with_empty_payload() {
|
|
|
147
147
|
let nilified_hash = endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce);
|
|
148
148
|
let expected_nil_hash = nil_hash(&context);
|
|
149
149
|
assert_eq!(nilified_hash, Some(expected_nil_hash));
|
|
150
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
// Nilify with None counts as "verified" for inbound_nonce (but does not change lazy nonce)
|
|
@@ -161,17 +162,53 @@ fn test_nilify_with_none_advances_inbound_nonce_without_changing_lazy_nonce() {
|
|
|
161
162
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
162
163
|
|
|
163
164
|
// Initial state.
|
|
164
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
165
165
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
166
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
166
167
|
|
|
167
168
|
// Nilify nonce 1 with None (non-verified nonce).
|
|
168
169
|
nilify_with_auth(&context, &receiver, &receiver, src_eid, &sender, 1, &None);
|
|
169
170
|
|
|
170
171
|
// Nilify writes a payload hash, so inbound_nonce can now advance to 1.
|
|
171
172
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 1);
|
|
173
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
#[test]
|
|
177
|
+
fn test_nilify_closes_gap_and_drains_pending_nonces() {
|
|
178
|
+
let context = setup();
|
|
179
|
+
let env = &context.env;
|
|
180
|
+
let endpoint_client = &context.endpoint_client;
|
|
172
181
|
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
let receiver = Address::generate(env);
|
|
183
|
+
let src_eid = 2;
|
|
184
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
185
|
+
|
|
186
|
+
// Force inbound nonce to 1 and create a gap by verifying nonce 3 first.
|
|
187
|
+
context.set_inbound_nonce(&receiver, src_eid, &sender, 1);
|
|
188
|
+
let payload_hash_3 = BytesN::from_array(env, &[0x33u8; 32]);
|
|
189
|
+
env.as_contract(&endpoint_client.address, || {
|
|
190
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 3u64, &payload_hash_3)
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 1);
|
|
194
|
+
assert_eq!(
|
|
195
|
+
endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender),
|
|
196
|
+
soroban_sdk::vec![env, 3u64]
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
// Nilify nonce 2 with None closes the gap and should drain pending to advance inbound nonce to 3.
|
|
200
|
+
nilify_with_auth(&context, &receiver, &receiver, src_eid, &sender, 2u64, &None);
|
|
201
|
+
|
|
202
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
203
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
204
|
+
assert_eq!(
|
|
205
|
+
endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2u64),
|
|
206
|
+
Some(nil_hash(&context))
|
|
207
|
+
);
|
|
208
|
+
assert_eq!(
|
|
209
|
+
endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &3u64),
|
|
210
|
+
Some(payload_hash_3)
|
|
211
|
+
);
|
|
175
212
|
}
|
|
176
213
|
|
|
177
214
|
// Nilify is allowed when nonce <= lazy nonce if a payload hash exists
|
|
@@ -187,14 +224,12 @@ fn test_nilify_allows_when_nonce_is_checkpointed_if_payload_exists() {
|
|
|
187
224
|
let nonce = 5u64;
|
|
188
225
|
let payload_hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
189
226
|
|
|
190
|
-
//
|
|
227
|
+
// Advance inbound nonce past the target nonce and store a payload hash at nonce 5.
|
|
191
228
|
env.as_contract(&endpoint_client.address, || {
|
|
192
|
-
storage::EndpointStorage::
|
|
229
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &10);
|
|
230
|
+
storage::EndpointStorage::set_inbound_payload_hash(env, &receiver, src_eid, &sender, nonce, &payload_hash);
|
|
193
231
|
});
|
|
194
|
-
assert_eq!(endpoint_client.
|
|
195
|
-
|
|
196
|
-
// Store a verified payload hash at nonce 5.
|
|
197
|
-
context.inbound_as_verified(&receiver, src_eid, &sender, nonce, &payload_hash);
|
|
232
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 10);
|
|
198
233
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &nonce), Some(payload_hash.clone()));
|
|
199
234
|
|
|
200
235
|
// Even though nonce <= lazy_nonce, this should succeed because a payload hash exists.
|
|
@@ -430,9 +465,9 @@ fn test_nilify_invalid_nonce_when_already_checkpointed_without_payload() {
|
|
|
430
465
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
431
466
|
let nonce = 1u64;
|
|
432
467
|
|
|
433
|
-
// Set
|
|
468
|
+
// Set inbound nonce to 1 and ensure there is NO payload for nonce 1.
|
|
434
469
|
env.as_contract(&endpoint_client.address, || {
|
|
435
|
-
storage::EndpointStorage::
|
|
470
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &1)
|
|
436
471
|
});
|
|
437
472
|
|
|
438
473
|
let result = try_nilify_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce, &None);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
use soroban_sdk::{testutils::Address as _, vec, Address, BytesN};
|
|
2
|
+
|
|
3
|
+
use crate::{endpoint_v2::EndpointV2, tests::endpoint_setup::setup};
|
|
4
|
+
|
|
5
|
+
#[test]
|
|
6
|
+
fn test_pending_inbound_nonces_initially_empty() {
|
|
7
|
+
let context = setup();
|
|
8
|
+
let env = &context.env;
|
|
9
|
+
let endpoint_client = &context.endpoint_client;
|
|
10
|
+
|
|
11
|
+
let receiver = Address::generate(env);
|
|
12
|
+
let src_eid = 2u32;
|
|
13
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
14
|
+
|
|
15
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
16
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
#[test]
|
|
20
|
+
fn test_pending_inbound_nonces_sorted_and_no_duplicates() {
|
|
21
|
+
let context = setup();
|
|
22
|
+
let env = &context.env;
|
|
23
|
+
let endpoint_client = &context.endpoint_client;
|
|
24
|
+
|
|
25
|
+
let receiver = Address::generate(env);
|
|
26
|
+
let src_eid = 2u32;
|
|
27
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
28
|
+
|
|
29
|
+
let hash_5 = BytesN::from_array(env, &[0x05u8; 32]);
|
|
30
|
+
env.as_contract(&endpoint_client.address, || {
|
|
31
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 5u64, &hash_5)
|
|
32
|
+
});
|
|
33
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 5u64]);
|
|
34
|
+
|
|
35
|
+
let hash_2 = BytesN::from_array(env, &[0x02u8; 32]);
|
|
36
|
+
env.as_contract(&endpoint_client.address, || {
|
|
37
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 2u64, &hash_2)
|
|
38
|
+
});
|
|
39
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 2u64, 5u64]);
|
|
40
|
+
|
|
41
|
+
let hash_4 = BytesN::from_array(env, &[0x04u8; 32]);
|
|
42
|
+
env.as_contract(&endpoint_client.address, || {
|
|
43
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 4u64, &hash_4)
|
|
44
|
+
});
|
|
45
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 2u64, 4u64, 5u64]);
|
|
46
|
+
|
|
47
|
+
// Re-verify the same nonce should not duplicate it in the pending list.
|
|
48
|
+
let hash_4b = BytesN::from_array(env, &[0x44u8; 32]);
|
|
49
|
+
env.as_contract(&endpoint_client.address, || {
|
|
50
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 4u64, &hash_4b)
|
|
51
|
+
});
|
|
52
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 2u64, 4u64, 5u64]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#[test]
|
|
56
|
+
fn test_pending_inbound_nonces_drains_when_consecutive_sequence_completed() {
|
|
57
|
+
let context = setup();
|
|
58
|
+
let env = &context.env;
|
|
59
|
+
let endpoint_client = &context.endpoint_client;
|
|
60
|
+
|
|
61
|
+
let receiver = Address::generate(env);
|
|
62
|
+
let src_eid = 2u32;
|
|
63
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
64
|
+
|
|
65
|
+
let hash_2 = BytesN::from_array(env, &[0x02u8; 32]);
|
|
66
|
+
let hash_3 = BytesN::from_array(env, &[0x03u8; 32]);
|
|
67
|
+
env.as_contract(&endpoint_client.address, || {
|
|
68
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 2u64, &hash_2);
|
|
69
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 3u64, &hash_3);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 0);
|
|
73
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender), vec![env, 2u64, 3u64]);
|
|
74
|
+
|
|
75
|
+
// Inserting nonce 1 closes the gap, so pending drains and inbound nonce advances to 3.
|
|
76
|
+
let hash_1 = BytesN::from_array(env, &[0x01u8; 32]);
|
|
77
|
+
env.as_contract(&endpoint_client.address, || {
|
|
78
|
+
EndpointV2::inbound_for_test(env, &receiver, src_eid, &sender, 1u64, &hash_1)
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
82
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[test]
|
|
86
|
+
fn test_pending_inbound_nonces_isolated_by_path() {
|
|
87
|
+
let context = setup();
|
|
88
|
+
let env = &context.env;
|
|
89
|
+
let endpoint_client = &context.endpoint_client;
|
|
90
|
+
|
|
91
|
+
let receiver_a = Address::generate(env);
|
|
92
|
+
let receiver_b = Address::generate(env);
|
|
93
|
+
let src_eid_a = 2u32;
|
|
94
|
+
let src_eid_b = 3u32;
|
|
95
|
+
let sender_a = BytesN::from_array(env, &[1u8; 32]);
|
|
96
|
+
let sender_b = BytesN::from_array(env, &[2u8; 32]);
|
|
97
|
+
|
|
98
|
+
let hash = BytesN::from_array(env, &[0xabu8; 32]);
|
|
99
|
+
env.as_contract(&endpoint_client.address, || {
|
|
100
|
+
EndpointV2::inbound_for_test(env, &receiver_a, src_eid_a, &sender_a, 2u64, &hash);
|
|
101
|
+
EndpointV2::inbound_for_test(env, &receiver_b, src_eid_a, &sender_a, 2u64, &hash);
|
|
102
|
+
EndpointV2::inbound_for_test(env, &receiver_a, src_eid_b, &sender_a, 2u64, &hash);
|
|
103
|
+
EndpointV2::inbound_for_test(env, &receiver_a, src_eid_a, &sender_b, 2u64, &hash);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver_a, &src_eid_a, &sender_a), vec![env, 2u64]);
|
|
107
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver_b, &src_eid_a, &sender_a), vec![env, 2u64]);
|
|
108
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver_a, &src_eid_b, &sender_a), vec![env, 2u64]);
|
|
109
|
+
assert_eq!(endpoint_client.pending_inbound_nonces(&receiver_a, &src_eid_a, &sender_b), vec![env, 2u64]);
|
|
110
|
+
}
|
|
111
|
+
|