@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
|
@@ -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
|
+
|
|
@@ -53,7 +53,7 @@ fn test_skip_requires_auth_even_when_caller_is_receiver() {
|
|
|
53
53
|
endpoint_client.skip(&receiver, &receiver, &src_eid, &sender, &nonce);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
// Successful skip updates inbound
|
|
56
|
+
// Successful skip updates inbound nonce and emits InboundNonceSkipped
|
|
57
57
|
#[test]
|
|
58
58
|
fn test_skip_success() {
|
|
59
59
|
let context = setup();
|
|
@@ -65,13 +65,10 @@ fn test_skip_success() {
|
|
|
65
65
|
let sender = BytesN::from_array(env, &[1u8; 32]);
|
|
66
66
|
let nonce = 1;
|
|
67
67
|
|
|
68
|
-
// Verify initial state: lazy inbound nonce should be 0.
|
|
69
|
-
let initial_lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
|
|
70
|
-
assert_eq!(initial_lazy_nonce, 0, "Initial lazy inbound nonce should be 0");
|
|
71
|
-
|
|
72
68
|
// Initially, inbound nonce should be 0.
|
|
73
69
|
let initial_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
|
|
74
70
|
assert_eq!(initial_nonce, 0);
|
|
71
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
75
72
|
|
|
76
73
|
// Skip nonce 1 (expected nonce is initial_nonce + 1 = 1).
|
|
77
74
|
skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce);
|
|
@@ -86,10 +83,7 @@ fn test_skip_success() {
|
|
|
86
83
|
// Verify inbound nonce reflects the skip via public interface.
|
|
87
84
|
let updated_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
|
|
88
85
|
assert_eq!(updated_nonce, nonce);
|
|
89
|
-
|
|
90
|
-
// Verify lazy inbound nonce was updated.
|
|
91
|
-
let lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
|
|
92
|
-
assert_eq!(lazy_nonce, nonce);
|
|
86
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
93
87
|
}
|
|
94
88
|
|
|
95
89
|
// Multiple sequential skips update to the latest nonce
|
|
@@ -111,13 +105,10 @@ fn test_skip_multiple_nonces() {
|
|
|
111
105
|
let nonce2 = 2;
|
|
112
106
|
skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, nonce2);
|
|
113
107
|
|
|
114
|
-
// Verify lazy inbound nonce was updated to nonce2.
|
|
115
|
-
let lazy_nonce = endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender);
|
|
116
|
-
assert_eq!(lazy_nonce, nonce2);
|
|
117
|
-
|
|
118
108
|
// Verify inbound nonce reflects the latest skip.
|
|
119
109
|
let updated_nonce = endpoint_client.inbound_nonce(&receiver, &src_eid, &sender);
|
|
120
110
|
assert_eq!(updated_nonce, nonce2);
|
|
111
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
121
112
|
}
|
|
122
113
|
|
|
123
114
|
// Delegate authorization (delegate(receiver) is allowed)
|
|
@@ -146,9 +137,8 @@ fn test_skip_with_delegate() {
|
|
|
146
137
|
InboundNonceSkipped { src_eid, sender: sender.clone(), receiver: receiver.clone(), nonce },
|
|
147
138
|
);
|
|
148
139
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
assert_eq!(lazy_nonce, nonce);
|
|
140
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), nonce);
|
|
141
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
152
142
|
}
|
|
153
143
|
|
|
154
144
|
// Path isolation (receiver/src_eid/sender are isolated)
|
|
@@ -176,11 +166,11 @@ fn test_skip_different_paths() {
|
|
|
176
166
|
// Skip for different senders.
|
|
177
167
|
skip_with_auth(&context, &receiver1, &receiver1, src_eid1, &sender2, nonce);
|
|
178
168
|
|
|
179
|
-
// Verify all paths have independent
|
|
180
|
-
assert_eq!(endpoint_client.
|
|
181
|
-
assert_eq!(endpoint_client.
|
|
182
|
-
assert_eq!(endpoint_client.
|
|
183
|
-
assert_eq!(endpoint_client.
|
|
169
|
+
// Verify all paths have independent inbound nonces.
|
|
170
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid1, &sender1), nonce);
|
|
171
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver2, &src_eid1, &sender1), nonce);
|
|
172
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid2, &sender1), nonce);
|
|
173
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver1, &src_eid1, &sender2), nonce);
|
|
184
174
|
}
|
|
185
175
|
|
|
186
176
|
// Invalid nonce rejection (must match expected nonce)
|
|
@@ -224,10 +214,10 @@ fn test_skip_next_nonce_accounts_for_verified_payload_hashes() {
|
|
|
224
214
|
let result = endpoint_client.try_skip(&receiver, &receiver, &src_eid, &sender, &1);
|
|
225
215
|
assert_eq!(result.err().unwrap().ok().unwrap(), EndpointError::InvalidNonce.into());
|
|
226
216
|
|
|
227
|
-
// Skipping 2 should succeed and advance
|
|
217
|
+
// Skipping 2 should succeed and advance inbound nonce to 2.
|
|
228
218
|
skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 2);
|
|
229
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
230
219
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
220
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
231
221
|
|
|
232
222
|
// skip() does not clear any existing payload hashes.
|
|
233
223
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &1), Some(payload_hash_1));
|
|
@@ -251,8 +241,8 @@ fn test_skip_closes_gap_and_advances_inbound_nonce() {
|
|
|
251
241
|
|
|
252
242
|
// Skip nonce 1 to close the gap. This should allow inbound_nonce to advance to 2.
|
|
253
243
|
skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 1);
|
|
254
|
-
assert_eq!(endpoint_client.lazy_inbound_nonce(&receiver, &src_eid, &sender), 1);
|
|
255
244
|
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 2);
|
|
245
|
+
assert!(endpoint_client.pending_inbound_nonces(&receiver, &src_eid, &sender).is_empty());
|
|
256
246
|
|
|
257
247
|
// Payload hash at nonce 2 remains intact.
|
|
258
248
|
assert_eq!(endpoint_client.inbound_payload_hash(&receiver, &src_eid, &sender, &2), Some(payload_hash_2));
|
|
@@ -271,7 +261,7 @@ fn test_skip_rejects_repeated_same_nonce() {
|
|
|
271
261
|
|
|
272
262
|
// Skip nonce 1 successfully.
|
|
273
263
|
skip_with_auth(&context, &receiver, &receiver, src_eid, &sender, 1);
|
|
274
|
-
assert_eq!(endpoint_client.
|
|
264
|
+
assert_eq!(endpoint_client.inbound_nonce(&receiver, &src_eid, &sender), 1);
|
|
275
265
|
|
|
276
266
|
// Skipping nonce 1 again should fail since the next expected nonce is now 2.
|
|
277
267
|
context.mock_auth(&receiver, "skip", (&receiver, &receiver, &src_eid, &sender, &1u64));
|
|
@@ -104,9 +104,9 @@ impl LayerZeroView {
|
|
|
104
104
|
let empty_hash = empty_payload_hash(env);
|
|
105
105
|
let nil_hash = nil_payload_hash(env);
|
|
106
106
|
|
|
107
|
-
// Executed: payload hash has been cleared (None) and nonce <=
|
|
107
|
+
// Executed: payload hash has been cleared (None) and nonce <= inbound_nonce
|
|
108
108
|
if payload_hash.is_none()
|
|
109
|
-
&& origin.nonce <= messaging_channel.
|
|
109
|
+
&& origin.nonce <= messaging_channel.inbound_nonce(receiver, &origin.src_eid, &origin.sender)
|
|
110
110
|
{
|
|
111
111
|
return ExecutionState::Executed;
|
|
112
112
|
}
|
|
@@ -206,9 +206,9 @@ fn test_executable_state_executed() {
|
|
|
206
206
|
let receiver = test_setup.register_oapp();
|
|
207
207
|
let sender = soroban_sdk::Address::generate(&test_setup.env);
|
|
208
208
|
|
|
209
|
-
// Clear payload hash (None) and set
|
|
209
|
+
// Clear payload hash (None) and set inbound_nonce >= nonce = Executed
|
|
210
210
|
test_setup.set_payload_hash(&receiver, REMOTE_EID, &sender, 1, &None);
|
|
211
|
-
test_setup.
|
|
211
|
+
test_setup.set_inbound_nonce(&receiver, REMOTE_EID, &sender, 1);
|
|
212
212
|
|
|
213
213
|
let origin = Origin { src_eid: REMOTE_EID, sender: address_to_bytes32(&sender), nonce: 1 };
|
|
214
214
|
|
|
@@ -262,9 +262,8 @@ fn test_executable_multiple_nonces_in_sequence() {
|
|
|
262
262
|
assert_eq!(test_setup.view_client.executable(&origin_2, &receiver), ExecutionState::VerifiedButNotExecutable);
|
|
263
263
|
assert_eq!(test_setup.view_client.executable(&origin_3, &receiver), ExecutionState::VerifiedButNotExecutable);
|
|
264
264
|
|
|
265
|
-
// Now execute nonce 1 (
|
|
265
|
+
// Now execute nonce 1 (clear payload hash, advance inbound_nonce)
|
|
266
266
|
test_setup.set_payload_hash(&receiver, REMOTE_EID, &sender, 1, &None);
|
|
267
|
-
test_setup.set_lazy_inbound_nonce(&receiver, REMOTE_EID, &sender, 1);
|
|
268
267
|
test_setup.set_inbound_nonce(&receiver, REMOTE_EID, &sender, 2);
|
|
269
268
|
|
|
270
269
|
assert_eq!(test_setup.view_client.executable(&origin_1, &receiver), ExecutionState::Executed);
|
|
@@ -30,7 +30,6 @@ mod endpoint_storage {
|
|
|
30
30
|
Initializable(Address, u32, BytesN<32>),
|
|
31
31
|
Verifiable(Address, u32, BytesN<32>),
|
|
32
32
|
// State for executable tests
|
|
33
|
-
LazyInboundNonce(Address, u32, BytesN<32>),
|
|
34
33
|
InboundNonce(Address, u32, BytesN<32>),
|
|
35
34
|
InboundPayloadHash(Address, u32, BytesN<32>, u64),
|
|
36
35
|
ReceiveLibrary(Address, u32),
|
|
@@ -91,13 +90,6 @@ impl MockEndpoint {
|
|
|
91
90
|
.set(&endpoint_storage::MockEndpointStorage::Verifiable(receiver.clone(), *src_eid, sender.clone()), value);
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
pub fn set_lazy_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>, nonce: &u64) {
|
|
95
|
-
env.storage().persistent().set(
|
|
96
|
-
&endpoint_storage::MockEndpointStorage::LazyInboundNonce(receiver.clone(), *src_eid, sender.clone()),
|
|
97
|
-
nonce,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
93
|
pub fn set_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>, nonce: &u64) {
|
|
102
94
|
env.storage().persistent().set(
|
|
103
95
|
&endpoint_storage::MockEndpointStorage::InboundNonce(receiver.clone(), *src_eid, sender.clone()),
|
|
@@ -135,13 +127,6 @@ impl MockEndpoint {
|
|
|
135
127
|
// Getters required by LayerZeroView
|
|
136
128
|
// =========================================================================
|
|
137
129
|
|
|
138
|
-
pub fn lazy_inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>) -> u64 {
|
|
139
|
-
env.storage()
|
|
140
|
-
.persistent()
|
|
141
|
-
.get(&endpoint_storage::MockEndpointStorage::LazyInboundNonce(receiver.clone(), *src_eid, sender.clone()))
|
|
142
|
-
.unwrap_or(0)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
130
|
pub fn inbound_nonce(env: &Env, receiver: &Address, src_eid: &u32, sender: &BytesN<32>) -> u64 {
|
|
146
131
|
env.storage()
|
|
147
132
|
.persistent()
|
|
@@ -282,12 +267,6 @@ impl<'a> TestSetup<'a> {
|
|
|
282
267
|
self.endpoint_client.set_verifiable(receiver, &src_eid, &sender_bytes32, &value);
|
|
283
268
|
}
|
|
284
269
|
|
|
285
|
-
/// Set lazy inbound nonce (marks messages up to this nonce as processed).
|
|
286
|
-
pub fn set_lazy_inbound_nonce(&self, receiver: &Address, src_eid: u32, sender: &Address, nonce: u64) {
|
|
287
|
-
let sender_bytes32 = address_to_bytes32(sender);
|
|
288
|
-
self.endpoint_client.set_lazy_inbound_nonce(receiver, &src_eid, &sender_bytes32, &nonce);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
270
|
/// Set inbound nonce (marks messages up to this nonce as verified and executable).
|
|
292
271
|
pub fn set_inbound_nonce(&self, receiver: &Address, src_eid: u32, sender: &Address, nonce: u64) {
|
|
293
272
|
let sender_bytes32 = address_to_bytes32(sender);
|
|
@@ -27,7 +27,7 @@ fn exposes_ttl_and_ownable_features() {
|
|
|
27
27
|
// Ownable helper works.
|
|
28
28
|
let owner = Address::generate(&env);
|
|
29
29
|
client.init(&owner);
|
|
30
|
-
assert_eq!(client.authorizer(), owner);
|
|
30
|
+
assert_eq!(client.authorizer(), Some(owner));
|
|
31
31
|
|
|
32
32
|
// TTL-configurable read methods exist.
|
|
33
33
|
let _cfg = client.ttl_configs();
|
|
@@ -16,7 +16,7 @@ fn uses_self_owning_auth_and_exposes_ttl() {
|
|
|
16
16
|
|
|
17
17
|
// MultiSig auth => authorizer should be the contract address, without any init.
|
|
18
18
|
let expected = env.as_contract(&contract_id, || env.current_contract_address());
|
|
19
|
-
assert_eq!(client.authorizer(), expected);
|
|
19
|
+
assert_eq!(client.authorizer(), Some(expected));
|
|
20
20
|
|
|
21
21
|
// TTL-configurable read methods exist.
|
|
22
22
|
let _cfg = client.ttl_configs();
|
package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs
CHANGED
|
@@ -30,7 +30,7 @@ fn self_auth_can_migrate_when_flag_set() {
|
|
|
30
30
|
|
|
31
31
|
// MultiSig auth => authorizer should be the contract address, without any init.
|
|
32
32
|
let expected = env.as_contract(&contract_id, || env.current_contract_address());
|
|
33
|
-
assert_eq!(client.authorizer(), expected);
|
|
33
|
+
assert_eq!(client.authorizer(), Some(expected));
|
|
34
34
|
|
|
35
35
|
// Unauthorized migrate should fail.
|
|
36
36
|
let unauthorized = client.try_migrate(&migration_data);
|