This repository has been archived by the owner on Dec 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #526 from rainprotocol/2023-01-22-op-extern
extern op interface extern
- Loading branch information
Showing
14 changed files
with
492 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// SPDX-License-Identifier: CAL | ||
pragma solidity ^0.8.15; | ||
|
||
type EncodedExternDispatch is uint256; | ||
type ExternDispatch is uint256; | ||
|
||
/// @title IInterpreterExternV1 | ||
/// Handle a single dispatch from some calling contract with an array of | ||
/// inputs and array of outputs. Ostensibly useful to build "word packs" for | ||
/// `IInterpreterV1` so that less frequently used words can be provided in | ||
/// a less efficient format, but without bloating the base interpreter in | ||
/// terms of code size. Effectively allows unlimited words to exist as externs | ||
/// alongside interpreters. | ||
interface IInterpreterExternV1 { | ||
/// Handles a single dispatch. | ||
/// @param dispatch_ Encoded information about the extern to dispatch. | ||
/// Analogous to the opcode/operand in the interpreter. | ||
/// @param inputs_ The array of inputs for the dispatched logic. | ||
/// @return outputs_ The result of the dispatched logic. | ||
function extern( | ||
ExternDispatch dispatch_, | ||
uint256[] memory inputs_ | ||
) external view returns (uint256[] memory outputs_); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// SPDX-License-Identifier: CAL | ||
pragma solidity ^0.8.15; | ||
|
||
import "./IInterpreterExternV1.sol"; | ||
|
||
library LibExtern { | ||
function decode( | ||
EncodedExternDispatch dispatch_ | ||
) internal pure returns (IInterpreterExternV1, ExternDispatch) { | ||
return ( | ||
IInterpreterExternV1( | ||
address(uint160(EncodedExternDispatch.unwrap(dispatch_))) | ||
), | ||
ExternDispatch.wrap(EncodedExternDispatch.unwrap(dispatch_) >> 160) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// SPDX-License-Identifier: CAL | ||
pragma solidity ^0.8.15; | ||
|
||
import "../../../math/Binary.sol"; | ||
import "../../deploy/LibIntegrityCheck.sol"; | ||
import "./OpReadMemory.sol"; | ||
import "../../extern/LibExtern.sol"; | ||
import "../../run/LibStackPointer.sol"; | ||
|
||
/// Thrown when the length of results from an extern don't match what the operand | ||
/// defines. This is bad because it implies our integrity check miscalculated the | ||
/// stack which is undefined behaviour. | ||
/// @param expected The length we expected based on the operand. | ||
/// @param actual The length that was returned from the extern. | ||
error BadExternResultsLength(uint256 expected, uint256 actual); | ||
|
||
library OpExtern { | ||
using LibIntegrityCheck for IntegrityCheckState; | ||
using LibStackPointer for StackPointer; | ||
|
||
function integrity( | ||
IntegrityCheckState memory integrityCheckState_, | ||
Operand operand_, | ||
StackPointer stackTop_ | ||
) internal pure returns (StackPointer) { | ||
uint256 inputs_ = Operand.unwrap(operand_) & MASK_5BIT; | ||
uint256 outputs_ = (Operand.unwrap(operand_) >> 5) & MASK_5BIT; | ||
uint256 offset_ = Operand.unwrap(operand_) >> 10; | ||
|
||
if (offset_ >= integrityCheckState_.constantsLength) { | ||
revert OutOfBoundsConstantsRead( | ||
integrityCheckState_.constantsLength, | ||
offset_ | ||
); | ||
} | ||
|
||
return | ||
integrityCheckState_.push( | ||
integrityCheckState_.pop(stackTop_, inputs_), | ||
outputs_ | ||
); | ||
} | ||
|
||
function intern( | ||
InterpreterState memory interpreterState_, | ||
Operand operand_, | ||
StackPointer stackTop_ | ||
) internal view returns (StackPointer) { | ||
IInterpreterExternV1 interpreterExtern_; | ||
ExternDispatch externDispatch_; | ||
uint256 head_; | ||
uint256[] memory tail_; | ||
{ | ||
uint256 inputs_ = Operand.unwrap(operand_) & MASK_5BIT; | ||
uint256 offset_ = (Operand.unwrap(operand_) >> 10); | ||
|
||
// Mirrors constant opcode. | ||
EncodedExternDispatch encodedDispatch_; | ||
assembly ("memory-safe") { | ||
encodedDispatch_ := mload(add( | ||
mload(add(interpreterState_, 0x20)), | ||
mul(0x20, offset_) | ||
)) | ||
} | ||
|
||
(interpreterExtern_, externDispatch_) = LibExtern.decode( | ||
encodedDispatch_ | ||
); | ||
(head_, tail_) = stackTop_.list(inputs_); | ||
stackTop_ = stackTop_.down(inputs_).down().push(head_); | ||
} | ||
|
||
{ | ||
uint256 outputs_ = (Operand.unwrap(operand_) >> 5) & MASK_5BIT; | ||
|
||
uint256[] memory results_ = interpreterExtern_.extern( | ||
externDispatch_, | ||
tail_ | ||
); | ||
|
||
if (results_.length != outputs_) { | ||
revert BadExternResultsLength(outputs_, results_.length); | ||
} | ||
|
||
stackTop_ = stackTop_.push(results_); | ||
} | ||
|
||
return stackTop_; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// SPDX-License-Identifier: CAL | ||
pragma solidity ^0.8.15; | ||
|
||
import "../extern/IInterpreterExternV1.sol"; | ||
import "../ops/chainlink/OpChainlinkOraclePrice.sol"; | ||
import "../run/LibStackPointer.sol"; | ||
import "../../array/LibUint256Array.sol"; | ||
|
||
/// Thrown when the inputs don't match the expected inputs. | ||
error BadInputs(uint256 expected, uint256 actual); | ||
|
||
/// EXPERIMENTAL implementation of `IInterpreterExternV1`. | ||
/// Currently only implements the Chainlink oracle price opcode as a starting | ||
/// point to test and flesh out externs generally. | ||
/// Hopefully one day the idea of there being only a single extern contract seems | ||
/// quaint. | ||
contract RainterpreterExtern is IInterpreterExternV1 { | ||
using LibStackPointer for uint256[]; | ||
using LibStackPointer for StackPointer; | ||
using LibUint256Array for uint256; | ||
|
||
/// @inheritdoc IInterpreterExternV1 | ||
function extern( | ||
ExternDispatch, | ||
uint256[] memory inputs_ | ||
) external view returns (uint256[] memory) { | ||
if (inputs_.length != 2) { | ||
revert BadInputs(2, inputs_.length); | ||
} | ||
return | ||
inputs_ | ||
.asStackPointerAfter() | ||
.applyFn(OpChainlinkOraclePrice.f) | ||
.peek() | ||
.arrayFrom(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.