1
+ use alloy_core:: sol_types:: { SolCall , SolValue } ;
2
+ use alloy_core:: { primitives:: U256 as AlloyU256 , sol} ;
1
3
use export_macro:: vm_test;
2
4
use fil_actor_miner:: {
3
5
ProveCommitSectors3Params , SectorActivationManifest , PieceActivationManifest ,
@@ -6,19 +8,25 @@ use fil_actor_miner::{
6
8
use fil_actors_runtime:: {
7
9
EAM_ACTOR_ADDR , test_utils:: EVM_ACTOR_CODE_ID , test_utils:: make_piece_cid,
8
10
} ;
9
- use fvm_ipld_encoding:: { RawBytes , ipld_block:: IpldBlock } ;
11
+ use fvm_ipld_encoding:: { RawBytes , ipld_block:: IpldBlock , BytesDe } ;
10
12
use fvm_shared:: {
11
13
address:: Address , econ:: TokenAmount , sector:: { RegisteredSealProof , SectorNumber } ,
12
14
piece:: PaddedPieceSize , piece:: PieceInfo ,
13
15
} ;
14
16
use num_traits:: Zero ;
15
17
use vm_api:: VM ;
18
+ use vm_api:: util:: serialize_ok;
16
19
17
20
use crate :: util:: {
18
21
create_accounts, create_miner, precommit_sectors_v2,
19
22
advance_by_deadline_to_epoch, PrecommitMetadata ,
20
23
} ;
21
24
25
+ // Generate a statically typed interface for the NotificationReceiver contract
26
+ sol ! ( "../actors/evm/tests/contracts/NotificationReceiver.sol" ) ;
27
+
28
+ // Use ContractParams from evm_test module to avoid duplicate definition
29
+ use super :: evm_test:: ContractParams ;
22
30
23
31
#[ vm_test]
24
32
pub fn evm_receives_ddo_notifications_test ( v : & dyn VM ) {
@@ -58,10 +66,7 @@ pub fn evm_receives_ddo_notifications_test(v: &dyn VM) {
58
66
create_result. ret . unwrap ( ) . deserialize ( ) . expect ( "Failed to decode create return" ) ;
59
67
let evm_actor_addr = Address :: new_id ( create_return. actor_id ) ;
60
68
let evm_robust_addr = create_return. robust_address . unwrap ( ) ;
61
- let evm_eth_addr = create_return. eth_address ;
62
-
63
- println ! ( "Created EVM contract at ID: {}, Robust: {}, ETH: 0x{}" ,
64
- evm_actor_addr, evm_robust_addr, hex:: encode( & evm_eth_addr) ) ;
69
+ let _evm_eth_addr = create_return. eth_address ;
65
70
66
71
67
72
// Precommit sectors
@@ -139,16 +144,87 @@ pub fn evm_receives_ddo_notifications_test(v: &dyn VM) {
139
144
) . unwrap ( ) ;
140
145
141
146
assert ! ( prove_result. code. is_success( ) , "ProveCommit failed: {}" , prove_result. message) ;
142
-
143
- println ! ( "Successfully proved sectors with EVM notifications" ) ;
144
147
145
148
// Verify that the EVM contract received the notifications
146
- // In a real test, we would call a getter method on the contract to verify state
147
- // For now, we check that the EVM actor exists and has the expected code
149
+ // Check that the EVM actor exists with correct code
148
150
let evm_actor = v. actor ( & evm_actor_addr) . unwrap ( ) ;
149
151
assert_eq ! ( evm_actor. code, * EVM_ACTOR_CODE_ID , "EVM actor has wrong code ID" ) ;
150
152
151
- // The contract should have processed the notifications
152
- // In production, we would call contract methods to verify the stored notification data
153
+ // 1. Call totalNotifications() to verify it equals 1
154
+ {
155
+ let call_params = NotificationReceiver :: totalNotificationsCall:: new ( ( ) ) . abi_encode ( ) ;
156
+ let call_result = v. execute_message (
157
+ & worker,
158
+ & evm_robust_addr,
159
+ & TokenAmount :: zero ( ) ,
160
+ fil_actor_evm:: Method :: InvokeContract as u64 ,
161
+ Some ( serialize_ok ( & ContractParams ( call_params. to_vec ( ) ) ) ) ,
162
+ ) . unwrap ( ) ;
163
+
164
+ assert ! ( call_result. code. is_success( ) , "Failed to call totalNotifications: {}" , call_result. message) ;
165
+
166
+ // Decode the return value
167
+ let return_data: BytesDe = call_result. ret . unwrap ( ) . deserialize ( ) . unwrap ( ) ;
168
+ let total_notifications = AlloyU256 :: abi_decode ( & return_data. 0 )
169
+ . expect ( "Failed to decode totalNotifications return value" ) ;
170
+ assert_eq ! ( total_notifications, AlloyU256 :: from( 1 ) , "Expected 1 notification, got {}" , total_notifications) ;
171
+ }
153
172
173
+ // 2. Call getNotification(0) to verify the notification contents match exactly what was sent
174
+ {
175
+ let call_params = NotificationReceiver :: getNotificationCall:: new ( ( AlloyU256 :: from ( 0 ) , ) ) . abi_encode ( ) ;
176
+ let call_result = v. execute_message (
177
+ & worker,
178
+ & evm_robust_addr,
179
+ & TokenAmount :: zero ( ) ,
180
+ fil_actor_evm:: Method :: InvokeContract as u64 ,
181
+ Some ( serialize_ok ( & ContractParams ( call_params. to_vec ( ) ) ) ) ,
182
+ ) . unwrap ( ) ;
183
+
184
+ assert ! ( call_result. code. is_success( ) , "Failed to call getNotification: {}" , call_result. message) ;
185
+
186
+ // Decode the return value - it returns a tuple of (uint64, int64, bytes, uint64, bytes)
187
+ let return_data: BytesDe = call_result. ret . unwrap ( ) . deserialize ( ) . unwrap ( ) ;
188
+
189
+ // Use the generated abi_decode_returns function
190
+ let notification_result = NotificationReceiver :: getNotificationCall:: abi_decode_returns ( & return_data. 0 )
191
+ . expect ( "Failed to decode getNotification return value" ) ;
192
+
193
+ let received_sector = notification_result. sector ;
194
+ let minimum_commitment_epoch = notification_result. minimumCommitmentEpoch ;
195
+ let data_cid_bytes = notification_result. dataCid ;
196
+ let received_piece_size = notification_result. pieceSize ;
197
+ let received_payload = notification_result. payload ;
198
+
199
+ // Verify the notification fields match EXACTLY what was sent in the manifest
200
+
201
+ // Check sector number matches what we set in the manifest
202
+ assert_eq ! ( received_sector, sector_number,
203
+ "Sector number mismatch: expected {}, got {}" , sector_number, received_sector) ;
204
+
205
+ // Check piece size matches what we set in the manifest
206
+ assert_eq ! ( received_piece_size, piece_size0. 0 ,
207
+ "Piece size mismatch: expected {}, got {}" , piece_size0. 0 , received_piece_size) ;
208
+
209
+ // Check payload matches exactly what we set in the manifest (hex "cafe")
210
+ let expected_payload_bytes = hex:: decode ( "cafe" ) . unwrap ( ) ;
211
+ assert_eq ! ( received_payload. as_ref( ) , expected_payload_bytes. as_slice( ) ,
212
+ "Payload mismatch: expected 0x{}, got 0x{}" ,
213
+ hex:: encode( & expected_payload_bytes) , hex:: encode( & received_payload) ) ;
214
+
215
+ // Check the piece CID data is present
216
+ // The contract receives the CID with an extra leading byte from the CBOR encoding,
217
+ // so we verify it contains the expected CID data after the first byte
218
+ let expected_cid_bytes = piece_cid0. to_bytes ( ) ;
219
+ assert ! ( !data_cid_bytes. is_empty( ) , "Data CID should not be empty" ) ;
220
+ assert ! ( data_cid_bytes. len( ) > expected_cid_bytes. len( ) , "Data CID seems too short" ) ;
221
+ // Verify the CID data matches (skipping the first byte which is CBOR encoding)
222
+ assert_eq ! ( & data_cid_bytes[ 1 ..] , expected_cid_bytes,
223
+ "Piece CID data mismatch: expected 0x{}, got 0x{}" ,
224
+ hex:: encode( & expected_cid_bytes) , hex:: encode( & data_cid_bytes[ 1 ..] ) ) ;
225
+
226
+ // Verify minimum_commitment_epoch is set (this is calculated by the system)
227
+ assert ! ( minimum_commitment_epoch > 0 ,
228
+ "Minimum commitment epoch should be positive, got {}" , minimum_commitment_epoch) ;
229
+ }
154
230
}
0 commit comments