Skip to content

Commit

Permalink
rewrite chainIdManager (#91)
Browse files Browse the repository at this point in the history
  • Loading branch information
josojo authored Nov 5, 2023
1 parent 576c0fa commit f7e5806
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 60 deletions.
45 changes: 28 additions & 17 deletions contracts/ChainIdManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,31 @@ pragma solidity ^0.8.20;
import {Owned} from "./mixin/Owned.sol";

contract ChainIdManager is Owned {
// Counter for the number of used Chain IDs
uint256 public usedChainIdCounter = 0;
// Counter for the number of Chain IDs
uint256 public chainIdCounter = 0;
mapping(uint256 => uint64) public usableChainIds;
uint64 public chainIdCounter = 0;
// contains a list of denied Chain IDs that should not be used as chainIds
// they are governed by a owner of the contract
mapping(uint64 => bool) public deniedChainIds;
// Fee to use up a Chain ID
uint256 public immutable gasBurnAmount = 1000000;

constructor() Owned() {}
constructor(uint64 _chainIdCounter) Owned() {chainIdCounter = _chainIdCounter;}

/**
* @dev Adds a Chain ID
* @dev Adds a Chain ID to the deny list, this can be done if the chainId is used by another project
* @param chainId The Chain ID to add
*/
function addChainId(uint64 chainId) public onlyOwner {
usableChainIds[chainIdCounter] = chainId;
chainIdCounter++;
function denyListChainId(uint64 chainId) public onlyOwner {
deniedChainIds[chainId] = true;
}

/**
* @dev Adds multiple Chain IDs
* @dev Adds multiple Chain IDs to the deny list
* @param chainIds The Chain IDs to add
*/
function addChainIds(uint64[] memory chainIds) public onlyOwner {
function denyListChainIds(uint64[] memory chainIds) public onlyOwner {
for (uint256 i = 0; i < chainIds.length; i++) {
addChainId(chainIds[i]);
denyListChainId(chainIds[i]);
}
}

Expand All @@ -36,10 +37,20 @@ contract ChainIdManager is Owned {
* @return chainId The next usable Chain ID
*/
function getNextUsableChainId() public returns (uint64 chainId) {
// Todo: Add a ddos protection: Probably charging gas. But for now,
// the owner can counter ddos attacks by readding unused chainIds
chainId = usableChainIds[usedChainIdCounter];
require(chainId != 0, "No usable Chain ID available");
usedChainIdCounter++;
// The burnGas function introduces a cost to use up chainIds.
// There are uint64(2**63=9.223372e+18) chainIds minus the publicly used chainIds available.
// Using all of the chainIds would cost 9.223372e+18 * gasBurnAmount = 9.223372e+24 gas = 6.1489147e+17 blocks = 237226647377 years
burnGas();
while (deniedChainIds[chainIdCounter]) {
chainIdCounter++;
}
chainId = chainIdCounter;
chainIdCounter++;
}

function burnGas() public view {
uint256 counter = 0;
uint256 _lowestLimit = gasleft() - gasBurnAmount;
while(gasleft() > _lowestLimit) counter++;
}
}
67 changes: 28 additions & 39 deletions test/ChainIdManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,90 +9,79 @@ contract ChainIdManagerTest is Test {

address public owner = address(0xabc);
address public nonOwner = address(0xdef);
uint64 public initialChainId = 10;

function setUp() public {
chainIdManager = new ChainIdManager();
chainIdManager = new ChainIdManager(initialChainId);
chainIdManager.transferOwnership(owner);
}

function testAddChainId() public {
vm.prank(owner);
uint64 newChainId = 1;
chainIdManager.addChainId(newChainId);
uint64 newChainId = 10;
chainIdManager.denyListChainId(newChainId);

assertEq(
chainIdManager.chainIdCounter(),
1,
"Chain ID counter did not increment"
);
assertEq(
chainIdManager.usableChainIds(0),
newChainId,
chainIdManager.getNextUsableChainId(),
newChainId + 1,
"Chain ID not correctly added"
);

// Attempt to add a ChainId by a non-owner, expect a revert
vm.prank(nonOwner);
vm.expectRevert(bytes("Caller is not the owner")); // Expect a revert with a specific revert message
chainIdManager.addChainId(2);
chainIdManager.denyListChainId(2);
}

function testAddChainIds() public {
vm.prank(owner);
uint64[] memory newChainIds = new uint64[](2);
newChainIds[0] = 1;
newChainIds[1] = 2;
chainIdManager.addChainIds(newChainIds);
newChainIds[0] = 10;
newChainIds[1] = 11;
chainIdManager.denyListChainIds(newChainIds);

assertEq(
chainIdManager.chainIdCounter(),
2,
initialChainId,
"Chain ID counter did not increment correctly"
);
assertEq(
chainIdManager.usableChainIds(0),
newChainIds[0],
chainIdManager.getNextUsableChainId(),
newChainIds[1] + 1,
"First Chain ID not correctly added"
);
assertEq(
chainIdManager.usableChainIds(1),
newChainIds[1],
"Second Chain ID not correctly added"
);
}

function testGetNextUsableChainId() public {
uint64 firstDeniedChainId = 10;
vm.prank(owner);
chainIdManager.addChainId(1);
chainIdManager.denyListChainId(firstDeniedChainId);
uint64 secondDeniedChainId = 11;
vm.prank(owner);
chainIdManager.addChainId(2);
chainIdManager.denyListChainId(secondDeniedChainId);

uint64 nextChainId = chainIdManager.getNextUsableChainId();
assertEq(
nextChainId,
1,
secondDeniedChainId + 1,
"Did not get the correct next usable Chain ID"
);
assertEq(
chainIdManager.usedChainIdCounter(),
1,
"Used Chain ID counter did not increment"
);

nextChainId = chainIdManager.getNextUsableChainId();
assertEq(
nextChainId,
2,
secondDeniedChainId + 2,
"Did not get the correct next usable Chain ID"
);
assertEq(
chainIdManager.usedChainIdCounter(),
2,
"Used Chain ID counter did not increment"
);
}

// Assuming that there's no Chain ID left, expect a revert or a return of a default value depending on the contract's behavior
vm.expectRevert(bytes("No usable Chain ID available")); // Or check for a specific return value
chainIdManager.getNextUsableChainId();
function testCheckGasBurn() public {
uint256 initialGasLeft = gasleft();
chainIdManager.burnGas();
uint256 finalGasLeft = gasleft();
assert(
initialGasLeft - finalGasLeft >=
chainIdManager.gasBurnAmount()
);
}
}
6 changes: 2 additions & 4 deletions test/ForkingManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ contract ForkingManagerTest is Test {
uint256 public arbitrationFee = 1020;
bytes32[32] public depositTree;
address public admin = address(0xad);
uint64 public initialChainId = 1;
uint64 public firstChainId = 1;
uint64 public secondChainId = 2;

Expand Down Expand Up @@ -131,10 +132,7 @@ contract ForkingManagerTest is Test {
)
);

chainIdManager = address(new ChainIdManager());

ChainIdManager(chainIdManager).addChainId(firstChainId);
ChainIdManager(chainIdManager).addChainId(secondChainId);
chainIdManager = address(new ChainIdManager(initialChainId));
globalExitRoot.initialize(
address(forkmanager),
address(0x0),
Expand Down

0 comments on commit f7e5806

Please sign in to comment.