When calculating differences between data points and mean values, the current implementation using unsigned integers (uint256
) can lead to arithmetic underflow when a data point is smaller than the mean, causing the transaction to revert and potentially resulting in a Denial of Service (DoS) condition.
Note: This is a simplified version of the project.
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../contracts/llm/LLMOracleCoordinator.sol";
import "../contracts/llm/LLMOracleRegistry.sol";
import "../contracts/llm/LLMOracleTask.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "forge-std/console.sol";
contract TestToken is ERC20 {
constructor() ERC20("TestToken", "TTK") {
_mint(msg.sender, 1_000_000 ether);
}
}
contract LLMOracleCoordinatorTest2 is Test {
LLMOracleCoordinator coordinator;
LLMOracleRegistry registry;
TestToken feeToken;
address owner = address(0x1);
address[] generators;
address[] validators;
function setUp() public {
feeToken = new TestToken();
registry = new LLMOracleRegistry(0, 0, address(feeToken));
coordinator = new LLMOracleCoordinator(
address(registry),
address(feeToken),
1 ether,
1 ether,
1 ether
);
vm.label(owner, "Owner");
vm.deal(owner, 100 ether);
feeToken.transfer(owner, 1_000_000 ether);
}
function logUint256Array(string memory name, uint256[] memory array) internal view {
console.log(string(abi.encodePacked(name, " length: ", vm.toString(array.length))));
for (uint256 i = 0; i < array.length; i++) {
console.log(string(abi.encodePacked(name, "[", vm.toString(i + 1), "] = ")), array[i]);
}
}
function testFuzzFinalizeValidation(uint256 numGenerations, uint256 numValidations) public {
numGenerations = bound(numGenerations, 1, 10);
numValidations = bound(numValidations, 1, 10);
console.log("numGenerations: ", numGenerations);
console.log("numValidations: ", numValidations);
vm.startPrank(owner);
feeToken.approve(address(coordinator), 1_000_000 ether);
vm.stopPrank();
for (uint256 i = 0; i < numGenerations; i++) {
address generator = address(uint160(uint256(keccak256(abi.encodePacked("Generator", i)))));
vm.label(generator, string(abi.encodePacked("Generator", vm.toString(i))));
generators.push(generator);
vm.deal(generator, 10 ether);
vm.startPrank(owner);
feeToken.transfer(generator, 100 ether);
vm.stopPrank();
vm.startPrank(generator);
feeToken.approve(address(registry), 100 ether);
registry.register(LLMOracleKind.Generator);
vm.stopPrank();
}
for (uint256 i = 0; i < numValidations; i++) {
address validator = address(uint160(uint256(keccak256(abi.encodePacked("Validator", i)))));
vm.label(validator, string(abi.encodePacked("Validator", vm.toString(i))));
validators.push(validator);
vm.deal(validator, 10 ether);
vm.startPrank(owner);
feeToken.transfer(validator, 10 ether);
vm.stopPrank();
vm.startPrank(validator);
feeToken.approve(address(registry), 10 ether);
registry.register(LLMOracleKind.Validator);
vm.stopPrank();
}
LLMOracleTaskParameters memory parameters = LLMOracleTaskParameters({
numGenerations: uint40(numGenerations),
numValidations: uint40(numValidations),
difficulty: 1
});
vm.startPrank(owner);
uint256 taskId = coordinator.request("protocol", "input", "models", parameters);
vm.stopPrank();
for (uint256 i = 0; i < numGenerations; i++) {
address generator = generators[i];
vm.startPrank(generator);
coordinator.respond(taskId, i + 1, "output", "metadata");
vm.stopPrank();
}
for (uint256 i = 0; i < numValidations; i++) {
address validator = validators[i];
vm.startPrank(validator);
uint256[] memory scores = new uint256[]();
for (uint256 j = 0; j < numGenerations; j++) {
scores[j] = (uint256(keccak256(abi.encodePacked(i, j, block.timestamp))) % 10) + 1;
}
coordinator.validate(taskId, i + 1, scores, "metadata");
logUint256Array("Total Scores", scores);
vm.stopPrank();
}
}
}
Validators cannot receive their earned fees.
Manual review.
Foundry.