Skip to content

Logic for how a request is submitted to watcher #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: new-contract-structure
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions contracts/app-gateway/DeliveryHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import "./FeesHelpers.sol";
/// @title DeliveryHelper
/// @notice Contract for managing payload delivery
contract DeliveryHelper is FeesHelpers {

/// @notice Calls the watcher precompile to start processing a request
/// @dev If a transmitter was already assigned, it updates the transmitter in watcher precompile too
/// @param requestCount_ The ID of the request
Expand Down Expand Up @@ -37,7 +36,7 @@ contract DeliveryHelper is FeesHelpers {

// todo: move it to watcher precompile
if (requestMetadata_.winningBid.transmitter != address(0))
IFeesManager(addressResolver__.feesManager()).unblockAndAssignCredits(
feesManager__().unblockAndAssignCredits(
requestCount_,
requestMetadata_.winningBid.transmitter
);
Expand Down Expand Up @@ -77,14 +76,13 @@ contract DeliveryHelper is FeesHelpers {
function _settleFees(uint40 requestCount_) internal {
// If the request has a winning bid, ie. transmitter already assigned, unblock and assign fees
if (requests[requestCount_].winningBid.transmitter != address(0)) {
IFeesManager(addressResolver__.feesManager()).unblockAndAssignCredits(
feesManager__().unblockAndAssignCredits(
requestCount_,
requests[requestCount_].winningBid.transmitter
);
} else {
// If the request has no winning bid, ie. transmitter not assigned, unblock fees
IFeesManager(addressResolver__.feesManager()).unblockCredits(requestCount_);
feesManager__().unblockCredits(requestCount_);
}
}

}
181 changes: 1 addition & 180 deletions contracts/app-gateway/RequestQueue.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,164 +5,21 @@ import "./DeliveryUtils.sol";

/// @notice Abstract contract for managing asynchronous payloads
abstract contract RequestQueue is DeliveryUtils {
// slots [207-257] reserved for gap
uint256[50] _gap_queue_async;


/// @notice Initiates a batch of payloads
/// @param maxFees_ The fees data
/// @param auctionManager_ The auction manager address
/// @return requestCount The ID of the batch
function batch(
uint256 maxFees_,
address auctionManager_,
address consumeFrom_,
bytes memory onCompleteData_
) external returns (uint40 requestCount) {
address appGateway = _getCoreAppGateway(msg.sender);
return _batch(appGateway, auctionManager_, consumeFrom_, maxFees_, onCompleteData_);
}

/// @notice Initiates a batch of payloads
/// @dev it checks fees, payload limits and creates the payload submit params array after assigning proper levels
/// @dev It also modifies the deploy payloads as needed by contract factory plug
/// @dev Stores request metadata and submits the request to watcher precompile
function _batch(
address appGateway_,
address auctionManager_,
address consumeFrom_,
uint256 maxFees_,
bytes memory onCompleteData_
) internal returns (uint40 requestCount) {
if (queuePayloadParams.length == 0) return 0;

BatchParams memory params = BatchParams({
appGateway: appGateway_,
auctionManager: _getAuctionManager(auctionManager_),
maxFees: maxFees_,
onCompleteData: onCompleteData_,
onlyReadRequests: false,
queryCount: 0,
finalizeCount: 0
});

// Split the function into smaller parts
(
PayloadSubmitParams[] memory payloadSubmitParamsArray,
bool onlyReadRequests,
uint256 queryCount,
uint256 finalizeCount
) = _createPayloadSubmitParamsArray();

params.onlyReadRequests = onlyReadRequests;
params.queryCount = queryCount;
params.finalizeCount = finalizeCount;

_checkBatch(consumeFrom_, params.appGateway, params.maxFees);
return _submitBatchRequest(payloadSubmitParamsArray, consumeFrom_, params);
}

function _submitBatchRequest(
PayloadSubmitParams[] memory payloadSubmitParamsArray,
address consumeFrom_,
BatchParams memory params
) internal returns (uint40 requestCount) {
RequestMetadata memory requestMetadata = RequestMetadata({
appGateway: params.appGateway,
auctionManager: params.auctionManager,
maxFees: params.maxFees,
winningBid: Bid({fee: 0, transmitter: address(0), extraData: new bytes(0)}),
onCompleteData: params.onCompleteData,
onlyReadRequests: params.onlyReadRequests,
consumeFrom: consumeFrom_,
queryCount: params.queryCount,
finalizeCount: params.finalizeCount
});

requestCount = watcherPrecompile__().submitRequest(payloadSubmitParamsArray);
requests[requestCount] = requestMetadata;

if (params.onlyReadRequests) {
watcherPrecompile__().startProcessingRequest(requestCount, address(0));
}

uint256 watcherFees = watcherPrecompileLimits().getTotalFeesRequired(
params.queryCount,
params.finalizeCount,
0,
0
);
if (watcherFees > params.maxFees) revert InsufficientFees();
uint256 maxTransmitterFees = params.maxFees - watcherFees;

emit PayloadSubmitted(
requestCount,
params.appGateway,
payloadSubmitParamsArray,
maxTransmitterFees,
params.maxFees - watcherFees,
params.auctionManager,
params.onlyReadRequests
);
}

function _getAuctionManager(address auctionManager_) internal view returns (address) {
return
auctionManager_ == address(0)
? IAddressResolver(addressResolver__).defaultAuctionManager()
: auctionManager_;
}

function _checkBatch(
address consumeFrom_,
address appGateway_,
uint256 maxFees_
) internal view {
if (queuePayloadParams.length > REQUEST_PAYLOAD_COUNT_LIMIT)
revert RequestPayloadCountLimitExceeded();

if (
!IFeesManager(addressResolver__.feesManager()).isUserCreditsEnough(
consumeFrom_,
appGateway_,
maxFees_
)
) revert InsufficientFees();
}

/// @notice Creates an array of payload details
/// @return payloadDetailsArray An array of payload details
function _createPayloadSubmitParamsArray()
internal
returns (
PayloadSubmitParams[] memory payloadDetailsArray,
bool onlyReadRequests,
uint256 queryCount,
uint256 finalizeCount
)
{
payloadDetailsArray = new PayloadSubmitParams[](queuePayloadParams.length);
onlyReadRequests = queuePayloadParams[0].callType == CallType.READ;

uint256 currentLevel = 0;
for (uint256 i = 0; i < queuePayloadParams.length; i++) {
if (queuePayloadParams[i].callType == CallType.READ) {
queryCount++;
} else {
onlyReadRequests = false;
finalizeCount++;
}

// Update level for calls
if (i > 0 && queuePayloadParams[i].isParallel != Parallel.ON) {
currentLevel = currentLevel + 1;
}

payloadDetailsArray[i] = _createPayloadDetails(currentLevel, queuePayloadParams[i]);
}

clearQueue();
}

function _createDeployPayloadDetails(
QueuePayloadParams memory queuePayloadParams_
) internal returns (bytes memory payload, address target) {
Expand All @@ -184,40 +41,4 @@ abstract contract RequestQueue is DeliveryUtils {
// getting app gateway for deployer as the plug is connected to the app gateway
target = getDeliveryHelperPlugAddress(queuePayloadParams_.chainSlug);
}

/// @notice Creates the payload details for a given call parameters
/// @param queuePayloadParams_ The call parameters
/// @return payloadDetails The payload details
function _createPayloadDetails(
uint256 level_,
QueuePayloadParams memory queuePayloadParams_
) internal returns (PayloadSubmitParams memory) {
bytes memory payload = queuePayloadParams_.payload;
address target = queuePayloadParams_.target;
if (queuePayloadParams_.callType == CallType.DEPLOY) {
(payload, target) = _createDeployPayloadDetails(queuePayloadParams_);
}

if (queuePayloadParams_.value > chainMaxMsgValueLimit[queuePayloadParams_.chainSlug])
revert MaxMsgValueLimitExceeded();

return
PayloadSubmitParams({
levelNumber: level_,
chainSlug: queuePayloadParams_.chainSlug,
callType: queuePayloadParams_.callType,
isParallel: queuePayloadParams_.isParallel,
writeFinality: queuePayloadParams_.writeFinality,
asyncPromise: queuePayloadParams_.asyncPromise,
switchboard: queuePayloadParams_.switchboard,
target: target,
appGateway: queuePayloadParams_.appGateway,
gasLimit: queuePayloadParams_.gasLimit == 0
? 10_000_000
: queuePayloadParams_.gasLimit,
value: queuePayloadParams_.value,
readAt: queuePayloadParams_.readAt,
payload: payload
});
}
}
32 changes: 4 additions & 28 deletions contracts/core/RequestHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ abstract contract RequestHandler is WatcherPrecompileCore {
function submitRequest(
PayloadSubmitParams[] memory payloadSubmitParams_
) public returns (uint40 requestCount) {
address appGateway = _checkAppGateways(payloadSubmitParams_);

requestCount = nextRequestCount++;
uint40 batchCount = nextBatchCount;
uint40 currentBatch = batchCount;
Expand All @@ -35,7 +33,7 @@ abstract contract RequestHandler is WatcherPrecompileCore {
PayloadSubmitParams memory p = payloadSubmitParams_[i];

// Count reads and writes for checking limits
if (p.callType == CallType.READ) {
if (p.callType == READ) {
readCount++;
} else writeCount++;

Expand All @@ -49,14 +47,6 @@ abstract contract RequestHandler is WatcherPrecompileCore {
}
}

uint40 localPayloadCount = payloadCounter++;
bytes32 payloadId = WatcherIdUtils.createPayloadId(
requestCount,
batchCount,
localPayloadCount,
p.switchboard,
p.chainSlug
);
batchPayloadIds[batchCount].push(payloadId);

bytes32 payloadHeader = PayloadHeaderDecoder.createPayloadHeader(
Expand All @@ -73,13 +63,11 @@ abstract contract RequestHandler is WatcherPrecompileCore {
payloads[payloadId].asyncPromise = p.asyncPromise;
payloads[payloadId].switchboard = p.switchboard;
payloads[payloadId].target = p.target;
payloads[payloadId].appGateway = p.callType == CallType.DEPLOY
? addressResolver__.deliveryHelper()
: p.appGateway;
payloads[payloadId].appGateway = p.appGateway;
payloads[payloadId].payloadId = payloadId;
payloads[payloadId].gasLimit = p.gasLimit;
payloads[payloadId].value = p.value;
payloads[payloadId].readAt = p.readAt;
payloads[payloadId].readAtBlockNumber = p.readAtBlockNumber;
payloads[payloadId].payload = p.payload;

requestParams[requestCount].payloadParamsArray.push(payloads[payloadId]);
Expand All @@ -89,13 +77,7 @@ abstract contract RequestHandler is WatcherPrecompileCore {
// Push the final batch ID to the request's batch list and increment the counter
// This is needed because the last batch in the loop above doesn't get added since there's no next level to trigger it
requestBatchIds[requestCount].push(nextBatchCount++);

requestParams[requestCount].queryCount = readCount;
requestParams[requestCount].finalizeCount = writeCount;

requestParams[requestCount].currentBatch = currentBatch;
requestParams[requestCount].payloadsRemaining = payloadSubmitParams_.length;
requestParams[requestCount].middleware = msg.sender;

emit RequestSubmitted(
msg.sender,
Expand All @@ -111,12 +93,8 @@ abstract contract RequestHandler is WatcherPrecompileCore {
function _checkAppGateways(
PayloadSubmitParams[] memory payloadSubmitParams
) internal view returns (address appGateway) {
bool isDeliveryHelper = msg.sender == addressResolver__.deliveryHelper();

// Get first app gateway and use it as reference
address coreAppGateway = isDeliveryHelper
? _getCoreAppGateway(payloadSubmitParams[0].appGateway)
: _getCoreAppGateway(msg.sender);
address coreAppGateway = _getCoreAppGateway(msg.sender);

// Skip first element since we already checked it
for (uint256 i = 1; i < payloadSubmitParams.length; i++) {
Expand Down Expand Up @@ -169,6 +147,4 @@ abstract contract RequestHandler is WatcherPrecompileCore {

r.currentBatchPayloadsLeft = totalPayloads;
}


}
37 changes: 6 additions & 31 deletions contracts/core/WatcherPrecompileCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import "./WatcherPrecompileStorage.sol";
/// @dev This contract implements the core functionality for payload verification, execution, and app configurations
/// @dev It is inherited by WatcherPrecompile and provides the base implementation for request handling
abstract contract WatcherPrecompileCore is
IWatcherPrecompile,
IWatcher,
WatcherPrecompileStorage,
Initializable,
Ownable,
Expand Down Expand Up @@ -58,22 +58,6 @@ abstract contract WatcherPrecompileCore is
PayloadParams memory params_,
address transmitter_
) internal returns (bytes32 digest) {
uint32 chainSlug = params_.payloadHeader.getChainSlug();

// Verify that the app gateway is properly configured for this chain and target
watcherPrecompileConfig__.verifyConnections(
chainSlug,
params_.target,
params_.appGateway,
params_.switchboard,
requestParams[params_.payloadHeader.getRequestCount()].middleware
);

_consumeCallbackFeesFromRequestCount(
watcherPrecompileLimits__.finalizeFees(),
params_.payloadHeader.getRequestCount()
);

uint256 deadline = block.timestamp + expiryTime;
payloads[params_.payloadId].deadline = deadline;
payloads[params_.payloadId].finalizedTransmitter = transmitter_;
Expand Down Expand Up @@ -107,11 +91,6 @@ abstract contract WatcherPrecompileCore is
/// @param params_ The payload parameters for the query
/// @dev This function sets up a query request and emits a QueryRequested event
function _query(PayloadParams memory params_) internal {
_consumeCallbackFeesFromRequestCount(
watcherPrecompileLimits__.queryFees(),
params_.payloadHeader.getRequestCount()
);

payloads[params_.payloadId].prevDigestsHash = _getPreviousDigestsHash(
params_.payloadHeader.getBatchCount()
);
Expand Down Expand Up @@ -184,22 +163,18 @@ abstract contract WatcherPrecompileCore is
return payloadParamsArray;
}



function _consumeCallbackFeesFromRequestCount(uint256 fees_, uint40 requestCount_) internal {
// for callbacks in all precompiles
uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees();
IFeesManager(addressResolver__.feesManager())
.assignWatcherPrecompileCreditsFromRequestCount(feesToConsume, requestCount_);
feesManager__().assignWatcherPrecompileCreditsFromRequestCount(
feesToConsume,
requestCount_
);
}

function _consumeCallbackFeesFromAddress(uint256 fees_, address consumeFrom_) internal {
// for callbacks in all precompiles
uint256 feesToConsume = fees_ + watcherPrecompileLimits__.callBackFees();
IFeesManager(addressResolver__.feesManager()).assignWatcherPrecompileCreditsFromAddress(
feesToConsume,
consumeFrom_
);
feesManager__().assignWatcherPrecompileCreditsFromAddress(feesToConsume, consumeFrom_);
}

}
Loading