Commit eabb5dd8 authored by Kelvin Fichter's avatar Kelvin Fichter

Lots of library cleanup

parent aa67fe22
......@@ -3,8 +3,9 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_EthMerkleTrie } from "../../libraries/trie/Lib_EthMerkleTrie.sol";
import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_BytesUtils } from "../../libraries/utils/Lib_BytesUtils.sol";
/* Interface Imports */
......@@ -221,11 +222,27 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros
)
);
return Lib_EthMerkleTrie.proveAccountStorageSlotValue(
0x4200000000000000000000000000000000000000,
storageKey,
bytes32(uint256(1)),
(
bool exists,
bytes memory encodedMessagePassingAccount
) = Lib_SecureMerkleTrie.get(
abi.encodePacked(0x4200000000000000000000000000000000000000),
_proof.stateTrieWitness,
_proof.stateRoot
);
require(
exists == true,
"Message passing precompile has not been initialized or invalid proof provided."
);
Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.decodeEVMAccount(
encodedMessagePassingAccount
);
return Lib_SecureMerkleTrie.verifyInclusionProof(
abi.encodePacked(storageKey),
abi.encodePacked(uint256(1)),
_proof.storageTrieWitness,
_proof.stateRoot
);
......
......@@ -1519,10 +1519,12 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
bool _valid
)
{
// Always have to be below the maximum gas limit.
if (_gasLimit > gasMeterConfig.maxTransactionGasLimit) {
return false;
}
// Always have to be above the minumum gas limit.
if (_gasLimit < gasMeterConfig.minTransactionGasLimit) {
return false;
}
......
......@@ -111,6 +111,20 @@ contract OVM_StateManager is iOVM_StateManager {
accounts[_address] = _account;
}
/**
* Marks an account as empty.
* @param _address Address of the account to mark.
*/
function putEmptyAccount(
address _address
)
override
public
authenticated
{
accounts[_address].codeHash = EMPTY_ACCOUNT_CODE_HASH;
}
/**
* Retrieves an account from the state.
* @param _address Address of the account to retrieve.
......@@ -215,6 +229,24 @@ contract OVM_StateManager is iOVM_StateManager {
return accounts[_address].ethAddress;
}
/**
* Retrieves the storage root of an account.
* @param _address Address of the account to access.
* @return _storageRoot Corresponding storage root.
*/
function getAccountStorageRoot(
address _address
)
override
public
view
returns (
bytes32 _storageRoot
)
{
return accounts[_address].storageRoot;
}
/**
* Initializes a pending account (during CREATE or CREATE2) with the default values.
* @param _address Address of the account to initialize.
......@@ -228,7 +260,7 @@ contract OVM_StateManager is iOVM_StateManager {
{
Lib_OVMCodec.Account storage account = accounts[_address];
account.nonce = 1;
account.codeHash = keccak256(hex'80');
account.codeHash = keccak256(hex'');
account.isFresh = true;
}
......
......@@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2;
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol";
import { Lib_EthMerkleTrie } from "../../libraries/trie/Lib_EthMerkleTrie.sol";
import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.sol";
/* Interface Imports */
import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol";
......@@ -14,6 +14,9 @@ import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManage
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
/* Logging Imports */
import { console } from "@nomiclabs/buidler/console.sol";
/**
* @title OVM_StateTransitioner
*/
......@@ -158,73 +161,115 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
*/
function proveContractState(
address _ovmContractAddress,
Lib_OVMCodec.Account memory _account,
address _ethContractAddress,
Lib_OVMCodec.EVMAccount memory _account,
bytes memory _stateTrieWitness
)
override
public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
{
// Exit quickly to avoid unnecessary work.
require(
ovmStateManager.hasAccount(_ovmContractAddress) == false,
"Account state has already been proven"
);
require(
_account.codeHash == Lib_EthUtils.getCodeHash(_account.ethAddress),
_account.codeHash == Lib_EthUtils.getCodeHash(_ethContractAddress),
"Invalid code hash provided."
);
require(
Lib_EthMerkleTrie.proveAccountState(
_ovmContractAddress,
Lib_OVMCodec.EVMAccount({
balance: _account.balance,
nonce: _account.nonce,
storageRoot: _account.storageRoot,
codeHash: _account.codeHash
}),
Lib_SecureMerkleTrie.verifyInclusionProof(
abi.encodePacked(_ovmContractAddress),
Lib_OVMCodec.encodeEVMAccount(_account),
_stateTrieWitness,
preStateRoot
),
"Invalid account state provided."
"Account state is not correct or invalid inclusion proof provided."
);
ovmStateManager.putAccount(
_ovmContractAddress,
_account
Lib_OVMCodec.Account({
nonce: _account.nonce,
balance: _account.balance,
storageRoot: _account.storageRoot,
codeHash: _account.codeHash,
ethAddress: _ethContractAddress,
isFresh: false
})
);
}
/**
* Allows a user to prove that an account does *not* exist in the state.
* @param _ovmContractAddress Address of the contract on the OVM.
* @param _stateTrieWitness Proof of the (empty) account state.
*/
function proveEmptyContractState(
address _ovmContractAddress,
bytes memory _stateTrieWitness
)
override
public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
{
// Exit quickly to avoid unnecessary work.
require(
ovmStateManager.hasEmptyAccount(_ovmContractAddress) == false,
"Account state has already been proven."
);
require(
Lib_SecureMerkleTrie.verifyExclusionProof(
abi.encodePacked(_ovmContractAddress),
_stateTrieWitness,
preStateRoot
),
"Account is not empty or invalid inclusion proof provided."
);
ovmStateManager.putEmptyAccount(_ovmContractAddress);
}
/**
* Allows a user to prove the initial state of a contract storage slot.
* @param _ovmContractAddress Address of the contract on the OVM.
* @param _key Claimed account slot key.
* @param _value Claimed account slot value.
* @param _stateTrieWitness Proof of the account state.
* @param _storageTrieWitness Proof of the storage slot.
*/
function proveStorageSlot(
address _ovmContractAddress,
bytes32 _key,
bytes32 _value,
bytes memory _stateTrieWitness,
bytes memory _storageTrieWitness
)
override
public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
{
// Exit quickly to avoid unnecessary work.
require(
ovmStateManager.hasContractStorage(_ovmContractAddress, _key) == false,
"Storage slot has already been proven."
);
require(
ovmStateManager.hasAccount(_ovmContractAddress) == true,
"Contract must be verified before proving a storage slot."
);
require(
Lib_EthMerkleTrie.proveAccountStorageSlotValue(
_ovmContractAddress,
_key,
_value,
_stateTrieWitness,
Lib_SecureMerkleTrie.verifyInclusionProof(
abi.encodePacked(_key),
abi.encodePacked(_value),
_storageTrieWitness,
preStateRoot
ovmStateManager.getAccountStorageRoot(_ovmContractAddress)
),
"Invalid account state provided."
"Storage slot is invalid or invalid inclusion proof provided."
);
ovmStateManager.putContractStorage(
......@@ -254,9 +299,14 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
"Invalid transaction provided."
);
// TODO: Set state manager for EM here.
// We call `setExecutionManager` right before `run` (and not earlier) just in case the
// OVM_ExecutionManager address was updated between the time when this contract was created
// and when `applyTransaction` was called.
ovmStateManager.setExecutionManager(resolve("OVM_ExecutionManager"));
// `run` always succeeds *unless* the user hasn't provided enough gas to `applyTransaction`
// or an INVALID_STATE_ACCESS flag was triggered. Either way, we won't get beyond this line
// if that's the case.
ovmExecutionManager.run(_transaction, address(ovmStateManager));
phase = TransitionPhase.POST_EXECUTION;
......@@ -275,7 +325,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
*/
function commitContractState(
address _ovmContractAddress,
Lib_OVMCodec.Account memory _account,
Lib_OVMCodec.EVMAccount memory _account,
bytes memory _stateTrieWitness
)
override
......@@ -284,17 +334,12 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
{
require(
ovmStateManager.commitAccount(_ovmContractAddress) == true,
"Cannot commit an account that has not been changed."
"Account was not changed or has already been committed."
);
postStateRoot = Lib_EthMerkleTrie.updateAccountState(
_ovmContractAddress,
Lib_OVMCodec.EVMAccount({
balance: _account.balance,
nonce: _account.nonce,
storageRoot: _account.storageRoot,
codeHash: _account.codeHash
}),
postStateRoot = Lib_SecureMerkleTrie.update(
abi.encodePacked(_ovmContractAddress),
Lib_OVMCodec.encodeEVMAccount(_account),
_stateTrieWitness,
postStateRoot
);
......@@ -321,15 +366,24 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
{
require(
ovmStateManager.commitContractStorage(_ovmContractAddress, _key) == true,
"Cannot commit a storage slot that has not been changed."
"Storage slot was not changed or has already been committed."
);
postStateRoot = Lib_EthMerkleTrie.updateAccountStorageSlotValue(
_ovmContractAddress,
_key,
_value,
_stateTrieWitness,
Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.toEVMAccount(
ovmStateManager.getAccount(_ovmContractAddress)
);
account.storageRoot = Lib_SecureMerkleTrie.update(
abi.encodePacked(_key),
abi.encodePacked(_value),
_storageTrieWitness,
account.storageRoot
);
postStateRoot = Lib_SecureMerkleTrie.update(
abi.encodePacked(_ovmContractAddress),
Lib_OVMCodec.encodeEVMAccount(account),
_stateTrieWitness,
postStateRoot
);
}
......
......@@ -34,12 +34,14 @@ interface iOVM_StateManager {
************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external;
function putEmptyAccount(address _address) external;
function getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external view returns (bool _exists);
function hasEmptyAccount(address _address) external view returns (bool _exists);
function setAccountNonce(address _address, uint256 _nonce) external;
function getAccountNonce(address _address) external view returns (uint256 _nonce);
function getAccountEthAddress(address _address) external view returns (address _ethAddress);
function getAccountStorageRoot(address _address) external view returns (bytes32 _storageRoot);
function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
......
......@@ -25,7 +25,13 @@ interface iOVM_StateTransitioner {
function proveContractState(
address _ovmContractAddress,
Lib_OVMCodec.Account calldata _account,
address _ethContractAddress,
Lib_OVMCodec.EVMAccount calldata _account,
bytes calldata _stateTrieWitness
) external;
function proveEmptyContractState(
address _ovmContractAddress,
bytes calldata _stateTrieWitness
) external;
......@@ -33,7 +39,6 @@ interface iOVM_StateTransitioner {
address _ovmContractAddress,
bytes32 _key,
bytes32 _value,
bytes calldata _stateTrieWitness,
bytes calldata _storageTrieWitness
) external;
......@@ -53,7 +58,7 @@ interface iOVM_StateTransitioner {
function commitContractState(
address _ovmContractAddress,
Lib_OVMCodec.Account calldata _account,
Lib_OVMCodec.EVMAccount calldata _account,
bytes calldata _stateTrieWitness
) external;
......
......@@ -4,12 +4,24 @@ pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/**
* @title Lib_OVMCodec
*/
library Lib_OVMCodec {
/*************
* Constants *
*************/
bytes constant internal RLP_NULL_BYTES = hex'80';
bytes constant internal NULL_BYTES = bytes('');
bytes32 constant internal NULL_BYTES32 = bytes32('');
bytes32 constant internal KECCAK256_RLP_NULL_BYTES = keccak256(RLP_NULL_BYTES);
bytes32 constant internal KECCAK256_NULL_BYTES = keccak256(NULL_BYTES);
/*********
* Enums *
*********/
......@@ -100,13 +112,13 @@ library Lib_OVMCodec {
EOATransaction memory _decoded
)
{
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.toList(Lib_RLPReader.toRlpItem(_transaction));
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_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])
nonce: Lib_RLPReader.readUint256(decoded[0]),
gasLimit: Lib_RLPReader.readUint256(decoded[2]),
target: Lib_RLPReader.readAddress(decoded[3]),
data: Lib_RLPReader.readBytes(decoded[5])
});
}
......@@ -151,4 +163,77 @@ library Lib_OVMCodec {
{
return keccak256(encodeTransaction(_transaction));
}
/**
* Converts an OVM account to an EVM account.
* @param _in OVM account to convert.
* @return _out Converted EVM account.
*/
function toEVMAccount(
Account memory _in
)
internal
pure
returns (
EVMAccount memory _out
)
{
return EVMAccount({
nonce: _in.nonce,
balance: _in.balance,
storageRoot: _in.storageRoot,
codeHash: _in.codeHash
});
}
/**
* @notice RLP-encodes an account state struct.
* @param _account Account state struct.
* @return _encoded RLP-encoded account state.
*/
function encodeEVMAccount(
EVMAccount memory _account
)
internal
pure
returns (
bytes memory _encoded
)
{
bytes[] memory raw = new bytes[](4);
// Unfortunately we can't create this array outright because
// RLPWriter.encodeList will reject fixed-size arrays. Assigning
// index-by-index circumvents this issue.
raw[0] = Lib_RLPWriter.encodeUint(_account.nonce);
raw[1] = Lib_RLPWriter.encodeUint(_account.balance);
raw[2] = _account.storageRoot == 0 ? RLP_NULL_BYTES : Lib_RLPWriter.encodeBytes(abi.encodePacked(_account.storageRoot));
raw[3] = _account.codeHash == 0 ? RLP_NULL_BYTES : Lib_RLPWriter.encodeBytes(abi.encodePacked(_account.codeHash));
return Lib_RLPWriter.encodeList(raw);
}
/**
* @notice Decodes an RLP-encoded account state into a useful struct.
* @param _encoded RLP-encoded account state.
* @return _account Account state struct.
*/
function decodeEVMAccount(
bytes memory _encoded
)
internal
pure
returns (
EVMAccount memory _account
)
{
Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
return EVMAccount({
nonce: Lib_RLPReader.readUint256(accountState[0]),
balance: Lib_RLPReader.readUint256(accountState[1]),
storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
codeHash: Lib_RLPReader.readBytes32(accountState[3])
});
}
}
......@@ -24,7 +24,7 @@ library Lib_SecureMerkleTrie {
* of a list of RLP-encoded nodes that make a path down to the target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return `true` if the k/v pair exists in the trie, `false` otherwise.
* @return _verified `true` if the k/v pair exists in the trie, `false` otherwise.
*/
function verifyInclusionProof(
bytes memory _key,
......@@ -35,7 +35,7 @@ library Lib_SecureMerkleTrie {
internal
view
returns (
bool
bool _verified
)
{
bytes memory key = _getSecureKey(_key);
......@@ -43,31 +43,28 @@ library Lib_SecureMerkleTrie {
}
/**
* @notice Verifies a proof that a given key/value pair is *not* present in
* @notice Verifies a proof that a given key is *not* present in
* the Merkle trie.
* @param _key Key of the node to search for, as a hex string.
* @param _value Value of the node to search for, as a hex string.
* @param _proof Merkle trie inclusion proof for the node *nearest* the
* target node. We effectively need to show that either the key exists and
* its value differs, or the key does not exist at all.
* target node.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return `true` if the k/v pair is absent in the trie, `false` otherwise.
* @return _verified `true` if the key is not present in the trie, `false` otherwise.
*/
function verifyExclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
)
internal
view
returns (
bool
bool _verified
)
{
bytes memory key = _getSecureKey(_key);
return Lib_MerkleTrie.verifyExclusionProof(key, _value, _proof, _root);
return Lib_MerkleTrie.verifyExclusionProof(key, _proof, _root);
}
/**
......@@ -79,7 +76,7 @@ library Lib_SecureMerkleTrie {
* Otherwise, we need to modify the trie to handle the new k/v pair.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return Root hash of the newly constructed trie.
* @return _updatedRoot Root hash of the newly constructed trie.
*/
function update(
bytes memory _key,
......@@ -90,7 +87,7 @@ library Lib_SecureMerkleTrie {
internal
view
returns (
bytes32
bytes32 _updatedRoot
)
{
bytes memory key = _getSecureKey(_key);
......@@ -102,7 +99,8 @@ library Lib_SecureMerkleTrie {
* @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie.
* @return Whether the node exists, value associated with the key if so.
* @return _exists Whether or not the key exists.
* @return _value Value of the key if it exists.
*/
function get(
bytes memory _key,
......@@ -112,8 +110,8 @@ library Lib_SecureMerkleTrie {
internal
view
returns (
bool,
bytes memory
bool _exists,
bytes memory _value
)
{
bytes memory key = _getSecureKey(_key);
......@@ -124,7 +122,7 @@ library Lib_SecureMerkleTrie {
* Computes the root hash for a trie with a single node.
* @param _key Key for the single node.
* @param _value Value for the single node.
* @return Hash of the trie.
* @return _updatedRoot Hash of the trie.
*/
function getSingleNodeRootHash(
bytes memory _key,
......@@ -133,7 +131,7 @@ library Lib_SecureMerkleTrie {
internal
view
returns (
bytes32
bytes32 _updatedRoot
)
{
bytes memory key = _getSecureKey(_key);
......@@ -145,13 +143,18 @@ library Lib_SecureMerkleTrie {
* Private Functions *
*********************/
/**
* Computes the secure counterpart to a key.
* @param _key Key to get a secure key from.
* @return _secureKey Secure version of the key.
*/
function _getSecureKey(
bytes memory _key
)
private
pure
returns (
bytes memory
bytes memory _secureKey
)
{
return abi.encodePacked(keccak256(_key));
......
......@@ -8,7 +8,7 @@ import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMC
/**
* @title TestLib_OVMCodec
*/
library TestLib_OVMCodec {
contract TestLib_OVMCodec {
function decodeEOATransaction(
bytes memory _transaction
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_RLPReader } from "../../optimistic-ethereum/libraries/rlp/Lib_RLPReader.sol";
/**
* @title TestLib_RLPReader
*/
contract TestLib_RLPReader {
function readList(
bytes memory _in
)
public
view
returns (
bytes[] memory
)
{
Lib_RLPReader.RLPItem[] memory decoded = Lib_RLPReader.readList(_in);
bytes[] memory out = new bytes[](decoded.length);
for (uint256 i = 0; i < out.length; i++) {
out[i] = Lib_RLPReader.readRawBytes(decoded[i]);
}
return out;
}
function readString(
bytes memory _in
)
public
view
returns (
string memory
)
{
return Lib_RLPReader.readString(_in);
}
function readBytes(
bytes memory _in
)
public
view
returns (
bytes memory
)
{
return Lib_RLPReader.readBytes(_in);
}
function readBytes32(
bytes memory _in
)
public
view
returns (
bytes32
)
{
return Lib_RLPReader.readBytes32(_in);
}
function readUint256(
bytes memory _in
)
public
view
returns (
uint256
)
{
return Lib_RLPReader.readUint256(_in);
}
function readBool(
bytes memory _in
)
public
view
returns (
bool
)
{
return Lib_RLPReader.readBool(_in);
}
function readAddress(
bytes memory _in
)
public
view
returns (
address
)
{
return Lib_RLPReader.readAddress(_in);
}
}
......@@ -8,7 +8,7 @@ import { Lib_RLPWriter } from "../../optimistic-ethereum/libraries/rlp/Lib_RLPWr
/**
* @title TestLib_RLPWriter
*/
library TestLib_RLPWriter {
contract TestLib_RLPWriter {
function encodeBytes(
bytes memory _in
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */
import { Lib_EthMerkleTrie } from "../../optimistic-ethereum/libraries/trie/Lib_EthMerkleTrie.sol";
import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMCodec.sol";
/**
* @title TestLib_EthMerkleTrie
*/
contract TestLib_EthMerkleTrie {
function proveAccountStorageSlotValue(
address _address,
bytes32 _key,
bytes32 _value,
bytes memory _stateTrieWitness,
bytes memory _storageTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountStorageSlotValue(
_address,
_key,
_value,
_stateTrieWitness,
_storageTrieWitness,
_stateTrieRoot
);
}
function updateAccountStorageSlotValue(
address _address,
bytes32 _key,
bytes32 _value,
bytes memory _stateTrieWitness,
bytes memory _storageTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountStorageSlotValue(
_address,
_key,
_value,
_stateTrieWitness,
_storageTrieWitness,
_stateTrieRoot
);
}
function proveAccountState(
address _address,
Lib_OVMCodec.EVMAccount memory _accountState,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountState(
_address,
_accountState,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountState(
address _address,
Lib_OVMCodec.EVMAccount memory _accountState,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountState(
_address,
_accountState,
_stateTrieWitness,
_stateTrieRoot
);
}
}
......@@ -7,7 +7,7 @@ import { Lib_MerkleTrie } from "../../optimistic-ethereum/libraries/trie/Lib_Mer
/**
* @title TestLib_MerkleTrie
*/
library TestLib_MerkleTrie {
contract TestLib_MerkleTrie {
function verifyInclusionProof(
bytes memory _key,
......@@ -31,7 +31,6 @@ library TestLib_MerkleTrie {
function verifyExclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
)
......@@ -43,7 +42,6 @@ library TestLib_MerkleTrie {
{
return Lib_MerkleTrie.verifyExclusionProof(
_key,
_value,
_proof,
_root
);
......
......@@ -8,7 +8,7 @@ import { Lib_SecureMerkleTrie } from "../../optimistic-ethereum/libraries/trie/L
/**
* @title TestLib_SecureMerkleTrie
*/
library TestLib_SecureMerkleTrie {
contract TestLib_SecureMerkleTrie {
function verifyInclusionProof(
bytes memory _key,
......@@ -32,7 +32,6 @@ library TestLib_SecureMerkleTrie {
function verifyExclusionProof(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
)
......@@ -44,7 +43,6 @@ library TestLib_SecureMerkleTrie {
{
return Lib_SecureMerkleTrie.verifyExclusionProof(
_key,
_value,
_proof,
_root
);
......
......@@ -7,7 +7,7 @@ import { Lib_Bytes32Utils } from "../../optimistic-ethereum/libraries/utils/Lib_
/**
* @title TestLib_Byte32Utils
*/
library TestLib_Bytes32Utils {
contract TestLib_Bytes32Utils {
function toBool(
bytes32 _in
......
......@@ -8,7 +8,7 @@ import { Lib_BytesUtils } from "../../optimistic-ethereum/libraries/utils/Lib_By
/**
* @title TestLib_BytesUtils
*/
library TestLib_BytesUtils {
contract TestLib_BytesUtils {
function concat(
bytes memory _preBytes,
......
......@@ -7,7 +7,7 @@ import { Lib_ECDSAUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EC
/**
* @title TestLib_ECDSAUtils
*/
library TestLib_ECDSAUtils {
contract TestLib_ECDSAUtils {
function recover(
bytes memory _message,
......
......@@ -8,7 +8,7 @@ import { Lib_EthUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EthU
/**
* @title TestLib_EthUtils
*/
library TestLib_EthUtils {
contract TestLib_EthUtils {
function getCode(
address _address,
......
......@@ -8,7 +8,7 @@ import { Lib_MerkleUtils } from "../../optimistic-ethereum/libraries/utils/Lib_M
/**
* @title TestLib_MerkleUtils
*/
library TestLib_MerkleUtils {
contract TestLib_MerkleUtils {
function getMerkleRoot(
bytes32[] memory _hashes
......
......@@ -10,7 +10,7 @@
"build:dump": "ts-node \"bin/take-dump.ts\"",
"build:copy": "copyfiles -u 2 \"contracts/optimistic-ethereum/**/*.sol\" \"build/contracts\"",
"test": "yarn run test:contracts",
"test:contracts": "buidler test \"test/contracts/libraries/trie/Lib_EthMerkleTrie.spec.ts\" --show-stack-traces",
"test:contracts": "buidler test \"test/contracts/libraries/rlp/Lib_RLPReader.spec.ts\" --show-stack-traces",
"lint": "yarn run lint:typescript",
"lint:typescript": "tslint --format stylish --project .",
"lint:fix": "yarn run lint:fix:typescript",
......
This diff is collapsed.
/* tslint:disable:no-empty */
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { BigNumber, Contract, ContractFactory } from 'ethers'
/* Internal Imports */
import {
makeAddressManager,
NON_NULL_BYTES32,
NON_ZERO_ADDRESS,
NULL_BYTES32,
setProxyTarget,
TrieTestGenerator,
ZERO_ADDRESS,
} from '../../../helpers'
import { MockContract, smockit } from '@eth-optimism/smock'
import { keccak256 } from 'ethers/lib/utils'
describe('OVM_StateTransitioner', () => {
let AddressManager: Contract
before(async () => {
AddressManager = await makeAddressManager()
})
let Mock__OVM_ExecutionManager: MockContract
let Mock__OVM_StateManagerFactory: MockContract
let Mock__OVM_StateManager: MockContract
before(async () => {
Mock__OVM_ExecutionManager = smockit(
await ethers.getContractFactory('OVM_ExecutionManager')
)
Mock__OVM_StateManagerFactory = smockit(
await ethers.getContractFactory('OVM_StateManagerFactory')
)
Mock__OVM_StateManager = smockit(
await ethers.getContractFactory('OVM_StateManager')
)
await setProxyTarget(
AddressManager,
'OVM_ExecutionManager',
Mock__OVM_ExecutionManager
)
await setProxyTarget(
AddressManager,
'OVM_StateManagerFactory',
Mock__OVM_StateManagerFactory
)
Mock__OVM_StateManagerFactory.smocked.create.will.return.with(
Mock__OVM_StateManager.address
)
Mock__OVM_StateManager.smocked.putAccount.will.return()
})
let Factory__OVM_StateTransitioner: ContractFactory
before(async () => {
Factory__OVM_StateTransitioner = await ethers.getContractFactory(
'OVM_StateTransitioner'
)
})
let OVM_StateTransitioner: Contract
beforeEach(async () => {
OVM_StateTransitioner = await Factory__OVM_StateTransitioner.deploy(
AddressManager.address,
0,
NULL_BYTES32,
NULL_BYTES32
)
})
describe('proveContractState', () => {
let account: any
beforeEach(() => {
account = {
nonce: 0,
balance: 0,
storageRoot: NULL_BYTES32,
codeHash: NULL_BYTES32,
ethAddress: ZERO_ADDRESS,
isFresh: false,
}
})
describe('when provided an invalid code hash', () => {
it('should revert', async () => {})
beforeEach(() => {
account.ethAddress = NON_ZERO_ADDRESS
account.codeHash = NON_NULL_BYTES32
})
it('should revert', async () => {
await expect(
OVM_StateTransitioner.proveContractState(ZERO_ADDRESS, account, '0x')
).to.be.revertedWith('Invalid code hash provided.')
})
})
describe('when provided a valid code hash', () => {
beforeEach(async () => {
account.ethAddress = OVM_StateTransitioner.address
account.codeHash = keccak256(
await ethers.provider.getCode(OVM_StateTransitioner.address)
)
})
describe('when provided an invalid account inclusion proof', () => {
it('should revert', async () => {})
const proof = '0x'
it('should revert', async () => {
await expect(
OVM_StateTransitioner.proveContractState(
ZERO_ADDRESS,
account,
proof
)
).to.be.reverted
})
})
describe('when provided a valid account inclusion proof', () => {
let proof: string
beforeEach(async () => {
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
...account,
address: NON_ZERO_ADDRESS,
},
],
secure: true,
})
const test = await generator.makeAccountProofTest(NON_ZERO_ADDRESS)
proof = test.accountTrieWitness
OVM_StateTransitioner = await Factory__OVM_StateTransitioner.deploy(
AddressManager.address,
0,
test.accountTrieRoot,
NULL_BYTES32
)
})
it('should put the account in the state manager', async () => {
await expect(
OVM_StateTransitioner.proveContractState(
NON_ZERO_ADDRESS,
account,
proof
)
).to.not.be.reverted
describe('when provided a valid account inclusion proof', () => {})
expect(
Mock__OVM_StateManager.smocked.putAccount.calls[0]
).to.deep.equal([
NON_ZERO_ADDRESS,
[
BigNumber.from(account.nonce),
BigNumber.from(account.balance),
account.storageRoot,
account.codeHash,
account.ethAddress,
account.isFresh,
],
])
})
})
})
})
describe('proveStorageSlot', () => {
describe('when the corresponding account is not proven', () => {
it('should revert', async () => {})
beforeEach(() => {
Mock__OVM_StateManager.smocked.hasAccount.will.return.with(false)
})
it('should revert', async () => {
await expect(
OVM_StateTransitioner.proveStorageSlot(
NON_ZERO_ADDRESS,
NON_NULL_BYTES32,
NON_NULL_BYTES32,
'0x',
'0x'
)
).to.be.revertedWith(
'Contract must be verified before proving a storage slot.'
)
})
})
describe('when the corresponding account is proven', () => {
beforeEach(() => {
Mock__OVM_StateManager.smocked.hasAccount.will.return.with(false)
})
describe('when provided an invalid slot inclusion proof', () => {
let account: any
let proof: string
beforeEach(async () => {
account = {
nonce: 0,
balance: 0,
storageRoot: NULL_BYTES32,
codeHash: NULL_BYTES32,
ethAddress: ZERO_ADDRESS,
isFresh: false,
}
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
...account,
address: NON_ZERO_ADDRESS,
storage: [
{
key: keccak256('0x1234'),
val: keccak256('0x5678'),
},
],
},
],
secure: true,
})
const test = await generator.makeAccountProofTest(NON_ZERO_ADDRESS)
proof = test.accountTrieWitness
OVM_StateTransitioner = await Factory__OVM_StateTransitioner.deploy(
AddressManager.address,
0,
test.accountTrieRoot,
NULL_BYTES32
)
})
it('should revert', async () => {})
})
......
/* External Imports */
import * as rlp from 'rlp'
/* Internal Imports */
import { Lib_RLPReader_TEST_JSON } from '../../../data'
import { runJsonTest, toHexString } from '../../../helpers'
describe('Lib_RLPReader', () => {
//console.log(JSON.stringify(Lib_RLPReader_TEST_JSON2, null, 4))
describe('JSON tests', () => {
runJsonTest('TestLib_RLPReader', Lib_RLPReader_TEST_JSON)
})
})
export { tests as Lib_RLPWriter_TEST_JSON } from './json/libraries/rlp/Lib_RLPWriter.test.json'
export { tests as Lib_RLPReader_TEST_JSON } from './json/libraries/rlp/Lib_RLPReader.test.json'
export { tests as Lib_Bytes32Utils_TEST_JSON } from './json/libraries/utils/Lib_Bytes32Utils.test.json'
export { tests as Lib_BytesUtils_TEST_JSON } from './json/libraries/utils/Lib_BytesUtils.test.json'
export { tests as Lib_ECDSAUtils_TEST_JSON } from './json/libraries/utils/Lib_ECDSAUtils.test.json'
......
......@@ -48,8 +48,8 @@ const rlpEncodeAccount = (account: EthereumAccount): string => {
rlp.encode([
account.nonce,
account.balance,
account.codeHash || NULL_BYTES32,
account.storageRoot || NULL_BYTES32,
account.codeHash || NULL_BYTES32,
])
)
}
......
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