Skip to content
Merged
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
30 changes: 26 additions & 4 deletions contracts/src/bridge/Outbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,30 @@ contract Outbox is DelegateCallAware, IOutbox {
context = prevContext;
}

function _calcSpentIndexOffset(uint256 index)
internal
view
returns (
uint256,
uint256,
bytes32
)
{
uint256 spentIndex = index / 255; // Note: Reserves the MSB.
uint256 bitOffset = index % 255;
bytes32 replay = spent[spentIndex];
return (spentIndex, bitOffset, replay);
}

function _isSpent(uint256 bitOffset, bytes32 replay) internal pure returns (bool) {
return ((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0);
}

function isSpent(uint256 index) external view returns (bool) {
(, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);
return _isSpent(bitOffset, replay);
}

function recordOutputAsSpent(
bytes32[] memory proof,
uint256 index,
Expand All @@ -219,11 +243,9 @@ contract Outbox is DelegateCallAware, IOutbox {
bytes32 calcRoot = calculateMerkleRoot(proof, index, item);
if (roots[calcRoot] == bytes32(0)) revert UnknownRoot(calcRoot);

uint256 spentIndex = index / 255; // Note: Reserves the MSB.
uint256 bitOffset = index % 255;
(uint256 spentIndex, uint256 bitOffset, bytes32 replay) = _calcSpentIndexOffset(index);

bytes32 replay = spent[spentIndex];
if (((replay >> bitOffset) & bytes32(uint256(1))) != bytes32(0)) revert AlreadySpent(index);
if (_isSpent(bitOffset, replay)) revert AlreadySpent(index);
spent[spentIndex] = (replay | bytes32(1 << bitOffset));
}

Expand Down