synapsecns/sanguine

View on GitHub
packages/contracts-core/test/utils/libs/Random.t.sol

Summary

Maintainability
Test Coverage
// 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();
    }
}