@layerzerolabs/protocol-stellar-v2 0.2.34 → 0.2.36
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 +281 -276
- package/.turbo/turbo-lint.log +209 -211
- package/.turbo/turbo-test.log +1705 -1701
- package/Cargo.lock +10 -10
- package/Cargo.toml +1 -1
- package/contracts/common-macros/src/auth.rs +5 -5
- package/contracts/common-macros/src/lib.rs +69 -0
- package/contracts/common-macros/src/rbac.rs +90 -0
- package/contracts/common-macros/src/storage.rs +7 -5
- package/contracts/common-macros/src/tests/lz_contract.rs +5 -7
- package/contracts/common-macros/src/tests/mod.rs +1 -0
- package/contracts/common-macros/src/tests/rbac.rs +420 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +4 -4
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +5 -12
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__rbac__snapshot_preserve_function_signature.snap +17 -0
- package/contracts/common-macros/src/tests/storage/parse_name.rs +0 -1
- 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/macro-integration-tests/tests/runtime/lz_contract/wrapper_default.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/multisig/self_auth.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/ownable/initialization.rs +8 -5
- package/contracts/macro-integration-tests/tests/runtime/ownable/ownership_transfer.rs +2 -2
- package/contracts/macro-integration-tests/tests/runtime/rbac/guard_behavior.rs +91 -0
- package/contracts/macro-integration-tests/tests/runtime/rbac/mod.rs +30 -0
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +2 -2
- package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +4 -4
- package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/basic.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.stderr +16 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.stderr +24 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.stderr +24 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/pass/basic.rs +71 -0
- package/contracts/macro-integration-tests/tests/ui_rbac.rs +12 -0
- 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/interfaces/mintable.rs +2 -2
- package/contracts/oapps/oft/src/oft.rs +5 -4
- package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +2 -2
- package/contracts/oapps/oft/src/tests/extensions/pausable.rs +2 -2
- package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +2 -2
- package/contracts/oapps/sac-manager/Cargo.toml +0 -1
- package/contracts/oapps/sac-manager/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/sac-manager/src/interfaces/sac_admin_wrapper.rs +49 -0
- package/contracts/oapps/sac-manager/src/lib.rs +3 -3
- package/contracts/oapps/sac-manager/src/sac_manager.rs +45 -73
- package/contracts/oapps/sac-manager/src/storage.rs +2 -9
- package/contracts/oapps/sac-manager/src/tests/sac_manager/clawback.rs +8 -10
- package/contracts/oapps/sac-manager/src/tests/sac_manager/mint.rs +13 -18
- package/contracts/oapps/sac-manager/src/tests/sac_manager/mod.rs +0 -1
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_admin.rs +22 -12
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_authorized.rs +19 -9
- package/contracts/oapps/sac-manager/src/tests/sac_manager/test_helper.rs +27 -10
- package/contracts/oapps/sac-manager/src/tests/sac_manager/view_functions.rs +0 -15
- package/contracts/oapps/sac-manager/src/tests/test_helper.rs +19 -28
- package/contracts/upgrader/src/lib.rs +5 -2
- package/contracts/utils/src/auth.rs +6 -2
- package/contracts/utils/src/errors.rs +18 -0
- package/contracts/utils/src/lib.rs +1 -0
- package/contracts/utils/src/multisig.rs +5 -1
- package/contracts/utils/src/ownable.rs +1 -1
- package/contracts/utils/src/rbac.rs +428 -0
- package/contracts/utils/src/tests/auth.rs +2 -2
- package/contracts/utils/src/tests/mod.rs +1 -0
- package/contracts/utils/src/tests/multisig.rs +2 -2
- package/contracts/utils/src/tests/ownable.rs +4 -5
- package/contracts/utils/src/tests/rbac.rs +559 -0
- package/contracts/utils/src/tests/ttl_configurable.rs +5 -6
- package/contracts/utils/src/tests/upgradeable.rs +4 -5
- package/contracts/workers/worker/src/worker.rs +1 -1
- package/docs/layerzero-v2-on-stellar.md +46 -2
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +370 -372
- package/sdk/dist/generated/bml.d.ts +53 -3
- package/sdk/dist/generated/bml.js +27 -3
- package/sdk/dist/generated/counter.d.ts +84 -5
- package/sdk/dist/generated/counter.js +31 -4
- package/sdk/dist/generated/dvn.d.ts +55 -5
- package/sdk/dist/generated/dvn.js +28 -4
- package/sdk/dist/generated/dvn_fee_lib.d.ts +55 -5
- package/sdk/dist/generated/dvn_fee_lib.js +28 -4
- package/sdk/dist/generated/endpoint.d.ts +64 -15
- package/sdk/dist/generated/endpoint.js +32 -8
- package/sdk/dist/generated/executor.d.ts +55 -5
- package/sdk/dist/generated/executor.js +28 -4
- package/sdk/dist/generated/executor_fee_lib.d.ts +55 -5
- package/sdk/dist/generated/executor_fee_lib.js +28 -4
- package/sdk/dist/generated/executor_helper.d.ts +53 -3
- package/sdk/dist/generated/executor_helper.js +27 -3
- package/sdk/dist/generated/layerzero_view.d.ts +55 -5
- package/sdk/dist/generated/layerzero_view.js +28 -4
- package/sdk/dist/generated/oft.d.ts +84 -5
- package/sdk/dist/generated/oft.js +31 -4
- package/sdk/dist/generated/price_feed.d.ts +55 -5
- package/sdk/dist/generated/price_feed.js +28 -4
- package/sdk/dist/generated/sac_manager.d.ts +213 -666
- package/sdk/dist/generated/sac_manager.js +57 -238
- package/sdk/dist/generated/sml.d.ts +55 -5
- package/sdk/dist/generated/sml.js +28 -4
- package/sdk/dist/generated/treasury.d.ts +55 -5
- package/sdk/dist/generated/treasury.js +28 -4
- package/sdk/dist/generated/uln302.d.ts +55 -5
- package/sdk/dist/generated/uln302.js +28 -4
- package/sdk/dist/generated/upgrader.d.ts +53 -3
- package/sdk/dist/generated/upgrader.js +27 -3
- package/sdk/package.json +1 -1
- package/sdk/test/oft-sml.test.ts +10 -9
- package/sdk/test/{sac-manager-redistribution.test.ts → sac-manager.test.ts} +49 -25
- package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +0 -39
- package/contracts/oapps/sac-manager/src/errors.rs +0 -14
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_minter.rs +0 -69
|
@@ -7,7 +7,7 @@ use crate::{
|
|
|
7
7
|
util::{compute_guid, keccak256},
|
|
8
8
|
};
|
|
9
9
|
use common_macros::contract_impl;
|
|
10
|
-
use soroban_sdk::{assert_with_error, Address, Bytes, BytesN, Env};
|
|
10
|
+
use soroban_sdk::{assert_with_error, Address, Bytes, BytesN, Env, Vec};
|
|
11
11
|
|
|
12
12
|
/// Represents an empty payload hash (equivalent to bytes32(uint256(0)) in Solidity)
|
|
13
13
|
const EMPTY_PAYLOAD_HASH_BYTES: [u8; 32] = [0u8; 32];
|
|
@@ -15,6 +15,9 @@ const EMPTY_PAYLOAD_HASH_BYTES: [u8; 32] = [0u8; 32];
|
|
|
15
15
|
/// Represents a nilified payload hash (equivalent to bytes32(type(uint256).max) in Solidity)
|
|
16
16
|
const NIL_PAYLOAD_HASH_BYTES: [u8; 32] = [0xffu8; 32];
|
|
17
17
|
|
|
18
|
+
/// Max number of out-of-order nonces in the pending list.
|
|
19
|
+
pub(super) const PENDING_INBOUND_NONCE_MAX_LEN: u64 = 256;
|
|
20
|
+
|
|
18
21
|
#[contract_impl]
|
|
19
22
|
impl IMessagingChannel for EndpointV2 {
|
|
20
23
|
/// Skips the next expected inbound nonce without verifying.
|
|
@@ -25,7 +28,7 @@ impl IMessagingChannel for EndpointV2 {
|
|
|
25
28
|
|
|
26
29
|
let next_nonce = Self::inbound_nonce(env, receiver, src_eid, sender) + 1;
|
|
27
30
|
assert_with_error!(env, nonce == next_nonce, EndpointError::InvalidNonce);
|
|
28
|
-
|
|
31
|
+
Self::insert_and_drain_pending_nonces(env, receiver, src_eid, sender, nonce);
|
|
29
32
|
|
|
30
33
|
InboundNonceSkipped { src_eid, sender: sender.clone(), receiver: receiver.clone(), nonce }.publish(env);
|
|
31
34
|
}
|
|
@@ -45,10 +48,14 @@ impl IMessagingChannel for EndpointV2 {
|
|
|
45
48
|
Self::require_oapp_auth(env, caller, receiver);
|
|
46
49
|
|
|
47
50
|
let cur_payload_hash = Self::inbound_payload_hash(env, receiver, src_eid, sender, nonce);
|
|
48
|
-
let
|
|
51
|
+
let inbound_nonce = Self::inbound_nonce(env, receiver, src_eid, sender);
|
|
49
52
|
|
|
50
53
|
assert_with_error!(env, payload_hash == &cur_payload_hash, EndpointError::PayloadHashNotFound);
|
|
51
|
-
assert_with_error!(env, nonce >
|
|
54
|
+
assert_with_error!(env, nonce > inbound_nonce || cur_payload_hash.is_some(), EndpointError::InvalidNonce);
|
|
55
|
+
|
|
56
|
+
if nonce > inbound_nonce {
|
|
57
|
+
Self::insert_and_drain_pending_nonces(env, receiver, src_eid, sender, nonce);
|
|
58
|
+
}
|
|
52
59
|
EndpointStorage::set_inbound_payload_hash(env, receiver, src_eid, sender, nonce, &Self::nil_payload_hash(env));
|
|
53
60
|
|
|
54
61
|
PacketNilified {
|
|
@@ -77,9 +84,9 @@ impl IMessagingChannel for EndpointV2 {
|
|
|
77
84
|
let cur_payload_hash = Self::inbound_payload_hash(env, receiver, src_eid, sender, nonce);
|
|
78
85
|
assert_with_error!(env, cur_payload_hash.as_ref() == Some(payload_hash), EndpointError::PayloadHashNotFound);
|
|
79
86
|
|
|
80
|
-
// Check if nonce is at or below the
|
|
81
|
-
let
|
|
82
|
-
assert_with_error!(env, nonce <=
|
|
87
|
+
// Check if nonce is at or below the inbound nonce
|
|
88
|
+
let inbound_nonce = Self::inbound_nonce(env, receiver, src_eid, sender);
|
|
89
|
+
assert_with_error!(env, nonce <= inbound_nonce, EndpointError::InvalidNonce);
|
|
83
90
|
|
|
84
91
|
// Remove the payload hash from storage
|
|
85
92
|
EndpointStorage::remove_inbound_payload_hash(env, receiver, src_eid, sender, nonce);
|
|
@@ -112,25 +119,15 @@ impl IMessagingChannel for EndpointV2 {
|
|
|
112
119
|
/// Returns the max index of the longest gapless sequence of verified message nonces.
|
|
113
120
|
///
|
|
114
121
|
/// The uninitialized value is 0. The first nonce is always 1.
|
|
115
|
-
/// It starts from the `lazy_inbound_nonce` (last checkpoint) and iteratively checks
|
|
116
|
-
/// if the next nonce has been verified.
|
|
117
122
|
///
|
|
118
123
|
/// Note: OApp explicitly skipped nonces count as "verified" for these purposes.
|
|
119
|
-
///
|
|
120
|
-
/// Examples: `[1,2,3,4,6,7] => 4`, `[1,2,6,8,10] => 2`, `[1,3,4,5,6] => 1`
|
|
121
124
|
fn inbound_nonce(env: &Env, receiver: &Address, src_eid: u32, sender: &BytesN<32>) -> u64 {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// Find the effective inbound current nonce
|
|
125
|
-
while EndpointStorage::has_inbound_payload_hash(env, receiver, src_eid, sender, nonce_cursor + 1) {
|
|
126
|
-
nonce_cursor += 1;
|
|
127
|
-
}
|
|
128
|
-
nonce_cursor
|
|
125
|
+
EndpointStorage::inbound_nonce(env, receiver, src_eid, sender)
|
|
129
126
|
}
|
|
130
127
|
|
|
131
|
-
/// Returns the
|
|
132
|
-
fn
|
|
133
|
-
EndpointStorage::
|
|
128
|
+
/// Returns the pending inbound nonces for a specific path.
|
|
129
|
+
fn pending_inbound_nonces(env: &Env, receiver: &Address, src_eid: u32, sender: &BytesN<32>) -> Vec<u64> {
|
|
130
|
+
EndpointStorage::pending_inbound_nonces(env, receiver, src_eid, sender)
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
/// Returns the payload hash for a specific inbound nonce.
|
|
@@ -162,9 +159,8 @@ impl EndpointV2 {
|
|
|
162
159
|
|
|
163
160
|
/// Records an inbound message payload hash for a specific nonce on a specific path.
|
|
164
161
|
///
|
|
165
|
-
///
|
|
166
|
-
///
|
|
167
|
-
/// Messages can only be cleared in order to preserve censorship-resistance.
|
|
162
|
+
/// When nonce > inbound_nonce, inserts into the pending list and drains consecutive
|
|
163
|
+
/// nonces to update the effective inbound nonce.
|
|
168
164
|
///
|
|
169
165
|
/// # Arguments
|
|
170
166
|
/// * `receiver` - The receiver OApp address
|
|
@@ -181,22 +177,27 @@ impl EndpointV2 {
|
|
|
181
177
|
payload_hash: &BytesN<32>,
|
|
182
178
|
) {
|
|
183
179
|
assert_with_error!(env, payload_hash != &Self::empty_payload_hash(env), EndpointError::InvalidPayloadHash);
|
|
180
|
+
|
|
181
|
+
let inbound_nonce = Self::inbound_nonce(env, receiver, src_eid, sender);
|
|
182
|
+
|
|
183
|
+
// Only allow to verify new nonces or re-verify unexecuted nonces.
|
|
184
|
+
assert_with_error!(
|
|
185
|
+
env,
|
|
186
|
+
nonce > inbound_nonce || EndpointStorage::has_inbound_payload_hash(env, receiver, src_eid, sender, nonce),
|
|
187
|
+
EndpointError::InvalidNonce
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if nonce > inbound_nonce {
|
|
191
|
+
Self::insert_and_drain_pending_nonces(env, receiver, src_eid, sender, nonce);
|
|
192
|
+
}
|
|
193
|
+
|
|
184
194
|
EndpointStorage::set_inbound_payload_hash(env, receiver, src_eid, sender, nonce, payload_hash);
|
|
185
195
|
}
|
|
186
196
|
|
|
187
|
-
/// Clears a stored message payload
|
|
188
|
-
///
|
|
189
|
-
/// Calling this function will clear the stored message and increment the
|
|
190
|
-
/// `lazy_inbound_nonce` to the provided nonce.
|
|
197
|
+
/// Clears a stored message payload.
|
|
191
198
|
///
|
|
192
|
-
///
|
|
193
|
-
///
|
|
194
|
-
///
|
|
195
|
-
/// # EVM Alignment
|
|
196
|
-
/// This implementation aligns with the EVM endpoint behavior. Executors should call
|
|
197
|
-
/// `clear` from lower nonce to higher nonce sequentially. This ensures the range check
|
|
198
|
-
/// `(current_nonce + 1..=nonce)` remains small, avoiding long iteration when verifying
|
|
199
|
-
/// that all intermediate nonces have been verified.
|
|
199
|
+
/// Requires nonce <= inbound_nonce (no iteration, O(1) check). The inbound_nonce
|
|
200
|
+
/// is updated during verify when consecutive nonces are drained from the pending list.
|
|
200
201
|
///
|
|
201
202
|
/// # Arguments
|
|
202
203
|
/// * `receiver` - The receiver OApp address
|
|
@@ -212,15 +213,8 @@ impl EndpointV2 {
|
|
|
212
213
|
nonce: u64,
|
|
213
214
|
payload: &Bytes,
|
|
214
215
|
) {
|
|
215
|
-
let
|
|
216
|
-
|
|
217
|
-
// Try to update the lazy inbound nonce until the target nonce
|
|
218
|
-
if nonce > current_nonce {
|
|
219
|
-
let has_payload = (current_nonce + 1..=nonce)
|
|
220
|
-
.all(|n| EndpointStorage::has_inbound_payload_hash(env, receiver, src_eid, sender, n));
|
|
221
|
-
assert_with_error!(env, has_payload, EndpointError::InvalidNonce);
|
|
222
|
-
EndpointStorage::set_lazy_inbound_nonce(env, receiver, src_eid, sender, &nonce);
|
|
223
|
-
}
|
|
216
|
+
let inbound_nonce = Self::inbound_nonce(env, receiver, src_eid, sender);
|
|
217
|
+
assert_with_error!(env, nonce <= inbound_nonce, EndpointError::InvalidNonce);
|
|
224
218
|
|
|
225
219
|
// Check the hash of the payload to verify the executor has given the proper payload that has been verified
|
|
226
220
|
let actual_hash = keccak256(env, payload);
|
|
@@ -231,6 +225,45 @@ impl EndpointV2 {
|
|
|
231
225
|
EndpointStorage::remove_inbound_payload_hash(env, receiver, src_eid, sender, nonce);
|
|
232
226
|
}
|
|
233
227
|
|
|
228
|
+
/// Inserts a nonce into a sorted pending list, then drains consecutive nonces from the front
|
|
229
|
+
/// to advance `inbound_nonce`.
|
|
230
|
+
///
|
|
231
|
+
/// Bounded by `PENDING_INBOUND_NONCE_MAX_LEN` to prevent DDoS via unbounded list growth.
|
|
232
|
+
fn insert_and_drain_pending_nonces(
|
|
233
|
+
env: &Env,
|
|
234
|
+
receiver: &Address,
|
|
235
|
+
src_eid: u32,
|
|
236
|
+
sender: &BytesN<32>,
|
|
237
|
+
new_nonce: u64,
|
|
238
|
+
) {
|
|
239
|
+
let inbound_nonce = Self::inbound_nonce(env, receiver, src_eid, sender);
|
|
240
|
+
assert_with_error!(
|
|
241
|
+
env,
|
|
242
|
+
new_nonce > inbound_nonce && new_nonce <= inbound_nonce + PENDING_INBOUND_NONCE_MAX_LEN,
|
|
243
|
+
EndpointError::InvalidNonce
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
let mut pending_nonces = Self::pending_inbound_nonces(env, receiver, src_eid, sender);
|
|
247
|
+
|
|
248
|
+
// Allow to re-verify at the same nonce and insert the new nonce if it doesn't already exist.
|
|
249
|
+
// When the binary_search returns an error, the nonce is not in the list and should be inserted.
|
|
250
|
+
if let Err(i) = pending_nonces.binary_search(new_nonce) {
|
|
251
|
+
pending_nonces.insert(i, new_nonce);
|
|
252
|
+
|
|
253
|
+
// Drain consecutive nonces from the front to advance the inbound nonce
|
|
254
|
+
let mut new_inbound_nonce = inbound_nonce;
|
|
255
|
+
while !pending_nonces.is_empty() && pending_nonces.first_unchecked() == new_inbound_nonce + 1 {
|
|
256
|
+
new_inbound_nonce = pending_nonces.pop_front_unchecked();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Update the pending nonces and inbound nonce if needed
|
|
260
|
+
EndpointStorage::set_pending_inbound_nonces(env, receiver, src_eid, sender, &pending_nonces);
|
|
261
|
+
if new_inbound_nonce > inbound_nonce {
|
|
262
|
+
EndpointStorage::set_inbound_nonce(env, receiver, src_eid, sender, &new_inbound_nonce);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
234
267
|
/// Represents an empty payload hash
|
|
235
268
|
fn empty_payload_hash(env: &Env) -> BytesN<32> {
|
|
236
269
|
BytesN::from_array(env, &EMPTY_PAYLOAD_HASH_BYTES)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use crate::Timeout;
|
|
2
2
|
use common_macros::storage;
|
|
3
|
-
use soroban_sdk::{Address, BytesN};
|
|
3
|
+
use soroban_sdk::{Address, BytesN, Vec};
|
|
4
4
|
|
|
5
5
|
#[storage]
|
|
6
6
|
pub enum EndpointStorage {
|
|
@@ -24,10 +24,15 @@ pub enum EndpointStorage {
|
|
|
24
24
|
/// Messaging Channel
|
|
25
25
|
/// ============================================================================================
|
|
26
26
|
|
|
27
|
-
///
|
|
27
|
+
/// Sorted list of out-of-order verified nonces
|
|
28
|
+
#[persistent(Vec<u64>)]
|
|
29
|
+
#[default(Vec::new(env))]
|
|
30
|
+
PendingInboundNonces { receiver: Address, src_eid: u32, sender: BytesN<32> },
|
|
31
|
+
|
|
32
|
+
/// The current inbound nonce for a receiver
|
|
28
33
|
#[persistent(u64)]
|
|
29
34
|
#[default(0)]
|
|
30
|
-
|
|
35
|
+
InboundNonce { receiver: Address, src_eid: u32, sender: BytesN<32> },
|
|
31
36
|
|
|
32
37
|
/// The inbound payload hash for a receiver
|
|
33
38
|
#[persistent(BytesN<32>)]
|
|
@@ -270,11 +270,11 @@ impl<'a> TestSetup<'a> {
|
|
|
270
270
|
self.endpoint_client.send_compose(from, to, guid, &index, message);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
-
pub fn
|
|
273
|
+
pub fn set_inbound_nonce(&self, receiver: &Address, src_eid: u32, sender: &BytesN<32>, inbound_nonce: u64) {
|
|
274
274
|
let env = &self.env;
|
|
275
275
|
let endpoint_client = &self.endpoint_client;
|
|
276
276
|
env.as_contract(&endpoint_client.address, || {
|
|
277
|
-
storage::EndpointStorage::
|
|
277
|
+
storage::EndpointStorage::set_inbound_nonce(env, receiver, src_eid, sender, &inbound_nonce)
|
|
278
278
|
});
|
|
279
279
|
}
|
|
280
280
|
|
|
@@ -119,9 +119,9 @@ fn test_clear_emits_packet_delivered_event() {
|
|
|
119
119
|
assert_eq_event(env, &endpoint_client.address, PacketDelivered { origin: origin.clone(), receiver: receiver.clone() });
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
//
|
|
122
|
+
// Inbound nonce is advanced during verify, not during clear
|
|
123
123
|
#[test]
|
|
124
|
-
fn
|
|
124
|
+
fn test_clear_does_not_change_inbound_nonce() {
|
|
125
125
|
let context = setup();
|
|
126
126
|
let env = &context.env;
|
|
127
127
|
let endpoint_client = &context.endpoint_client;
|
|
@@ -136,15 +136,13 @@ fn test_clear_updates_lazy_inbound_nonce() {
|
|
|
136
136
|
let (_receive_lib, origin, _payload_hash) =
|
|
137
137
|
arrange_verified_packet_with_auth(&context, src_eid, &sender, &receiver, nonce, &guid, &message);
|
|
138
138
|
|
|
139
|
-
// Verify
|
|
140
|
-
|
|
141
|
-
assert_eq!(initial_lazy_nonce, 0, "Initial lazy inbound nonce should be 0");
|
|
139
|
+
// Verify advanced inbound nonce (happens during verify).
|
|
140
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), nonce);
|
|
142
141
|
|
|
143
142
|
clear_packet_with_auth(&context, &receiver, &origin, &receiver, &guid, &message);
|
|
144
143
|
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
assert_eq!(lazy_nonce, nonce);
|
|
144
|
+
// Clear does not advance inbound nonce.
|
|
145
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), nonce);
|
|
148
146
|
}
|
|
149
147
|
|
|
150
148
|
// Sequential nonce behavior
|
|
@@ -179,9 +177,8 @@ fn test_clear_success_sequential_nonces_update_lazy_nonce_to_latest() {
|
|
|
179
177
|
verify_packet_with_auth(&context, &receive_lib, &origin2, &receiver, &payload_hash2);
|
|
180
178
|
clear_packet_with_auth(&context, &receiver, &origin2, &receiver, &guid2, &message2);
|
|
181
179
|
|
|
182
|
-
// Verify
|
|
183
|
-
|
|
184
|
-
assert_eq!(lazy_nonce, 2);
|
|
180
|
+
// Verify advanced inbound nonce.
|
|
181
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
185
182
|
}
|
|
186
183
|
|
|
187
184
|
// Authorization
|
|
@@ -410,11 +407,11 @@ fn test_clear_does_not_advance_lazy_nonce_when_clearing_older_nonce() {
|
|
|
410
407
|
let origin2 = Origin { src_eid, sender: sender.clone(), nonce: 2 };
|
|
411
408
|
verify_packet_with_auth(&context, &receive_lib, &origin2, &receiver, &payload_hash2);
|
|
412
409
|
|
|
413
|
-
// Clear nonce 2 first
|
|
410
|
+
// Clear nonce 2 first. This does not advance inbound nonce (it was advanced during verify).
|
|
414
411
|
clear_packet_with_auth(&context, &receiver, &origin2, &receiver, &guid2, &message2);
|
|
415
|
-
assert_eq!(endpoint_client.
|
|
412
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
416
413
|
|
|
417
|
-
// Clearing an older nonce should not change
|
|
414
|
+
// Clearing an older nonce should not change inbound nonce.
|
|
418
415
|
clear_packet_with_auth(&context, &receiver, &origin1, &receiver, &guid1, &message1);
|
|
419
|
-
assert_eq!(endpoint_client.
|
|
416
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
420
417
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use soroban_sdk::{testutils::Address as _, BytesN};
|
|
2
2
|
|
|
3
|
-
use crate::{tests::endpoint_setup::setup, tests::endpoint_setup::TestSetup, Origin};
|
|
3
|
+
use crate::{storage, tests::endpoint_setup::setup, tests::endpoint_setup::TestSetup, Origin};
|
|
4
4
|
|
|
5
5
|
fn skip_with_auth(context: &TestSetup, receiver: &soroban_sdk::Address, src_eid: u32, sender: &BytesN<32>, nonce: u64) {
|
|
6
6
|
// `skip` requires authorization from `caller` (the receiver or its delegate).
|
|
@@ -20,7 +20,7 @@ fn verify_with_auth(
|
|
|
20
20
|
context.endpoint_client.verify(receive_lib, origin, receiver, payload_hash);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// New path (
|
|
23
|
+
// New path (inbound nonce == 0) => verifiable when origin.nonce is within (0, 256]
|
|
24
24
|
#[test]
|
|
25
25
|
fn test_verifiable_new_path_nonce_1_true() {
|
|
26
26
|
let context = setup();
|
|
@@ -30,12 +30,12 @@ fn test_verifiable_new_path_nonce_1_true() {
|
|
|
30
30
|
let sender = BytesN::from_array(&context.env, &[1u8; 32]);
|
|
31
31
|
let origin = Origin { src_eid, sender, nonce: 1 };
|
|
32
32
|
|
|
33
|
-
// For a new path (
|
|
33
|
+
// For a new path (inbound nonce is 0), nonce 1 should be verifiable.
|
|
34
34
|
let result = endpoint_client.verifiable(&origin, &receiver);
|
|
35
35
|
assert!(result);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// Established path
|
|
38
|
+
// Established path => verifiable when origin.nonce is in (inbound_nonce, inbound_nonce + 256]
|
|
39
39
|
#[test]
|
|
40
40
|
fn test_verifiable_after_skip_nonce_gt_lazy_true() {
|
|
41
41
|
let context = setup();
|
|
@@ -48,7 +48,7 @@ fn test_verifiable_after_skip_nonce_gt_lazy_true() {
|
|
|
48
48
|
// Establish the path by skipping nonce 1.
|
|
49
49
|
skip_with_auth(&context, &receiver, src_eid, &sender, 1);
|
|
50
50
|
|
|
51
|
-
// Now
|
|
51
|
+
// Now inbound_nonce = 1, nonce 2 should be verifiable.
|
|
52
52
|
let origin = Origin { src_eid, sender, nonce: 2 };
|
|
53
53
|
let result = endpoint_client.verifiable(&origin, &receiver);
|
|
54
54
|
assert!(result);
|
|
@@ -79,8 +79,8 @@ fn test_verifiable_true_when_nonce_leq_lazy_but_payload_hash_exists() {
|
|
|
79
79
|
// Advance lazy nonce to 3 while keeping payload hash for 2 (skip sets lazy nonce only).
|
|
80
80
|
skip_with_auth(&context, &receiver, src_eid, &sender, 3);
|
|
81
81
|
|
|
82
|
-
// Sanity:
|
|
83
|
-
assert_eq!(endpoint_client.
|
|
82
|
+
// Sanity: inbound nonce was advanced, and the payload hash for nonce 2 still exists.
|
|
83
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 3);
|
|
84
84
|
assert!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2u64).is_some());
|
|
85
85
|
|
|
86
86
|
// Now nonce 2 <= lazy 3, but payload hash exists -> verifiable should be true.
|
|
@@ -98,13 +98,50 @@ fn test_verifiable_nonce_eq_lazy_false_without_payload_hash() {
|
|
|
98
98
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
99
99
|
let receiver = soroban_sdk::Address::generate(env);
|
|
100
100
|
|
|
101
|
-
//
|
|
101
|
+
// Advance inbound nonce to 2 without storing any payload hashes at nonce 2.
|
|
102
102
|
skip_with_auth(&context, &receiver, src_eid, &sender, 1);
|
|
103
103
|
skip_with_auth(&context, &receiver, src_eid, &sender, 2);
|
|
104
|
-
assert_eq!(endpoint_client.
|
|
104
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
105
105
|
|
|
106
106
|
// nonce == lazy and payload hash missing -> verifiable should be false.
|
|
107
107
|
let origin2 = Origin { src_eid, sender: sender.clone(), nonce: 2u64 };
|
|
108
108
|
assert!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2u64).is_none());
|
|
109
109
|
assert!(!endpoint_client.verifiable(&origin2, &receiver));
|
|
110
110
|
}
|
|
111
|
+
|
|
112
|
+
#[test]
|
|
113
|
+
fn test_verifiable_upper_bound_is_enforced() {
|
|
114
|
+
let context = setup();
|
|
115
|
+
let env = &context.env;
|
|
116
|
+
let endpoint_client = &context.endpoint_client;
|
|
117
|
+
|
|
118
|
+
let src_eid = 2u32;
|
|
119
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
120
|
+
let receiver = soroban_sdk::Address::generate(env);
|
|
121
|
+
|
|
122
|
+
// For a new path inbound_nonce=0: 256 is allowed, 257 is not.
|
|
123
|
+
let origin_256 = Origin { src_eid, sender: sender.clone(), nonce: 256u64 };
|
|
124
|
+
let origin_257 = Origin { src_eid, sender, nonce: 257u64 };
|
|
125
|
+
assert!(endpoint_client.verifiable(&origin_256, &receiver));
|
|
126
|
+
assert!(!endpoint_client.verifiable(&origin_257, &receiver));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
#[test]
|
|
130
|
+
fn test_verifiable_upper_bound_is_enforced_when_inbound_nonce_nonzero() {
|
|
131
|
+
let context = setup();
|
|
132
|
+
let env = &context.env;
|
|
133
|
+
let endpoint_client = &context.endpoint_client;
|
|
134
|
+
|
|
135
|
+
let src_eid = 2u32;
|
|
136
|
+
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
137
|
+
let receiver = soroban_sdk::Address::generate(env);
|
|
138
|
+
|
|
139
|
+
env.as_contract(&endpoint_client.address, || {
|
|
140
|
+
storage::EndpointStorage::set_inbound_nonce(env, &receiver, src_eid, &sender, &100u64)
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
let ok = Origin { src_eid, sender: sender.clone(), nonce: 356u64 }; // 100 + 256
|
|
144
|
+
let too_far = Origin { src_eid, sender, nonce: 357u64 };
|
|
145
|
+
assert!(endpoint_client.verifiable(&ok, &receiver));
|
|
146
|
+
assert!(!endpoint_client.verifiable(&too_far, &receiver));
|
|
147
|
+
}
|
|
@@ -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
|
}
|