Skip to content

Commit b38aefe

Browse files
committed
claude first pass
1 parent 29658f6 commit b38aefe

File tree

6 files changed

+799
-2
lines changed

6 files changed

+799
-2
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.19;
3+
4+
import "./FEVM.sol";
5+
6+
contract NotificationReceiver {
7+
// Events to track notifications
8+
event SectorContentChanged(uint64 indexed method, bytes params);
9+
event NotificationReceived(uint64 indexed sector, uint64 indexed minimumCommitmentEpoch, bytes32 indexed dataCid);
10+
11+
// State variables to track received notifications
12+
struct SectorNotification {
13+
uint64 sector;
14+
uint64 minimumCommitmentEpoch;
15+
bytes32 dataCid;
16+
uint256 pieceSize;
17+
bytes payload;
18+
uint256 timestamp;
19+
}
20+
21+
SectorNotification[] public notifications;
22+
mapping(uint64 => uint256[]) public sectorNotificationIndices;
23+
24+
// Counter for total notifications received
25+
uint256 public totalNotifications;
26+
27+
// Flag to test different response behaviors
28+
bool public shouldRejectNotifications = false;
29+
30+
// Method selector for handle_filecoin_method
31+
bytes4 constant NATIVE_METHOD_SELECTOR = 0x868e10c4;
32+
33+
// Sector content changed method number
34+
uint64 constant SECTOR_CONTENT_CHANGED = 86399155;
35+
36+
/**
37+
* @dev Toggle whether to reject notifications (for testing)
38+
*/
39+
function setRejectNotifications(bool _reject) public {
40+
shouldRejectNotifications = _reject;
41+
}
42+
43+
/**
44+
* @dev Get the count of notifications for a specific sector
45+
*/
46+
function getNotificationCount(uint64 sector) public view returns (uint256) {
47+
return sectorNotificationIndices[sector].length;
48+
}
49+
50+
/**
51+
* @dev Get all notification indices for a sector
52+
*/
53+
function getSectorNotifications(uint64 sector) public view returns (uint256[] memory) {
54+
return sectorNotificationIndices[sector];
55+
}
56+
57+
/**
58+
* @dev Get a specific notification by index
59+
*/
60+
function getNotification(uint256 index) public view returns (
61+
uint64 sector,
62+
uint64 minimumCommitmentEpoch,
63+
bytes32 dataCid,
64+
uint256 pieceSize,
65+
bytes memory payload,
66+
uint256 timestamp
67+
) {
68+
require(index < notifications.length, "Invalid notification index");
69+
SectorNotification memory notif = notifications[index];
70+
return (
71+
notif.sector,
72+
notif.minimumCommitmentEpoch,
73+
notif.dataCid,
74+
notif.pieceSize,
75+
notif.payload,
76+
notif.timestamp
77+
);
78+
}
79+
80+
/**
81+
* @dev Handle incoming Filecoin method calls
82+
* This is the main entry point for receiving notifications from the miner actor
83+
*/
84+
function handle_filecoin_method(uint64 method, uint64, bytes memory params) public returns (bytes memory) {
85+
emit SectorContentChanged(method, params);
86+
87+
// Check if this is a sector content changed notification
88+
if (method == SECTOR_CONTENT_CHANGED) {
89+
return processSectorContentChanged(params);
90+
}
91+
92+
// For other methods, just acknowledge receipt
93+
return abi.encode(true);
94+
}
95+
96+
/**
97+
* @dev Process sector content changed notification
98+
* Expected params structure (CBOR encoded):
99+
* {
100+
* sectors: [{
101+
* sector: uint64,
102+
* minimum_commitment_epoch: int64,
103+
* added: [{
104+
* data: Cid,
105+
* size: uint64,
106+
* payload: bytes
107+
* }]
108+
* }]
109+
* }
110+
*/
111+
function processSectorContentChanged(bytes memory params) internal returns (bytes memory) {
112+
// In a real implementation, we would decode CBOR here
113+
// For testing, we'll process the raw bytes and extract key information
114+
115+
// Check if we should reject this notification
116+
if (shouldRejectNotifications) {
117+
// Return a rejection response
118+
return encodeRejectionResponse();
119+
}
120+
121+
// For this test contract, we'll store a simplified version of the notification
122+
// In production, you would properly decode the CBOR data
123+
124+
// Extract some basic info from the params (simplified for testing)
125+
uint64 sector = extractSectorNumber(params);
126+
uint64 minimumCommitmentEpoch = extractMinimumCommitmentEpoch(params);
127+
bytes32 dataCid = extractDataCid(params);
128+
uint256 pieceSize = extractPieceSize(params);
129+
bytes memory payload = extractPayload(params);
130+
131+
// Store the notification
132+
uint256 notificationIndex = notifications.length;
133+
notifications.push(SectorNotification({
134+
sector: sector,
135+
minimumCommitmentEpoch: minimumCommitmentEpoch,
136+
dataCid: dataCid,
137+
pieceSize: pieceSize,
138+
payload: payload,
139+
timestamp: block.timestamp
140+
}));
141+
142+
sectorNotificationIndices[sector].push(notificationIndex);
143+
totalNotifications++;
144+
145+
emit NotificationReceived(sector, minimumCommitmentEpoch, dataCid);
146+
147+
// Return acceptance response
148+
return encodeAcceptanceResponse();
149+
}
150+
151+
/**
152+
* @dev Extract sector number from params (simplified for testing)
153+
*/
154+
function extractSectorNumber(bytes memory params) internal pure returns (uint64) {
155+
// In a real implementation, this would properly decode CBOR
156+
// For testing, return a dummy value or extract from known position
157+
if (params.length >= 8) {
158+
return uint64(uint8(params[7])) |
159+
(uint64(uint8(params[6])) << 8) |
160+
(uint64(uint8(params[5])) << 16) |
161+
(uint64(uint8(params[4])) << 24);
162+
}
163+
return 0;
164+
}
165+
166+
/**
167+
* @dev Extract minimum commitment epoch from params (simplified)
168+
*/
169+
function extractMinimumCommitmentEpoch(bytes memory params) internal pure returns (uint64) {
170+
// Simplified extraction for testing
171+
if (params.length >= 16) {
172+
return uint64(uint8(params[15])) |
173+
(uint64(uint8(params[14])) << 8) |
174+
(uint64(uint8(params[13])) << 16) |
175+
(uint64(uint8(params[12])) << 24);
176+
}
177+
return 0;
178+
}
179+
180+
/**
181+
* @dev Extract data CID from params (simplified)
182+
*/
183+
function extractDataCid(bytes memory params) internal pure returns (bytes32) {
184+
// Simplified extraction for testing
185+
if (params.length >= 48) {
186+
bytes32 cid;
187+
assembly {
188+
cid := mload(add(params, 48))
189+
}
190+
return cid;
191+
}
192+
return bytes32(0);
193+
}
194+
195+
/**
196+
* @dev Extract piece size from params (simplified)
197+
*/
198+
function extractPieceSize(bytes memory params) internal pure returns (uint256) {
199+
// Simplified extraction for testing
200+
if (params.length >= 24) {
201+
return uint256(uint64(uint8(params[23])) |
202+
(uint64(uint8(params[22])) << 8) |
203+
(uint64(uint8(params[21])) << 16) |
204+
(uint64(uint8(params[20])) << 24));
205+
}
206+
return 0;
207+
}
208+
209+
/**
210+
* @dev Extract payload from params (simplified)
211+
*/
212+
function extractPayload(bytes memory params) internal pure returns (bytes memory) {
213+
// For testing, return a portion of the params as payload
214+
if (params.length > 64) {
215+
bytes memory payload = new bytes(params.length - 64);
216+
for (uint i = 0; i < payload.length; i++) {
217+
payload[i] = params[i + 64];
218+
}
219+
return payload;
220+
}
221+
return "";
222+
}
223+
224+
/**
225+
* @dev Encode an acceptance response for the notification
226+
* The response should match SectorContentChangedReturn structure
227+
*/
228+
function encodeAcceptanceResponse() internal pure returns (bytes memory) {
229+
// Return a properly formatted response indicating acceptance
230+
// Structure: { sectors: [{ added: [{ accepted: true }] }] }
231+
// For simplified testing, return a basic acceptance
232+
return abi.encode(true);
233+
}
234+
235+
/**
236+
* @dev Encode a rejection response for the notification
237+
*/
238+
function encodeRejectionResponse() internal pure returns (bytes memory) {
239+
// Return a properly formatted response indicating rejection
240+
return abi.encode(false);
241+
}
242+
243+
/**
244+
* @dev Fallback function to handle direct calls
245+
*/
246+
fallback() external payable {
247+
// Check if this is a handle_filecoin_method call
248+
if (msg.data.length >= 4 && bytes4(msg.data[0:4]) == NATIVE_METHOD_SELECTOR) {
249+
// Decode the parameters
250+
(uint64 method, uint64 codec, bytes memory params) = abi.decode(msg.data[4:], (uint64, uint64, bytes));
251+
bytes memory result = handle_filecoin_method(method, codec, params);
252+
253+
// Return the result
254+
assembly {
255+
return(add(result, 0x20), mload(result))
256+
}
257+
}
258+
}
259+
260+
receive() external payable {}
261+
}

actors/miner/src/notifications.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::{
44
};
55
use fil_actors_runtime::runtime::Runtime;
66
use fil_actors_runtime::{
7-
ActorError, AsActorError, STORAGE_MARKET_ACTOR_ADDR, SendError, actor_error,
7+
ActorError, AsActorError, SendError,
88
};
99
use fvm_ipld_encoding::ipld_block::IpldBlock;
1010

0 commit comments

Comments
 (0)