packages/contracts-core/test/utils/libs/Random.t.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {SNAPSHOT_MAX_STATES} from "../../../contracts/libs/Constants.sol";
import {
RawAttestation,
RawExecReceipt,
RawGasData,
RawGasData256,
RawRequest,
RawState,
RawStateIndex,
RawSnapshot
} from "./SynapseStructs.t.sol";
struct Random {
bytes32 seed;
}
using RandomLib for Random global;
// solhint-disable no-empty-blocks
// solhint-disable ordering
library RandomLib {
/// @notice Prevents this contract from being included in the coverage report
function testRandomLib() external {}
// @notice Returns next "random" bytes32 value and updates the Random's seed.
function next(Random memory r) internal pure returns (bytes32 value) {
value = r.seed;
r.seed = keccak256(bytes.concat(value));
}
// @notice Returns next "random" bytes value of given length and updates the Random's seed.
function nextBytes(Random memory r, uint256 length) internal pure returns (bytes memory value) {
value = new bytes(length);
uint256 words = length / 32;
for (uint256 i = 0; i < words; ++i) {
bytes32 word = r.next();
// TODO: This is probably not the best way to do this - rewrite in assembly
for (uint256 j = 0; j < 32; ++j) {
value[32 * i + j] = word[j];
}
}
uint256 remainder = length % 32;
if (remainder != 0) {
bytes32 word = r.next();
for (uint256 j = 0; j < remainder; ++j) {
value[32 * words + j] = word[j];
}
}
}
// @notice Returns next "random" bytes value having N memory words and updates the Random's seed.
function nextBytesWords(Random memory r, uint256 words) internal pure returns (bytes memory value) {
bytes32[] memory args = new bytes32[](words);
for (uint256 i = 0; i < words; ++i) {
args[i] = r.next();
}
return abi.encodePacked(args);
}
// @notice Returns next "random" uint256 value and updates the Random's seed.
function nextUint256(Random memory r) internal pure returns (uint256 value) {
return uint256(r.next());
}
// @notice Returns next "random" uint192 value and updates the Random's seed.
function nextUint192(Random memory r) internal pure returns (uint192 value) {
return uint192(r.nextUint256());
}
// @notice Returns next "random" uint160 value and updates the Random's seed.
function nextUint160(Random memory r) internal pure returns (uint160 value) {
return uint160(r.nextUint256());
}
// @notice Returns next "random" uint96 value and updates the Random's seed.
function nextUint96(Random memory r) internal pure returns (uint96 value) {
return uint96(r.nextUint256());
}
// @notice Returns next "random" uint64 value and updates the Random's seed.
function nextUint64(Random memory r) internal pure returns (uint64 value) {
return uint64(r.nextUint256());
}
// @notice Returns next "random" uint40 value and updates the Random's seed.
function nextUint40(Random memory r) internal pure returns (uint40 value) {
return uint40(r.nextUint256());
}
// @notice Returns next "random" uint32 value and updates the Random's seed.
function nextUint32(Random memory r) internal pure returns (uint32 value) {
return uint32(r.nextUint256());
}
// @notice Returns next "random" uint16 value and updates the Random's seed.
function nextUint16(Random memory r) internal pure returns (uint16 value) {
return uint16(r.nextUint256());
}
// @notice Returns next "random" uint8 value and updates the Random's seed.
function nextUint8(Random memory r) internal pure returns (uint8 value) {
return uint8(r.nextUint256());
}
// @notice Returns next "random" address value and updates the Random's seed.
function nextAddress(Random memory r) internal pure returns (address value) {
return address(r.nextUint160());
}
function nextSnapshot(Random memory r) internal pure returns (RawSnapshot memory rs) {
uint32 statesAmount = r.nextUint32();
// Should be in range [1, SNAPSHOT_MAX_STATES]
statesAmount = uint32(1 + statesAmount % (SNAPSHOT_MAX_STATES - 1));
return r.nextSnapshot(statesAmount);
}
function nextSnapshot(Random memory r, uint32 statesAmount) internal pure returns (RawSnapshot memory rs) {
rs.states = new RawState[](statesAmount);
for (uint32 i = 0; i < statesAmount; ++i) {
rs.states[i] = r.nextState();
}
}
function nextState(Random memory r, uint32 origin, uint32 nonce) internal pure returns (RawState memory state) {
state.root = r.next();
state.origin = origin;
state.nonce = nonce;
state.blockNumber = r.nextUint40();
state.timestamp = r.nextUint40();
state.gasData = r.nextGasData();
}
function nextState(Random memory r) internal pure returns (RawState memory state) {
return r.nextState(r.nextUint32(), r.nextUint32());
}
function nextGasData256(Random memory r) internal pure returns (RawGasData256 memory rgd256) {
rgd256.gasPrice = r.nextUint256();
rgd256.dataPrice = r.nextUint256();
rgd256.execBuffer = r.nextUint256();
rgd256.amortAttCost = r.nextUint256();
rgd256.etherPrice = r.nextUint256();
rgd256.markup = r.nextUint256();
}
function nextGasData(Random memory r) internal pure returns (RawGasData memory rgd) {
return r.nextGasData256().compress();
}
function nextRequest(Random memory r) internal pure returns (RawRequest memory rr) {
rr.gasDrop = r.nextUint96();
rr.gasLimit = r.nextUint64();
rr.version = r.nextUint32();
}
function nextStateIndex(Random memory r) internal pure returns (RawStateIndex memory rsi) {
rsi.stateIndex = r.nextUint8();
rsi.statesAmount = r.nextUint256();
rsi.boundStateIndex();
}
function nextAttestation(Random memory r, uint32 nonce) internal pure returns (RawAttestation memory ra) {
ra.snapRoot = r.next();
ra._agentRoot = r.next();
ra.nonce = nonce;
ra.blockNumber = r.nextUint40();
ra.timestamp = r.nextUint40();
}
function nextAttestation(Random memory r, RawSnapshot memory rawSnap, uint32 nonce)
internal
view
returns (RawAttestation memory ra)
{
return rawSnap.castToRawAttestation(r.next(), nonce, r.nextUint40(), r.nextUint40());
}
function nextReceipt(Random memory r, uint32 destination) internal pure returns (RawExecReceipt memory re) {
re.origin = r.nextUint32();
re.destination = destination;
re.messageHash = r.next();
re.snapshotRoot = r.next();
re.stateIndex = r.nextUint8();
re.attNotary = r.nextAddress();
re.firstExecutor = r.nextAddress();
re.finalExecutor = r.nextAddress();
}
}