Commit 9b464f1d authored by Kelvin Fichter's avatar Kelvin Fichter

Added comments to more contracts, added account abstraction

parent b439747a
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol";
/**
* @title OVM_ECDSAContractAccount
*/
contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
/********************
* Public Functions *
********************/
/**
* Executes a signed transaction.
* @param _transaction Signed EOA transaction.
* @param _signatureType Hashing scheme used for the transaction (e.g., ETH signed message).
* @param _v Signature `v` parameter.
* @param _r Signature `r` parameter.
* @param _s Signature `s` parameter.
* @return _success Whether or not the call returned (rather than reverted).
* @return _returndata Data returned by the call.
*/
function execute(
bytes memory _transaction,
Lib_OVMCodec.EOASignatureType _signatureType,
uint8 _v,
bytes32 _r,
bytes32 _s
)
override
public
returns (
bool _success,
bytes memory _returndata
)
{
iOVM_ExecutionManager ovmExecutionManager = iOVM_ExecutionManager(msg.sender);
// Address of this contract within the ovm (ovmADDRESS) should be the same as the
// recovered address of the user who signed this message. This is how we manage to shim
// account abstraction even though the user isn't a contract.
require(
Lib_ECDSAUtils.recover(
_transaction,
_signatureType == Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE,
_v,
_r,
_s,
ovmExecutionManager.ovmCHAINID()
) == ovmExecutionManager.ovmADDRESS(),
"Signature provided for EOA transaction execution is invalid."
);
Lib_OVMCodec.EOATransaction memory decodedTx = Lib_OVMCodec.decodeEOATransaction(_transaction);
// Need to make sure that the transaction nonce is right and bump it if so.
require(
decodedTx.nonce == ovmExecutionManager.ovmGETNONCE() + 1,
"Transaction nonce does not match the expected nonce."
);
ovmExecutionManager.ovmSETNONCE(decodedTx.nonce);
// Contract creations are signalled by sending a transaction to the zero address.
if (decodedTx.target == address(0)) {
address created = ovmExecutionManager.ovmCREATE{gas: decodedTx.gasLimit}(
decodedTx.data
);
// EVM doesn't tell us whether a contract creation failed, even if it reverted during
// initialization. Always return `true` for our success value here.
return (true, abi.encode(created));
} else {
return ovmExecutionManager.ovmCALL(
decodedTx.gasLimit,
decodedTx.target,
decodedTx.data
);
}
}
}
......@@ -3,14 +3,17 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol";
/* Interface Imports */
import { iOVM_DataTypes } from "../../iOVM/codec/iOVM_DataTypes.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol";
/* Contract Imports */
import { OVM_ECDSAContractAccount } from "../accounts/OVM_ECDSAContractAccount.sol";
/**
* @title OVM_ExecutionManager
*/
......@@ -93,7 +96,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
* @param _ovmStateManager iOVM_StateManager implementation providing account state.
*/
function run(
iOVM_DataTypes.OVMTransactionData memory _transaction,
Lib_OVMCodec.Transaction memory _transaction,
address _ovmStateManager
)
override
......@@ -235,7 +238,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
// Generate the correct CREATE address.
address contractAddress = Lib_EthUtils.getAddressForCREATE(
creator,
_getAccount(creator).nonce
_getAccountNonce(creator)
);
_createContract(
......@@ -282,6 +285,101 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
}
/*******************************
* Account Abstraction Opcodes *
******************************/
/**
* Retrieves the nonce of the current ovmADDRESS.
* @return _nonce Nonce of the current contract.
*/
function ovmGETNONCE()
override
public
returns (
uint256 _nonce
)
{
return _getAccountNonce(ovmADDRESS());
}
/**
* Sets the nonce of the current ovmADDRESS.
* @param _nonce New nonce for the current contract.
*/
function ovmSETNONCE(
uint256 _nonce
)
override
public
{
if (_nonce <= ovmGETNONCE()) {
return;
}
_setAccountNonce(ovmADDRESS(), _nonce);
}
/**
* Creates a new EOA contract account, for account abstraction.
* @dev Essentially functions like ovmCREATE or ovmCREATE2, but we can bypass a lot of checks
* because the contract we're creating is trusted (no need to do safety checking or to
* handle unexpected reverts). Doesn't need to return an address because the address is
* assumed to be the user's actual address.
* @param _messageHash Hash of a message signed by some user, for verification.
* @param _v Signature `v` parameter.
* @param _r Signature `r` parameter.
* @param _s Signature `s` parameter.
*/
function ovmCREATEEOA(
bytes32 _messageHash,
uint8 _v,
bytes32 _r,
bytes32 _s
)
override
public
{
// Recover the EOA address from the message hash and signature parameters. Since we do the
// hashing in advance, we don't have handle different message hashing schemes. Even if this
// function were to return the wrong address (rather than explicitly returning the zero
// address), the rest of the transaction would simply fail (since there's no EOA account to
// actually execute the transaction).
address eoa = ecrecover(
_messageHash,
(_v - uint8(ovmCHAINID()) * 2) - 8,
_r,
_s
);
// Invalid signature is a case we proactively handle with a revert. We could alternatively
// have this function return a `success` boolean, but this is just easier.
if (eoa == address(0)) {
ovmREVERT(bytes("Signature provided for EOA contract creation is invalid."));
}
// If the user already has an EOA account, then there's no need to perform this operation.
if (_hasAccount(eoa) == true) {
return;
}
// We always need to initialize the contract with the default account values.
_initPendingAccount(eoa);
// Now actually create the account and get its bytecode. We're not worried about reverts
// (other than out of gas, which we can't capture anyway) because this contract is trusted.
OVM_ECDSAContractAccount eoaContractAccount = new OVM_ECDSAContractAccount();
bytes memory deployedCode = Lib_EthUtils.getCode(address(eoaContractAccount));
// Commit the account with its final values.
_commitPendingAccount(
eoa,
address(eoaContractAccount),
keccak256(deployedCode)
);
}
/*********************************
* Opcodes: Contract Interaction *
*********************************/
......@@ -470,7 +568,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
uint256 length = _length == 1 ? 2 : _length;
return Lib_EthUtils.getCode(
_getAccount(_contract).ethAddress,
_getAccountEthAddress(_contract),
_offset,
_length
);
......@@ -491,7 +589,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
)
{
return Lib_EthUtils.getCodeSize(
_getAccount(_contract).ethAddress
_getAccountEthAddress(_contract)
);
}
......@@ -510,7 +608,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
)
{
return Lib_EthUtils.getCodeHash(
_getAccount(_contract).ethAddress
_getAccountEthAddress(_contract)
);
}
......@@ -599,7 +697,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
internal
{
// We always update the nonce of the creating account, even if the creation fails.
_incrementAccountNonce(ovmADDRESS());
_setAccountNonce(ovmADDRESS(), 1);
// We're stepping into a CREATE or CREATE2, so we need to update ADDRESS to point
// to the contract's associated address.
......@@ -648,7 +746,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
return _handleExternalInteraction(
_nextMessageContext,
_gasLimit,
_getAccount(_contract).ethAddress,
_getAccountEthAddress(_contract),
_calldata
);
}
......@@ -749,54 +847,69 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
******************************************/
/**
* Retrieves an account from the OVM_StateManager.
* @param _address Address of the account to retrieve.
* @return _account Retrieved account object.
* Checks whether an account exists within the OVM_StateManager.
* @param _address Address of the account to check.
* @return _exists Whether or not the account exists.
*/
function _getAccount(
function _hasAccount(
address _address
)
internal
returns (
iOVM_DataTypes.OVMAccount memory _account
bool _exists
)
{
// We need to make sure that the transaction isn't trying to access an account that hasn't
// been provided to the OVM_StateManager. We'll immediately abort if this is the case.
_checkInvalidStateAccess(
ovmStateManager.hasAccount(_address)
);
// Check whether the account has been loaded before and mark it as loaded if not. We need
// this because "nuisance gas" only applies to the first time that an account is loaded.
(
bool _wasAccountAlreadyLoaded
) = ovmStateManager.testAndSetAccountLoaded(_address);
// Actually retrieve the account.
iOVM_DataTypes.OVMAccount memory account = ovmStateManager.getAccount(_address);
_checkAccountLoad(_address);
return ovmStateManager.hasAccount(_address);
}
// If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyLoaded == false) {
_useNuisanceGas(
Lib_EthUtils.getCodeSize(account.ethAddress) * NUISANCE_GAS_PER_CONTRACT_BYTE
);
}
/**
* Sets the nonce of an account.
* @param _address Address of the account to modify.
* @param _nonce New account nonce.
*/
function _setAccountNonce(
address _address,
uint256 _nonce
)
internal
{
_checkAccountChange(_address);
ovmStateManager.setAccountNonce(_address, _nonce);
}
return account;
/**
* Gets the nonce of an account.
* @param _address Address of the account to access.
* @return _nonce Nonce of the account.
*/
function _getAccountNonce(
address _address
)
internal
returns (
uint256 _nonce
)
{
_checkAccountLoad(_address);
return ovmStateManager.getAccountNonce(_address);
}
/**
* Increments the nonce of an account.
* @param _address Address of the account to bump.
* Retrieves the Ethereum address of an account.
* @param _address Address of the account to access.
* @return _ethAddress Corresponding Ethereum address.
*/
function _incrementAccountNonce(
function _getAccountEthAddress(
address _address
)
internal
returns (
address _ethAddress
)
{
ovmStateManager.incrementAccountNonce(_address);
_checkAccountLoad(_address);
ovmStateManager.getAccountEthAddress(_address);
}
/**
......@@ -808,6 +921,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
)
internal
{
_checkAccountChange(_address);
ovmStateManager.initPendingAccount(_address);
}
......@@ -826,21 +940,7 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
)
internal
{
// Check whether the account has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that an account is changed.
(
bool _wasAccountAlreadyChanged
) = ovmStateManager.testAndSetAccountChanged(_address);
// If we hadn't already changed the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyChanged == false) {
_useNuisanceGas(
Lib_EthUtils.getCodeSize(_ethAddress) * NUISANCE_GAS_PER_CONTRACT_BYTE
);
}
// Actually commit the contract.
_checkAccountChange(_address);
ovmStateManager.commitPendingAccount(
_address,
_ethAddress,
......@@ -862,6 +962,95 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
returns (
bytes32 _value
)
{
_checkContractStorageLoad(_contract, _key);
return ovmStateManager.getContractStorage(_contract, _key);
}
/**
* Sets the value of a storage slot.
* @param _contract Address of the contract to modify.
* @param _key 32 byte key of the storage slot.
* @param _value 32 byte storage slot value.
*/
function _putContractStorage(
address _contract,
bytes32 _key,
bytes32 _value
)
internal
{
_checkContractStorageChange(_contract, _key);
ovmStateManager.putContractStorage(_contract, _key, _value);
}
/**
* Validation whenever a contract needs to be loaded. Checks that the account exists, charges
* nuisance gas if the account hasn't been loaded before.
* @param _address Address of the account to load.
*/
function _checkAccountLoad(
address _address
)
internal
{
// We need to make sure that the transaction isn't trying to access an account that hasn't
// been provided to the OVM_StateManager. We'll immediately abort if this is the case.
_checkInvalidStateAccess(
ovmStateManager.hasAccount(_address)
);
// Check whether the account has been loaded before and mark it as loaded if not. We need
// this because "nuisance gas" only applies to the first time that an account is loaded.
(
bool _wasAccountAlreadyLoaded
) = ovmStateManager.testAndSetAccountLoaded(_address);
// If we hadn't already loaded the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyLoaded == false) {
_useNuisanceGas(
Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE
);
}
}
/**
* Validation whenever a contract needs to be changed. Checks that the account exists, charges
* nuisance gas if the account hasn't been changed before.
* @param _address Address of the account to change.
*/
function _checkAccountChange(
address _address
)
internal
{
// Check whether the account has been changed before and mark it as changed if not. We need
// this because "nuisance gas" only applies to the first time that an account is changed.
(
bool _wasAccountAlreadyChanged
) = ovmStateManager.testAndSetAccountChanged(_address);
// If we hadn't already changed the account, then we'll need to charge "nuisance gas" based
// on the size of the contract code.
if (_wasAccountAlreadyChanged == false) {
_useNuisanceGas(
Lib_EthUtils.getCodeSize(_getAccountEthAddress(_address)) * NUISANCE_GAS_PER_CONTRACT_BYTE
);
}
}
/**
* Validation whenever a slot needs to be loaded. Checks that the account exists, charges
* nuisance gas if the slot hasn't been loaded before.
* @param _contract Address of the account to load from.
* @param _key 32 byte key to load.
*/
function _checkContractStorageLoad(
address _contract,
bytes32 _key
)
internal
{
// We need to make sure that the transaction isn't trying to access storage that hasn't
// been provided to the OVM_StateManager. We'll immediately abort if this is the case.
......@@ -880,21 +1069,17 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
if (_wasContractStorageAlreadyLoaded == false) {
_useNuisanceGas(NUISANCE_GAS_SLOAD);
}
// Actually retrieve the storage slot.
return ovmStateManager.getContractStorage(_contract, _key);
}
/**
* Sets the value of a storage slot.
* @param _contract Address of the contract to modify.
* @param _key 32 byte key of the storage slot.
* @param _value 32 byte storage slot value.
* Validation whenever a slot needs to be changed. Checks that the account exists, charges
* nuisance gas if the slot hasn't been changed before.
* @param _contract Address of the account to change.
* @param _key 32 byte key to change.
*/
function _putContractStorage(
function _checkContractStorageChange(
address _contract,
bytes32 _key,
bytes32 _value
bytes32 _key
)
internal
{
......@@ -909,9 +1094,6 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
if (_wasContractStorageAlreadyChanged == false) {
_useNuisanceGas(NUISANCE_GAS_SSTORE);
}
// Actually modify the storage slot.
ovmStateManager.putContractStorage(_contract, _key, _value);
}
......
......@@ -4,7 +4,20 @@ pragma solidity ^0.7.0;
/* Interface Imports */
import { iOVM_SafetyChecker } from "../../iOVM/execution/iOVM_SafetyChecker.sol";
/**
* @title OVM_SafetyChecker
*/
contract OVM_SafetyChecker is iOVM_SafetyChecker {
/********************
* Public Functions *
********************/
/**
* Checks that a given bytecode string is considered safe.
* @param _bytecode Bytecode string to check.
* @return _safe Whether or not the bytecode is safe.
*/
function isBytecodeSafe(
bytes memory _bytecode
)
......
......@@ -2,26 +2,39 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_DataTypes } from "../../iOVM/codec/iOVM_DataTypes.sol";
/**
* @title OVM_StateManager
*/
contract OVM_StateManager is iOVM_StateManager {
enum ItemState {
ITEM_UNTOUCHED,
ITEM_LOADED,
ITEM_CHANGED
}
mapping (address => iOVM_DataTypes.OVMAccount) public accounts;
mapping (address => iOVM_DataTypes.OVMAccount) public pendingAccounts;
mapping (address => mapping (bytes32 => bytes32)) public contractStorage;
mapping (address => mapping (bytes32 => bool)) public verifiedContractStorage;
mapping (bytes32 => ItemState) public itemStates;
/****************************************
* Contract Variables: Internal Storage *
****************************************/
mapping (address => Lib_OVMCodec.Account) internal accounts;
mapping (address => mapping (bytes32 => bytes32)) internal contractStorage;
mapping (address => mapping (bytes32 => bool)) internal verifiedContractStorage;
mapping (bytes32 => ItemState) internal itemStates;
/************************************
* Public Functions: Account Access *
************************************/
/**
* Inserts an account into the state.
* @param _address Address of the account to insert.
* @param _account Account to insert for the given address.
*/
function putAccount(
address _address,
iOVM_DataTypes.OVMAccount memory _account
Lib_OVMCodec.Account memory _account
)
override
public
......@@ -29,16 +42,26 @@ contract OVM_StateManager is iOVM_StateManager {
accounts[_address] = _account;
}
/**
* Retrieves an account from the state.
* @param _address Address of the account to retrieve.
* @return _account Account for the given address.
*/
function getAccount(address _address)
override
public
returns (
iOVM_DataTypes.OVMAccount memory _account
Lib_OVMCodec.Account memory _account
)
{
return accounts[_address];
}
/**
* Checks whether the state has a given account.
* @param _address Address of the account to check.
* @return _exists Whether or not the state has the account.
*/
function hasAccount(
address _address
)
......@@ -48,29 +71,79 @@ contract OVM_StateManager is iOVM_StateManager {
bool _exists
)
{
return getAccount(_address).codeHash != bytes32(0);
return accounts[_address].codeHash != bytes32(0);
}
/**
* Sets the nonce of an account.
* @param _address Address of the account to modify.
* @param _nonce New account nonce.
*/
function setAccountNonce(
address _address,
uint256 _nonce
)
override
public
{
accounts[_address].nonce = _nonce;
}
function incrementAccountNonce(
/**
* Gets the nonce of an account.
* @param _address Address of the account to access.
* @return _nonce Nonce of the account.
*/
function getAccountNonce(
address _address
)
override
public
returns (
uint256 _nonce
)
{
accounts[_address].nonce += 1;
return accounts[_address].nonce;
}
/**
* Retrieves the Ethereum address of an account.
* @param _address Address of the account to access.
* @return _ethAddress Corresponding Ethereum address.
*/
function getAccountEthAddress(
address _address
)
override
public
returns (
address _ethAddress
)
{
return accounts[_address].ethAddress;
}
/**
* Initializes a pending account (during CREATE or CREATE2) with the default values.
* @param _address Address of the account to initialize.
*/
function initPendingAccount(
address _address
)
override
public
{
iOVM_DataTypes.OVMAccount storage account = accounts[_address];
Lib_OVMCodec.Account storage account = accounts[_address];
account.nonce = 1;
account.codeHash = keccak256(hex'80');
}
/**
* Finalizes the creation of a pending account (during CREATE or CREATE2).
* @param _address Address of the account to finalize.
* @param _ethAddress Address of the account's associated contract on Ethereum.
* @param _codeHash Hash of the account's code.
*/
function commitPendingAccount(
address _address,
address _ethAddress,
......@@ -79,11 +152,62 @@ contract OVM_StateManager is iOVM_StateManager {
override
public
{
iOVM_DataTypes.OVMAccount storage account = accounts[_address];
Lib_OVMCodec.Account storage account = accounts[_address];
account.ethAddress = _ethAddress;
account.codeHash = _codeHash;
}
/**
* Checks whether an account has already been retrieved, and marks it as retrieved if not.
* @param _address Address of the account to check.
* @return _wasAccountAlreadyLoaded Whether or not the account was already loaded.
*/
function testAndSetAccountLoaded(
address _address
)
override
public
returns (
bool _wasAccountAlreadyLoaded
)
{
return _testItemState(
keccak256(abi.encodePacked(_address)),
ItemState.ITEM_LOADED
);
}
/**
* Checks whether an account has already been modified, and marks it as modified if not.
* @param _address Address of the account to check.
* @return _wasAccountAlreadyChanged Whether or not the account was already modified.
*/
function testAndSetAccountChanged(
address _address
)
override
public
returns (
bool _wasAccountAlreadyChanged
)
{
return _testItemState(
keccak256(abi.encodePacked(_address)),
ItemState.ITEM_CHANGED
);
}
/************************************
* Public Functions: Storage Access *
************************************/
/**
* Changes a contract storage slot value.
* @param _contract Address of the contract to modify.
* @param _key 32 byte storage slot key.
* @param _value 32 byte storage slot value.
*/
function putContractStorage(
address _contract,
bytes32 _key,
......@@ -96,6 +220,12 @@ contract OVM_StateManager is iOVM_StateManager {
verifiedContractStorage[_contract][_key] = true;
}
/**
* Retrieves a contract storage slot value.
* @param _contract Address of the contract to access.
* @param _key 32 byte storage slot key.
* @return _value 32 byte storage slot value.
*/
function getContractStorage(
address _contract,
bytes32 _key
......@@ -109,6 +239,12 @@ contract OVM_StateManager is iOVM_StateManager {
return contractStorage[_contract][_key];
}
/**
* Checks whether a contract storage slot exists in the state.
* @param _contract Address of the contract to access.
* @param _key 32 byte storage slot key.
* @return _exists Whether or not the key was set in the state.
*/
function hasContractStorage(
address _contract,
bytes32 _key
......@@ -121,37 +257,13 @@ contract OVM_StateManager is iOVM_StateManager {
{
return verifiedContractStorage[_contract][_key];
}
function testAndSetAccountLoaded(
address _address
)
override
public
returns (
bool _wasAccountAlreadyLoaded
)
{
return _testItemState(
keccak256(abi.encodePacked(_address)),
ItemState.ITEM_LOADED
);
}
function testAndSetAccountChanged(
address _address
)
override
public
returns (
bool _wasAccountAlreadyChanged
)
{
return _testItemState(
keccak256(abi.encodePacked(_address)),
ItemState.ITEM_CHANGED
);
}
/**
* Checks whether a storage slot has already been retrieved, and marks it as retrieved if not.
* @param _contract Address of the contract to check.
* @param _key 32 byte storage slot key.
* @return _wasContractStorageAlreadyLoaded Whether or not the slot was already loaded.
*/
function testAndSetContractStorageLoaded(
address _contract,
bytes32 _key
......@@ -168,6 +280,12 @@ contract OVM_StateManager is iOVM_StateManager {
);
}
/**
* Checks whether a storage slot has already been modified, and marks it as modified if not.
* @param _contract Address of the contract to check.
* @param _key 32 byte storage slot key.
* @return _wasContractStorageAlreadyChanged Whether or not the slot was already modified.
*/
function testAndSetContractStorageChanged(
address _contract,
bytes32 _key
......@@ -185,10 +303,17 @@ contract OVM_StateManager is iOVM_StateManager {
}
/*
* Internal Functions
*/
/**********************
* Internal Functions *
**********************/
/**
* Checks whether an item is in a particular state (ITEM_LOADED or ITEM_CHANGED) and sets the
* item to the provided state if not.
* @param _item 32 byte item ID to check.
* @param _minItemState Minumum state that must be satisfied by the item.
* @return _wasItemState Whether or not the item was already in the state.
*/
function _testItemState(
bytes32 _item,
ItemState _minItemState
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_ECDSAContractAccount
*/
interface iOVM_ECDSAContractAccount {
/********************
* Public Functions *
********************/
function execute(
bytes memory _transaction,
Lib_OVMCodec.EOASignatureType _signatureType,
uint8 _v,
bytes32 _r,
bytes32 _s
) external returns (bool _success, bytes memory _returndata);
}
......@@ -2,10 +2,14 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_DataTypes } from "../codec/iOVM_DataTypes.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
interface iOVM_ExecutionManager {
/*******************
* Data Structures *
*******************/
enum RevertFlag {
DID_NOT_REVERT,
OUT_OF_GAS,
......@@ -42,8 +46,13 @@ interface iOVM_ExecutionManager {
RevertFlag revertFlag;
}
/************************************
* Transaction Execution Entrypoint *
************************************/
function run(
iOVM_DataTypes.OVMTransactionData calldata _transaction,
Lib_OVMCodec.Transaction calldata _transaction,
address _txStateManager
) external;
......@@ -73,7 +82,15 @@ interface iOVM_ExecutionManager {
function ovmCREATE(bytes memory _bytecode) external returns (address _contract);
function ovmCREATE2(bytes memory _bytecode, bytes32 _salt) external returns (address _contract);
function safeCREATE(address _address, bytes memory _bytecode) external;
/*******************************
* Account Abstraction Opcodes *
******************************/
function ovmGETNONCE() external returns (uint256 _nonce);
function ovmSETNONCE(uint256 _nonce) external;
function ovmCREATEEOA(bytes32 _messageHash, uint8 _v, bytes32 _r, bytes32 _s) external;
/****************************
......@@ -100,4 +117,11 @@ interface iOVM_ExecutionManager {
function ovmEXTCODECOPY(address _contract, uint256 _offset, uint256 _length) external returns (bytes memory _code);
function ovmEXTCODESIZE(address _contract) external returns (uint256 _size);
function ovmEXTCODEHASH(address _contract) external returns (bytes32 _hash);
/**************************************
* Public Functions: Execution Safety *
**************************************/
function safeCREATE(address _address, bytes memory _bytecode) external;
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
/**
* @title iOVM_SafetyChecker
*/
interface iOVM_SafetyChecker {
/********************
* Public Functions *
********************/
function isBytecodeSafe(bytes memory _bytecode) external view returns (bool _safe);
}
......@@ -2,25 +2,48 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Interface Imports */
import { iOVM_DataTypes } from "../codec/iOVM_DataTypes.sol";
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title iOVM_StateManager
*/
interface iOVM_StateManager {
function putAccount(address _address, iOVM_DataTypes.OVMAccount memory _account) external;
function getAccount(address _address) external returns (iOVM_DataTypes.OVMAccount memory _account);
/*******************
* Data Structures *
*******************/
enum ItemState {
ITEM_UNTOUCHED,
ITEM_LOADED,
ITEM_CHANGED
}
/************************************
* Public Functions: Account Access *
************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external;
function getAccount(address _address) external returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external returns (bool _exists);
function incrementAccountNonce(address _address) external;
function setAccountNonce(address _address, uint256 _nonce) external;
function getAccountNonce(address _address) external returns (uint256 _nonce);
function getAccountEthAddress(address _address) external returns (address _ethAddress);
function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
/************************************
* Public Functions: Storage Access *
************************************/
function putContractStorage(address _contract, bytes32 _key, bytes32 _value) external;
function getContractStorage(address _contract, bytes32 _key) external returns (bytes32 _value);
function hasContractStorage(address _contract, bytes32 _key) external returns (bool _exists);
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
function testAndSetAccountChanged(address _address) external returns (bool _wasAccountAlreadyChanged);
function testAndSetContractStorageLoaded(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyLoaded);
function testAndSetContractStorageChanged(address _contract, bytes32 _key) external returns (bool _wasContractStorageAlreadyChanged);
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
interface iOVM_DataTypes {
struct OVMAccount {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
address ethAddress;
}
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
/**
* @title Lib_OVMCodec
*/
library Lib_OVMCodec {
/*******************
* Data Structures *
*******************/
struct EVMAccount {
struct Account {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
address ethAddress;
}
struct OVMChainBatchHeader {
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
......@@ -25,12 +30,12 @@ interface iOVM_DataTypes {
bytes extraData;
}
struct OVMChainInclusionProof {
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}
struct OVMTransactionData {
struct Transaction {
uint256 timestamp;
uint256 queueOrigin;
address entrypoint;
......@@ -40,16 +45,57 @@ interface iOVM_DataTypes {
bytes data;
}
struct OVMProofMatrix {
struct ProofMatrix {
bool checkNonce;
bool checkBalance;
bool checkStorageRoot;
bool checkCodeHash;
}
struct OVMQueueElement {
struct QueueElement {
uint256 timestamp;
bytes32 batchRoot;
bool isL1ToL2Batch;
}
struct EOATransaction {
address target;
uint256 nonce;
uint256 gasLimit;
bytes data;
}
enum EOASignatureType {
ETH_SIGNED_MESSAGE,
NATIVE_TRANSACTON
}
/*********************************************
* Internal Functions: Encoding and Decoding *
*********************************************/
/**
* Decodes an EOA transaction (i.e., native Ethereum RLP encoding).
* @param _transaction Encoded EOA transaction.
* @return _decoded Transaction decoded into a struct.
*/
function decodeEOATransaction(
bytes memory _transaction
)
internal
pure
returns (
EOATransaction memory _decoded
)
{
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.toList(Lib_RLPReader.toRlpItem(_transaction));
return EOATransaction({
nonce: Lib_RLPReader.toUint(decoded[0]),
gasLimit: Lib_RLPReader.toUint(decoded[2]),
target: Lib_RLPReader.toAddress(decoded[3]),
data: Lib_RLPReader.toBytes(decoded[5])
});
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
/**
* @title Lib_ECDSAUtils
*/
library Lib_ECDSAUtils {
/**************************************
* Internal Functions: ECDSA Recovery *
**************************************/
/**
* Recovers a signed address given a message and signature.
* @param _message Message that was originally signed.
* @param _isEthSignedMessage Whether or not the user used the `Ethereum Signed Message` prefix.
* @param _v Signature `v` parameter.
* @param _r Signature `r` parameter.
* @param _s Signature `s` parameter.
* @param _chainId Chain ID parameter.
* @return _sender Signer address.
*/
function recover(
bytes memory _message,
bool _isEthSignedMessage,
uint8 _v,
bytes32 _r,
bytes32 _s,
uint256 _chainId
)
internal
pure
returns (
address _sender
)
{
bytes32 messageHash;
if (_isEthSignedMessage) {
messageHash = getEthSignedMessageHash(_message);
} else {
messageHash = getNativeMessageHash(_message);
}
return ecrecover(
messageHash,
(_v - uint8(_chainId) * 2) - 8,
_r,
_s
);
}
/*************************************
* Private Functions: ECDSA Recovery *
*************************************/
/**
* Gets the native message hash (simple keccak256) for a message.
* @param _message Message to hash.
* @return _messageHash Native message hash.
*/
function getNativeMessageHash(
bytes memory _message
)
private
pure
returns (
bytes32 _messageHash
)
{
return keccak256(_message);
}
/**
* Gets the hash of a message with the `Ethereum Signed Message` prefix.
* @param _message Message to hash.
* @return _messageHash Prefixed message hash.
*/
function getEthSignedMessageHash(
bytes memory _message
)
private
pure
returns (
bytes32 _messageHash
)
{
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
bytes32 messageHash = keccak256(_message);
return keccak256(abi.encodePacked(prefix, messageHash));
}
}
\ No newline at end of file
......@@ -5,7 +5,22 @@ pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/**
* @title Lib_EthUtils
*/
library Lib_EthUtils {
/***********************************
* Internal Functions: Code Access *
***********************************/
/**
* Gets the code for a given address.
* @param _address Address to get code for.
* @param _offset Offset to start reading from.
* @param _length Number of bytes to read.
* @return _code Code read from the contract.
*/
function getCode(
address _address,
uint256 _offset,
......@@ -27,6 +42,11 @@ library Lib_EthUtils {
return _code;
}
/**
* Gets the full code for a given address.
* @param _address Address to get code for.
* @return _code Full code of the contract.
*/
function getCode(
address _address
)
......@@ -43,6 +63,11 @@ library Lib_EthUtils {
);
}
/**
* Gets the size of a contract's code in bytes.
* @param _address Address to get code size for.
* @return _codeSize Size of the contract's code in bytes.
*/
function getCodeSize(
address _address
)
......@@ -59,6 +84,11 @@ library Lib_EthUtils {
return _codeSize;
}
/**
* Gets the hash of a contract's code.
* @param _address Address to get a code hash for.
* @return _codeHash Hash of the contract's code.
*/
function getCodeHash(
address _address
)
......@@ -75,6 +105,16 @@ library Lib_EthUtils {
return _codeHash;
}
/*****************************************
* Internal Functions: Contract Creation *
*****************************************/
/**
* Creates a contract with some given initialization code.
* @param _code Contract initialization code.
* @return _created Address of the created contract.
*/
function createContract(
bytes memory _code
)
......@@ -94,6 +134,12 @@ library Lib_EthUtils {
return _created;
}
/**
* Computes the address that would be generated by CREATE.
* @param _creator Address creating the contract.
* @param _nonce Creator's nonce.
* @return _address Address to be generated by CREATE.
*/
function getAddressForCREATE(
address _creator,
uint256 _nonce
......@@ -112,6 +158,13 @@ library Lib_EthUtils {
return getAddressFromHash(keccak256(encodedList));
}
/**
* Computes the address that would be generated by CREATE2.
* @param _creator Address creating the contract.
* @param _bytecode Bytecode of the contract to be created.
* @param _salt 32 byte salt value mixed into the hash.
* @return _address Address to be generated by CREATE2.
*/
function getAddressForCREATE2(
address _creator,
bytes memory _bytecode,
......@@ -131,19 +184,26 @@ library Lib_EthUtils {
return getAddressFromHash(hashedData);
}
/****************************************
* Private Functions: Contract Creation *
****************************************/
/**
* Determines an address from a 32 byte hash. Since addresses are only
* 20 bytes, we need to retrieve the last 20 bytes from the original
* hash. Converting to uint256 and then uint160 gives us these bytes.
* @param _hash Hash to convert to an address.
* @return Hash converted to an address.
* @return _address Hash converted to an address.
*/
function getAddressFromHash(
bytes32 _hash
)
private
pure
returns (address)
returns (
address _address
)
{
return address(bytes20(uint160(uint256(_hash))));
}
......
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Forwarder', () => {
describe('fallback', () => {
})
})
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Manager', () => {
describe('setProxy', () => {
})
describe('getProxy', () => {
})
describe('hasProxy', () => {
})
describe('isProxy', () => {
})
describe('setTarget', () => {
})
describe('getTarget', () => {
})
describe('hasTarget', () => {
})
describe('isTarget', () => {
})
})
import { expect } from '../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract, ContractFactory } from 'ethers'
describe('Proxy_Resolver', () => {
describe('resolve', () => {
})
})
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