Commit 3e4e0be0 authored by clabby's avatar clabby

Load data in oracle

parent d6f80baf
......@@ -575,4 +575,3 @@ TransactorTest:test_constructor_succeeds() (gas: 9739)
TransactorTest:test_delegateCall_succeeds() (gas: 20909)
TransactorTest:test_delegateCall_unauthorized_reverts() (gas: 16550)
TransferOnionTest:test_constructor_succeeds() (gas: 564855)
TransferOnionTest:test_unwrap_succeeds() (gas: 724955)
\ No newline at end of file
......@@ -51,29 +51,87 @@ contract PreimageOracle {
preimageLengths[key] = size;
}
/// @notice Computes and returns the key for a pre-image.
/// @param _preimage The pre-image.
/// @return key_ The pre-image key.
function computePreimageKey(bytes calldata _preimage) external pure returns (bytes32 key_) {
/// @notice Loads local data into the pre-image oracle in the context of the caller.
/// @param _bootInfo The boot info struct encoded as a tuple of .
function loadLocalData(bytes memory _bootInfo) external {
(
bytes32 l1head,
bytes32 l2head,
bytes32 l2claim,
uint64 l2ClaimBlockNumber,
bytes memory l2ChainConfig,
bytes memory rollupConfig
) = abi.decode(_bootInfo, (bytes32, bytes32, bytes32, uint64, bytes, bytes));
assembly {
let size := calldataload(0x24)
/// Store a value in a mapping
function storeInMapping(k, v, mappingSlot) {
// Value slot: `keccak256(k . mappingSlot)`
mstore(0x00, k)
mstore(0x20, mappingSlot)
sstore(keccak256(0x00, 0x40), v)
}
// Leave slots 0x40 and 0x60 untouched,
// and everything after as scratch-memory.
let ptr := 0x80
/// Store a value in a nested mapping
function storeInNestedMapping(ka, kb, v, mappingSlot) {
// Compute the slot of the nested mapping
mstore(0x00, ka)
mstore(0x20, mappingSlot)
let nestedSlot := keccak256(0x00, 0x40)
// Compute the slot of the value & store it
mstore(0x00, kb)
mstore(0x20, nestedSlot)
sstore(keccak256(0x00, 0x40), v)
}
// Store size as a big-endian uint64 at the start of pre-image
mstore(ptr, shl(192, size))
ptr := add(ptr, 8)
/// Compute the context-specifc key for a given local data identifier
function contextKey(ident) -> key {
// Store the global key (1 << 248 | ident)
mstore(0, or(shl(248, 1), ident))
// Store the caller to add context to the local data's global key
mstore(0x20, caller())
// Hash the data to get the context-specific key
// localize(k) = H(k .. sender) & ~(0xFF << 248) | (1 << 248)
key := or(and(keccak256(0, 0x40), not(shl(248, 0xFF))), shl(248, 1))
}
// Copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, _preimage.offset, size)
/// Store a fixed-size piece of local data
function storeFixed(ident, offset, size, data) {
// Grab the context key for the given `ident`
let k := contextKey(ident)
// Compute the pre-image keccak256 hash (aka the pre-image key)
let h := keccak256(ptr, size)
// Store the fixed data
storeInNestedMapping(k, offset, true, preimagePartOk.slot)
storeInNestedMapping(k, offset, data, preimageParts.slot)
storeInMapping(k, size, preimageLengths.slot)
}
// Mask out prefix byte, replace with type 2 byte
key_ := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
/// Store a dynamic-size piece of local data
function storeDyn(ident, dataOffset) {
// Grab the length of the data
let size := mload(dataOffset)
// Grab the context key for the given `ident`
let k := contextKey(ident)
// Store each component of the preimage key.
let dataStart := add(dataOffset, 0x20)
for { let i := 0 } lt(i, size) { i := add(i, 0x20) } {
// Load the part at the given offset
// TODO(clabby): Verify size.
let part := mload(add(dataStart, i))
storeInNestedMapping(k, i, true, preimagePartOk.slot)
storeInNestedMapping(k, i, part, preimageParts.slot)
storeInMapping(k, size, preimageLengths.slot)
}
}
// Store all components of the boot info.
storeFixed(0, 0, 32, l1head)
storeFixed(1, 0, 32, l2head)
storeFixed(2, 0, 32, l2claim)
storeFixed(3, 0, 32, l2ClaimBlockNumber)
storeDyn(4, l2ChainConfig)
storeDyn(5, rollupConfig)
}
}
......@@ -82,34 +140,59 @@ contract PreimageOracle {
/// @param _partOffset The offset of the pre-image to read.
/// @param _preimage The preimage data.
function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external {
(uint256 size, bytes32 key, bytes32 part) = loadPart(_partOffset, _preimage);
preimagePartOk[key][_partOffset] = true;
preimageParts[key][_partOffset] = part;
preimageLengths[key] = size;
}
function loadPart(uint256 _partOffset, bytes calldata _preimage) internal pure returns (uint256 size_, bytes32 key_, bytes32 part_) {
uint256 size;
bytes32 key;
bytes32 part;
assembly {
// len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44
size_ := calldataload(0x44)
size := calldataload(0x44)
// revert if part offset > size+8 (i.e. parts must be within bounds)
if gt(_partOffset, add(size_, 8)) {
if gt(_partOffset, add(size, 8)) {
revert(0, 0)
}
// we leave solidity slots 0x40 and 0x60 untouched,
// and everything after as scratch-memory.
let ptr := 0x80
// put size as big-endian uint64 at start of pre-image
mstore(ptr, shl(192, size_))
mstore(ptr, shl(192, size))
ptr := add(ptr, 8)
// copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, _preimage.offset, size_)
calldatacopy(ptr, _preimage.offset, size)
// Note that it includes the 8-byte big-endian uint64 length prefix.
// this will be zero-padded at the end, since memory at end is clean.
part_ := mload(add(sub(ptr, 8), _partOffset))
let h := keccak256(ptr, size_) // compute preimage keccak256 hash
part := mload(add(sub(ptr, 8), _partOffset))
let h := keccak256(ptr, size) // compute preimage keccak256 hash
// mask out prefix byte, replace with type 2 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
}
preimagePartOk[key][_partOffset] = true;
preimageParts[key][_partOffset] = part;
preimageLengths[key] = size;
}
/// @notice Computes and returns the key for a global keccak pre-image.
/// @param _preimage The pre-image.
/// @return key_ The pre-image key.
function computeKeccak256PreimageKey(bytes calldata _preimage) external pure returns (bytes32 key_) {
assembly {
let size := calldataload(0x24)
// Leave slots 0x40 and 0x60 untouched,
// and everything after as scratch-memory.
let ptr := 0x80
// Store size as a big-endian uint64 at the start of pre-image
mstore(ptr, shl(192, size))
ptr := add(ptr, 8)
// Copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, _preimage.offset, size)
// Compute the pre-image keccak256 hash (aka the pre-image key)
let h := keccak256(ptr, size)
// Mask out prefix byte, replace with type 2 byte
key_ := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
}
}
......
......@@ -93,7 +93,9 @@ contract DisputeGameFactory is OwnableUpgradeable, IDisputeGameFactory, Semver {
}
// Clone the implementation contract and initialize it with the given parameters.
proxy = IDisputeGame(address(impl).clone(abi.encodePacked(rootClaim, extraData.length, extraData)));
proxy = IDisputeGame(
address(impl).clone(abi.encodePacked(rootClaim, extraData.length, extraData))
);
proxy.initialize();
// Compute the unique identifier for the dispute game.
......
......@@ -382,6 +382,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
countered: false
})
);
// Load the local data into the preimage oracle.
VM.oracle().loadLocalData(extraData());
}
/// @notice Returns the length of the `claimData` array.
......
......@@ -31,4 +31,15 @@ interface IBigStepper {
function step(bytes calldata _stateData, bytes calldata _proof)
external
returns (bytes32 postState_);
/// @notice Returns the preimage oracle used by the stepper.
function oracle() external view returns (IPreimageOracle oracle_);
}
/// @notice Temporary interface for the `IPreimageOracle`. Remove once we've upgraded
/// the cannon contracts to a newer version of solc.
interface IPreimageOracle {
/// @notice Loads local data into the pre-image oracle in the context of the caller.
/// @param _bootInfo The boot info struct encoded as a tuple of .
function loadLocalData(bytes memory _bootInfo) external;
}
......@@ -7,11 +7,11 @@ import { DisputeGameFactory_Init } from "./DisputeGameFactory.t.sol";
import { DisputeGameFactory } from "../src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame } from "../src/dispute/FaultDisputeGame.sol";
import "../src/libraries/DisputeTypes.sol";
import "../src/libraries/DisputeErrors.sol";
import { LibClock } from "../src/dispute/lib/LibClock.sol";
import { LibPosition } from "../src/dispute/lib/LibPosition.sol";
import { IBigStepper } from "../src/dispute/interfaces/IBigStepper.sol";
import "../libraries/DisputeTypes.sol";
import "../libraries/DisputeErrors.sol";
import { LibClock } from "../dispute/lib/LibClock.sol";
import { LibPosition } from "../dispute/lib/LibPosition.sol";
import { IBigStepper, IPreimageOracle } from "../dispute/interfaces/IBigStepper.sol";
contract FaultDisputeGame_Init is DisputeGameFactory_Init {
/// @dev The extra data passed to the game for initialization.
......@@ -889,9 +889,16 @@ contract VariableDivergentPlayer is GamePlayer {
contract AlphabetVM is IBigStepper {
Claim internal immutable ABSOLUTE_PRESTATE;
IPreimageOracle public oracle;
constructor(Claim _absolutePrestate) {
ABSOLUTE_PRESTATE = _absolutePrestate;
// Deploy a noop preimage oracle
assembly {
mstore(0x00, 0x60016000F3)
let size := 5
sstore(oracle.slot, create(0, sub(0x20, size), size))
}
}
/// @inheritdoc IBigStepper
......
......@@ -17,7 +17,7 @@ contract PreimageOracle_Test is Test {
/// @notice Test the pre-image key computation with a known pre-image.
function test_computePreimageKey_succeeds() public {
bytes memory preimage = hex"deadbeef";
bytes32 key = oracle.computePreimageKey(preimage);
bytes32 key = oracle.computeKeccak256PreimageKey(preimage);
bytes32 known = 0x02fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1;
assertEq(key, known);
}
......@@ -26,7 +26,7 @@ contract PreimageOracle_Test is Test {
function test_loadKeccak256PreimagePart_succeeds() public {
// Set the pre-image
bytes memory preimage = hex"deadbeef";
bytes32 key = oracle.computePreimageKey(preimage);
bytes32 key = oracle.computeKeccak256PreimageKey(preimage);
uint256 offset = 0;
oracle.loadKeccak256PreimagePart(offset, preimage);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment