Commit ee8164a9 authored by ben-chain's avatar ben-chain Committed by GitHub

Merge pull request #2 from ethereum-optimism/dev/port-tests

Ports over most of the tests from Contracts V1
parents c7b37b40 7d72e069
/* External Imports */
import * as fs from 'fs'
import * as path from 'path'
import * as mkdirp from 'mkdirp'
/* Internal Imports */
import { makeStateDump } from '../src'
;(async () => {
const outdir = path.resolve(__dirname, '../build/dumps')
const outfile = path.join(outdir, 'state-dump.latest.json')
mkdirp.sync(outdir)
const dump = await makeStateDump()
fs.writeFileSync(outfile, JSON.stringify(dump))
})()
...@@ -8,7 +8,7 @@ import { ...@@ -8,7 +8,7 @@ import {
usePlugin('@nomiclabs/buidler-ethers') usePlugin('@nomiclabs/buidler-ethers')
usePlugin('@nomiclabs/buidler-waffle') usePlugin('@nomiclabs/buidler-waffle')
import '@eth-optimism/smock/src/buidler-plugins/compiler-storage-layout' import '@eth-optimism/smock/build/src/buidler-plugins/compiler-storage-layout'
const config: BuidlerConfig = { const config: BuidlerConfig = {
networks: { networks: {
......
...@@ -4,11 +4,11 @@ pragma experimental ABIEncoderV2; ...@@ -4,11 +4,11 @@ pragma experimental ABIEncoderV2;
/* Interface Imports */ /* Interface Imports */
import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol"; import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol";
import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManager.sol";
/* Library Imports */ /* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol"; import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol";
import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol";
/** /**
* @title OVM_ECDSAContractAccount * @title OVM_ECDSAContractAccount
...@@ -43,7 +43,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { ...@@ -43,7 +43,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
bytes memory _returndata bytes memory _returndata
) )
{ {
iOVM_ExecutionManager ovmExecutionManager = iOVM_ExecutionManager(msg.sender); address ovmExecutionManager = msg.sender;
// Address of this contract within the ovm (ovmADDRESS) should be the same as the // 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 // recovered address of the user who signed this message. This is how we manage to shim
...@@ -55,8 +55,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { ...@@ -55,8 +55,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
_v, _v,
_r, _r,
_s, _s,
ovmExecutionManager.ovmCHAINID() Lib_SafeExecutionManagerWrapper.safeCHAINID(ovmExecutionManager)
) == ovmExecutionManager.ovmADDRESS(), ) == Lib_SafeExecutionManagerWrapper.safeADDRESS(ovmExecutionManager),
"Signature provided for EOA transaction execution is invalid." "Signature provided for EOA transaction execution is invalid."
); );
...@@ -64,14 +64,16 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { ...@@ -64,14 +64,16 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
// Need to make sure that the transaction nonce is right and bump it if so. // Need to make sure that the transaction nonce is right and bump it if so.
require( require(
decodedTx.nonce == ovmExecutionManager.ovmGETNONCE() + 1, decodedTx.nonce == Lib_SafeExecutionManagerWrapper.safeGETNONCE(ovmExecutionManager) + 1,
"Transaction nonce does not match the expected nonce." "Transaction nonce does not match the expected nonce."
); );
ovmExecutionManager.ovmSETNONCE(decodedTx.nonce); Lib_SafeExecutionManagerWrapper.safeSETNONCE(ovmExecutionManager, decodedTx.nonce);
// Contract creations are signalled by sending a transaction to the zero address. // Contract creations are signalled by sending a transaction to the zero address.
if (decodedTx.target == address(0)) { if (decodedTx.target == address(0)) {
address created = ovmExecutionManager.ovmCREATE{gas: decodedTx.gasLimit}( address created = Lib_SafeExecutionManagerWrapper.safeCREATE(
ovmExecutionManager,
decodedTx.gasLimit,
decodedTx.data decodedTx.data
); );
...@@ -79,7 +81,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount { ...@@ -79,7 +81,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
// initialization. Always return `true` for our success value here. // initialization. Always return `true` for our success value here.
return (true, abi.encode(created)); return (true, abi.encode(created));
} else { } else {
return ovmExecutionManager.ovmCALL( return Lib_SafeExecutionManagerWrapper.safeCALL(
ovmExecutionManager,
decodedTx.gasLimit, decodedTx.gasLimit,
decodedTx.target, decodedTx.target,
decodedTx.data decodedTx.data
......
...@@ -41,6 +41,32 @@ contract OVM_BaseCrossDomainMessenger is iOVM_BaseCrossDomainMessenger { ...@@ -41,6 +41,32 @@ contract OVM_BaseCrossDomainMessenger is iOVM_BaseCrossDomainMessenger {
targetMessengerAddress = _targetMessengerAddress; targetMessengerAddress = _targetMessengerAddress;
} }
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint256 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
_sendXDomainMessage(xDomainCalldata, _gasLimit);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
}
/********************** /**********************
* Internal Functions * * Internal Functions *
...@@ -74,4 +100,19 @@ contract OVM_BaseCrossDomainMessenger is iOVM_BaseCrossDomainMessenger { ...@@ -74,4 +100,19 @@ contract OVM_BaseCrossDomainMessenger is iOVM_BaseCrossDomainMessenger {
_messageNonce _messageNonce
); );
} }
/**
* Sends a cross domain message.
* @param _message Message to send.
* @param _gasLimit Gas limit for the provided message.
*/
function _sendXDomainMessage(
bytes memory _message,
uint256 _gasLimit
)
virtual
internal
{
revert("Implement me in child contracts!");
}
} }
...@@ -3,8 +3,9 @@ pragma solidity ^0.7.0; ...@@ -3,8 +3,9 @@ pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.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"; import { Lib_BytesUtils } from "../../libraries/utils/Lib_BytesUtils.sol";
/* Interface Imports */ /* Interface Imports */
...@@ -94,31 +95,6 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros ...@@ -94,31 +95,6 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros
receivedMessages[keccak256(xDomainCalldata)] = true; receivedMessages[keccak256(xDomainCalldata)] = true;
} }
/**
* Sends a cross domain message to the target messenger.
* @inheritdoc iOVM_L1CrossDomainMessenger
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
_sendXDomainMessage(xDomainCalldata, _gasLimit);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
}
/** /**
* Replays a cross domain message to the target messenger. * Replays a cross domain message to the target messenger.
* @inheritdoc iOVM_L1CrossDomainMessenger * @inheritdoc iOVM_L1CrossDomainMessenger
...@@ -221,11 +197,27 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros ...@@ -221,11 +197,27 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros
) )
); );
return Lib_EthMerkleTrie.proveAccountStorageSlotValue( (
0x4200000000000000000000000000000000000000, bool exists,
storageKey, bytes memory encodedMessagePassingAccount
bytes32(uint256(1)), ) = Lib_SecureMerkleTrie.get(
abi.encodePacked(0x4200000000000000000000000000000000000000),
_proof.stateTrieWitness, _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.storageTrieWitness,
_proof.stateRoot _proof.stateRoot
); );
...@@ -238,8 +230,9 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros ...@@ -238,8 +230,9 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, OVM_BaseCros
*/ */
function _sendXDomainMessage( function _sendXDomainMessage(
bytes memory _message, bytes memory _message,
uint32 _gasLimit uint256 _gasLimit
) )
override
internal internal
{ {
ovmL1ToL2TransactionQueue.enqueue( ovmL1ToL2TransactionQueue.enqueue(
......
...@@ -88,31 +88,6 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, OVM_BaseCros ...@@ -88,31 +88,6 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, OVM_BaseCros
receivedMessages[keccak256(xDomainCalldata)] = true; receivedMessages[keccak256(xDomainCalldata)] = true;
} }
/**
* Sends a cross domain message to the target messenger.
* @inheritdoc iOVM_L2CrossDomainMessenger
*/
function sendMessage(
address _target,
bytes memory _message,
uint256 _gasLimit
)
override
public
{
bytes memory xDomainCalldata = _getXDomainCalldata(
_target,
msg.sender,
_message,
messageNonce
);
_sendXDomainMessage(xDomainCalldata, _gasLimit);
messageNonce += 1;
sentMessages[keccak256(xDomainCalldata)] = true;
}
/********************** /**********************
* Internal Functions * * Internal Functions *
...@@ -142,6 +117,7 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, OVM_BaseCros ...@@ -142,6 +117,7 @@ contract OVM_L2CrossDomainMessenger is iOVM_L2CrossDomainMessenger, OVM_BaseCros
bytes memory _message, bytes memory _message,
uint256 _gasLimit uint256 _gasLimit
) )
override
internal internal
{ {
ovmL2ToL1MessagePasser.passMessageToL1(_message); ovmL2ToL1MessagePasser.passMessageToL1(_message);
......
...@@ -73,7 +73,10 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, OVM_BaseChain, L ...@@ -73,7 +73,10 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, OVM_BaseChain, L
elements[i] = abi.encodePacked(_batch[i]); elements[i] = abi.encodePacked(_batch[i]);
} }
_appendBatch(elements); _appendBatch(
elements,
abi.encodePacked(block.timestamp)
);
} }
/** /**
......
...@@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2; ...@@ -4,6 +4,7 @@ pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; 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_EthUtils } from "../../libraries/utils/Lib_EthUtils.sol";
/* Interface Imports */ /* Interface Imports */
...@@ -20,7 +21,7 @@ import { console } from "@nomiclabs/buidler/console.sol"; ...@@ -20,7 +21,7 @@ import { console } from "@nomiclabs/buidler/console.sol";
/** /**
* @title OVM_ExecutionManager * @title OVM_ExecutionManager
*/ */
contract OVM_ExecutionManager is iOVM_ExecutionManager { contract OVM_ExecutionManager is iOVM_ExecutionManager, Lib_AddressResolver {
/******************************** /********************************
* External Contract References * * External Contract References *
...@@ -59,12 +60,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -59,12 +60,14 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
***************/ ***************/
/** /**
* @param _ovmSafetyChecker Address of the iOVM_SafetyChecker implementation. * @param _libAddressManager Address of the Address Manager.
*/ */
constructor( constructor(
address _ovmSafetyChecker address _libAddressManager
) { )
ovmSafetyChecker = iOVM_SafetyChecker(_ovmSafetyChecker); Lib_AddressResolver(_libAddressManager)
{
ovmSafetyChecker = iOVM_SafetyChecker(resolve("OVM_SafetyChecker"));
} }
...@@ -1516,10 +1519,12 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager { ...@@ -1516,10 +1519,12 @@ contract OVM_ExecutionManager is iOVM_ExecutionManager {
bool _valid bool _valid
) )
{ {
// Always have to be below the maximum gas limit.
if (_gasLimit > gasMeterConfig.maxTransactionGasLimit) { if (_gasLimit > gasMeterConfig.maxTransactionGasLimit) {
return false; return false;
} }
// Always have to be above the minumum gas limit.
if (_gasLimit < gasMeterConfig.minTransactionGasLimit) { if (_gasLimit < gasMeterConfig.minTransactionGasLimit) {
return false; return false;
} }
......
...@@ -111,6 +111,20 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -111,6 +111,20 @@ contract OVM_StateManager is iOVM_StateManager {
accounts[_address] = _account; 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. * Retrieves an account from the state.
* @param _address Address of the account to retrieve. * @param _address Address of the account to retrieve.
...@@ -215,6 +229,24 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -215,6 +229,24 @@ contract OVM_StateManager is iOVM_StateManager {
return accounts[_address].ethAddress; 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. * Initializes a pending account (during CREATE or CREATE2) with the default values.
* @param _address Address of the account to initialize. * @param _address Address of the account to initialize.
...@@ -228,7 +260,7 @@ contract OVM_StateManager is iOVM_StateManager { ...@@ -228,7 +260,7 @@ contract OVM_StateManager is iOVM_StateManager {
{ {
Lib_OVMCodec.Account storage account = accounts[_address]; Lib_OVMCodec.Account storage account = accounts[_address];
account.nonce = 1; account.nonce = 1;
account.codeHash = keccak256(hex'80'); account.codeHash = keccak256(hex'');
account.isFresh = true; account.isFresh = true;
} }
......
...@@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2; ...@@ -6,7 +6,7 @@ pragma experimental ABIEncoderV2;
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol"; import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol"; import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_EthUtils } from "../../libraries/utils/Lib_EthUtils.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 */ /* Interface Imports */
import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol"; import { iOVM_StateTransitioner } from "../../iOVM/verification/iOVM_StateTransitioner.sol";
...@@ -14,6 +14,9 @@ import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManage ...@@ -14,6 +14,9 @@ import { iOVM_ExecutionManager } from "../../iOVM/execution/iOVM_ExecutionManage
import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol"; import { iOVM_StateManager } from "../../iOVM/execution/iOVM_StateManager.sol";
import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol"; import { iOVM_StateManagerFactory } from "../../iOVM/execution/iOVM_StateManagerFactory.sol";
/* Logging Imports */
import { console } from "@nomiclabs/buidler/console.sol";
/** /**
* @title OVM_StateTransitioner * @title OVM_StateTransitioner
*/ */
...@@ -158,70 +161,128 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -158,70 +161,128 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
*/ */
function proveContractState( function proveContractState(
address _ovmContractAddress, address _ovmContractAddress,
Lib_OVMCodec.Account memory _account, address _ethContractAddress,
Lib_OVMCodec.EVMAccount memory _account,
bytes memory _stateTrieWitness bytes memory _stateTrieWitness
) )
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
{ {
// Exit quickly to avoid unnecessary work.
require(
ovmStateManager.hasAccount(_ovmContractAddress) == false,
"Account state has already been proven"
);
require( require(
_account.codeHash == Lib_EthUtils.getCodeHash(_account.ethAddress), _account.codeHash == Lib_EthUtils.getCodeHash(_ethContractAddress),
"Invalid code hash provided." "Invalid code hash provided."
); );
require( require(
Lib_EthMerkleTrie.proveAccountState( Lib_SecureMerkleTrie.verifyInclusionProof(
_ovmContractAddress, abi.encodePacked(_ovmContractAddress),
_account, Lib_OVMCodec.encodeEVMAccount(_account),
_stateTrieWitness, _stateTrieWitness,
preStateRoot preStateRoot
), ),
"Invalid account state provided." "Account state is not correct or invalid inclusion proof provided."
); );
ovmStateManager.putAccount( ovmStateManager.putAccount(
_ovmContractAddress, _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. * Allows a user to prove the initial state of a contract storage slot.
* @param _ovmContractAddress Address of the contract on the OVM. * @param _ovmContractAddress Address of the contract on the OVM.
* @param _key Claimed account slot key. * @param _key Claimed account slot key.
* @param _value Claimed account slot value. * @param _value Claimed account slot value.
* @param _stateTrieWitness Proof of the account state.
* @param _storageTrieWitness Proof of the storage slot. * @param _storageTrieWitness Proof of the storage slot.
*/ */
function proveStorageSlot( function proveStorageSlot(
address _ovmContractAddress, address _ovmContractAddress,
bytes32 _key, bytes32 _key,
bytes32 _value, bytes32 _value,
bytes memory _stateTrieWitness,
bytes memory _storageTrieWitness bytes memory _storageTrieWitness
) )
override override
public public
onlyDuringPhase(TransitionPhase.PRE_EXECUTION) onlyDuringPhase(TransitionPhase.PRE_EXECUTION)
{ {
// Exit quickly to avoid unnecessary work.
require(
ovmStateManager.hasContractStorage(_ovmContractAddress, _key) == false,
"Storage slot has already been proven."
);
require( require(
ovmStateManager.hasAccount(_ovmContractAddress) == true, ovmStateManager.hasAccount(_ovmContractAddress) == true,
"Contract must be verified before proving a storage slot." "Contract must be verified before proving a storage slot."
); );
require( (
Lib_EthMerkleTrie.proveAccountStorageSlotValue( bool exists,
_ovmContractAddress, bytes memory value
_key, ) = Lib_SecureMerkleTrie.get(
_value, abi.encodePacked(_key),
_stateTrieWitness, _storageTrieWitness,
_storageTrieWitness, ovmStateManager.getAccountStorageRoot(_ovmContractAddress)
preStateRoot
),
"Invalid account state provided."
); );
if (exists == true) {
require(
keccak256(value) == keccak256(abi.encodePacked(_value)),
"Provided storage slot value is invalid."
);
} else {
require(
_value == bytes32(0),
"Provided storage slot value is invalid."
);
}
ovmStateManager.putContractStorage( ovmStateManager.putContractStorage(
_ovmContractAddress, _ovmContractAddress,
_key, _key,
...@@ -249,9 +310,14 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -249,9 +310,14 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
"Invalid transaction provided." "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")); 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)); ovmExecutionManager.run(_transaction, address(ovmStateManager));
phase = TransitionPhase.POST_EXECUTION; phase = TransitionPhase.POST_EXECUTION;
...@@ -270,7 +336,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -270,7 +336,7 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
*/ */
function commitContractState( function commitContractState(
address _ovmContractAddress, address _ovmContractAddress,
Lib_OVMCodec.Account memory _account, Lib_OVMCodec.EVMAccount memory _account,
bytes memory _stateTrieWitness bytes memory _stateTrieWitness
) )
override override
...@@ -279,12 +345,12 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -279,12 +345,12 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
{ {
require( require(
ovmStateManager.commitAccount(_ovmContractAddress) == true, 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( postStateRoot = Lib_SecureMerkleTrie.update(
_ovmContractAddress, abi.encodePacked(_ovmContractAddress),
_account, Lib_OVMCodec.encodeEVMAccount(_account),
_stateTrieWitness, _stateTrieWitness,
postStateRoot postStateRoot
); );
...@@ -311,15 +377,24 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver { ...@@ -311,15 +377,24 @@ contract OVM_StateTransitioner is iOVM_StateTransitioner, Lib_AddressResolver {
{ {
require( require(
ovmStateManager.commitContractStorage(_ovmContractAddress, _key) == true, 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( Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.toEVMAccount(
_ovmContractAddress, ovmStateManager.getAccount(_ovmContractAddress)
_key, );
_value,
_stateTrieWitness, account.storageRoot = Lib_SecureMerkleTrie.update(
abi.encodePacked(_key),
abi.encodePacked(_value),
_storageTrieWitness, _storageTrieWitness,
account.storageRoot
);
postStateRoot = Lib_SecureMerkleTrie.update(
abi.encodePacked(_ovmContractAddress),
Lib_OVMCodec.encodeEVMAccount(account),
_stateTrieWitness,
postStateRoot postStateRoot
); );
} }
......
...@@ -18,4 +18,16 @@ interface iOVM_BaseCrossDomainMessenger { ...@@ -18,4 +18,16 @@ interface iOVM_BaseCrossDomainMessenger {
function setTargetMessengerAddress( function setTargetMessengerAddress(
address _targetMessengerAddress address _targetMessengerAddress
) external; ) external;
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint256 _gasLimit
) external;
} }
...@@ -46,18 +46,6 @@ interface iOVM_L1CrossDomainMessenger is iOVM_BaseCrossDomainMessenger { ...@@ -46,18 +46,6 @@ interface iOVM_L1CrossDomainMessenger is iOVM_BaseCrossDomainMessenger {
L2MessageInclusionProof memory _proof L2MessageInclusionProof memory _proof
) external; ) external;
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
) external;
/** /**
* Replays a cross domain message to the target messenger. * Replays a cross domain message to the target messenger.
* @param _target Target contract address. * @param _target Target contract address.
......
...@@ -27,16 +27,4 @@ interface iOVM_L2CrossDomainMessenger is iOVM_BaseCrossDomainMessenger { ...@@ -27,16 +27,4 @@ interface iOVM_L2CrossDomainMessenger is iOVM_BaseCrossDomainMessenger {
bytes memory _message, bytes memory _message,
uint256 _messageNonce uint256 _messageNonce
) external; ) external;
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint256 _gasLimit
) external;
} }
...@@ -34,12 +34,14 @@ interface iOVM_StateManager { ...@@ -34,12 +34,14 @@ interface iOVM_StateManager {
************************************/ ************************************/
function putAccount(address _address, Lib_OVMCodec.Account memory _account) external; 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 getAccount(address _address) external view returns (Lib_OVMCodec.Account memory _account);
function hasAccount(address _address) external view returns (bool _exists); function hasAccount(address _address) external view returns (bool _exists);
function hasEmptyAccount(address _address) external view returns (bool _exists); function hasEmptyAccount(address _address) external view returns (bool _exists);
function setAccountNonce(address _address, uint256 _nonce) external; function setAccountNonce(address _address, uint256 _nonce) external;
function getAccountNonce(address _address) external view returns (uint256 _nonce); function getAccountNonce(address _address) external view returns (uint256 _nonce);
function getAccountEthAddress(address _address) external view returns (address _ethAddress); function getAccountEthAddress(address _address) external view returns (address _ethAddress);
function getAccountStorageRoot(address _address) external view returns (bytes32 _storageRoot);
function initPendingAccount(address _address) external; function initPendingAccount(address _address) external;
function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external; function commitPendingAccount(address _address, address _ethAddress, bytes32 _codeHash) external;
function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded); function testAndSetAccountLoaded(address _address) external returns (bool _wasAccountAlreadyLoaded);
......
...@@ -25,7 +25,13 @@ interface iOVM_StateTransitioner { ...@@ -25,7 +25,13 @@ interface iOVM_StateTransitioner {
function proveContractState( function proveContractState(
address _ovmContractAddress, 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 bytes calldata _stateTrieWitness
) external; ) external;
...@@ -33,7 +39,6 @@ interface iOVM_StateTransitioner { ...@@ -33,7 +39,6 @@ interface iOVM_StateTransitioner {
address _ovmContractAddress, address _ovmContractAddress,
bytes32 _key, bytes32 _key,
bytes32 _value, bytes32 _value,
bytes calldata _stateTrieWitness,
bytes calldata _storageTrieWitness bytes calldata _storageTrieWitness
) external; ) external;
...@@ -53,7 +58,7 @@ interface iOVM_StateTransitioner { ...@@ -53,7 +58,7 @@ interface iOVM_StateTransitioner {
function commitContractState( function commitContractState(
address _ovmContractAddress, address _ovmContractAddress,
Lib_OVMCodec.Account calldata _account, Lib_OVMCodec.EVMAccount calldata _account,
bytes calldata _stateTrieWitness bytes calldata _stateTrieWitness
) external; ) external;
......
...@@ -4,12 +4,24 @@ pragma experimental ABIEncoderV2; ...@@ -4,12 +4,24 @@ pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol"; import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/** /**
* @title Lib_OVMCodec * @title Lib_OVMCodec
*/ */
library 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 * * Enums *
*********/ *********/
...@@ -68,13 +80,6 @@ library Lib_OVMCodec { ...@@ -68,13 +80,6 @@ library Lib_OVMCodec {
bytes data; bytes data;
} }
struct ProofMatrix {
bool checkNonce;
bool checkBalance;
bool checkStorageRoot;
bool checkCodeHash;
}
struct QueueElement { struct QueueElement {
uint256 timestamp; uint256 timestamp;
bytes32 batchRoot; bytes32 batchRoot;
...@@ -107,13 +112,13 @@ library Lib_OVMCodec { ...@@ -107,13 +112,13 @@ library Lib_OVMCodec {
EOATransaction memory _decoded 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({ return EOATransaction({
nonce: Lib_RLPReader.toUint(decoded[0]), nonce: Lib_RLPReader.readUint256(decoded[0]),
gasLimit: Lib_RLPReader.toUint(decoded[2]), gasLimit: Lib_RLPReader.readUint256(decoded[2]),
target: Lib_RLPReader.toAddress(decoded[3]), target: Lib_RLPReader.readAddress(decoded[3]),
data: Lib_RLPReader.toBytes(decoded[5]) data: Lib_RLPReader.readBytes(decoded[5])
}); });
} }
...@@ -158,4 +163,77 @@ library Lib_OVMCodec { ...@@ -158,4 +163,77 @@ library Lib_OVMCodec {
{ {
return keccak256(encodeTransaction(_transaction)); 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.writeUint(_account.nonce);
raw[1] = Lib_RLPWriter.writeUint(_account.balance);
raw[2] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.storageRoot));
raw[3] = Lib_RLPWriter.writeBytes(abi.encodePacked(_account.codeHash));
return Lib_RLPWriter.writeList(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])
});
}
} }
...@@ -20,7 +20,7 @@ library Lib_RLPWriter { ...@@ -20,7 +20,7 @@ library Lib_RLPWriter {
* @param _in The byte string to encode. * @param _in The byte string to encode.
* @return _out The RLP encoded string in bytes. * @return _out The RLP encoded string in bytes.
*/ */
function encodeBytes( function writeBytes(
bytes memory _in bytes memory _in
) )
internal internal
...@@ -34,7 +34,7 @@ library Lib_RLPWriter { ...@@ -34,7 +34,7 @@ library Lib_RLPWriter {
if (_in.length == 1 && uint8(_in[0]) < 128) { if (_in.length == 1 && uint8(_in[0]) < 128) {
encoded = _in; encoded = _in;
} else { } else {
encoded = Lib_BytesUtils.concat(encodeLength(_in.length, 128), _in); encoded = Lib_BytesUtils.concat(_writeLength(_in.length, 128), _in);
} }
return encoded; return encoded;
...@@ -45,7 +45,7 @@ library Lib_RLPWriter { ...@@ -45,7 +45,7 @@ library Lib_RLPWriter {
* @param _in The list of RLP encoded byte strings. * @param _in The list of RLP encoded byte strings.
* @return _out The RLP encoded list of items in bytes. * @return _out The RLP encoded list of items in bytes.
*/ */
function encodeList( function writeList(
bytes[] memory _in bytes[] memory _in
) )
internal internal
...@@ -54,8 +54,8 @@ library Lib_RLPWriter { ...@@ -54,8 +54,8 @@ library Lib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
bytes memory list = flatten(_in); bytes memory list = _flatten(_in);
return Lib_BytesUtils.concat(encodeLength(list.length, 192), list); return Lib_BytesUtils.concat(_writeLength(list.length, 192), list);
} }
/** /**
...@@ -63,7 +63,7 @@ library Lib_RLPWriter { ...@@ -63,7 +63,7 @@ library Lib_RLPWriter {
* @param _in The string to encode. * @param _in The string to encode.
* @return _out The RLP encoded string in bytes. * @return _out The RLP encoded string in bytes.
*/ */
function encodeString( function writeString(
string memory _in string memory _in
) )
internal internal
...@@ -72,7 +72,7 @@ library Lib_RLPWriter { ...@@ -72,7 +72,7 @@ library Lib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return encodeBytes(bytes(_in)); return writeBytes(bytes(_in));
} }
/** /**
...@@ -80,7 +80,7 @@ library Lib_RLPWriter { ...@@ -80,7 +80,7 @@ library Lib_RLPWriter {
* @param _in The address to encode. * @param _in The address to encode.
* @return _out The RLP encoded address in bytes. * @return _out The RLP encoded address in bytes.
*/ */
function encodeAddress( function writeAddress(
address _in address _in
) )
internal internal
...@@ -97,7 +97,7 @@ library Lib_RLPWriter { ...@@ -97,7 +97,7 @@ library Lib_RLPWriter {
inputBytes := m inputBytes := m
} }
return encodeBytes(inputBytes); return writeBytes(inputBytes);
} }
/** /**
...@@ -105,7 +105,7 @@ library Lib_RLPWriter { ...@@ -105,7 +105,7 @@ library Lib_RLPWriter {
* @param _in The uint to encode. * @param _in The uint to encode.
* @return _out The RLP encoded uint in bytes. * @return _out The RLP encoded uint in bytes.
*/ */
function encodeUint( function writeUint(
uint _in uint _in
) )
internal internal
...@@ -114,7 +114,7 @@ library Lib_RLPWriter { ...@@ -114,7 +114,7 @@ library Lib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return encodeBytes(toBinary(_in)); return writeBytes(_toBinary(_in));
} }
/** /**
...@@ -122,7 +122,7 @@ library Lib_RLPWriter { ...@@ -122,7 +122,7 @@ library Lib_RLPWriter {
* @param _in The int to encode. * @param _in The int to encode.
* @return _out The RLP encoded int in bytes. * @return _out The RLP encoded int in bytes.
*/ */
function encodeInt( function writeInt(
int _in int _in
) )
internal internal
...@@ -131,7 +131,7 @@ library Lib_RLPWriter { ...@@ -131,7 +131,7 @@ library Lib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return encodeUint(uint(_in)); return writeUint(uint(_in));
} }
/** /**
...@@ -139,7 +139,7 @@ library Lib_RLPWriter { ...@@ -139,7 +139,7 @@ library Lib_RLPWriter {
* @param _in The bool to encode. * @param _in The bool to encode.
* @return _out The RLP encoded bool in bytes. * @return _out The RLP encoded bool in bytes.
*/ */
function encodeBool( function writeBool(
bool _in bool _in
) )
internal internal
...@@ -164,7 +164,7 @@ library Lib_RLPWriter { ...@@ -164,7 +164,7 @@ library Lib_RLPWriter {
* @param _offset 128 if item is string, 192 if item is list. * @param _offset 128 if item is string, 192 if item is list.
* @return _encoded RLP encoded bytes. * @return _encoded RLP encoded bytes.
*/ */
function encodeLength( function _writeLength(
uint _len, uint _len,
uint _offset uint _offset
) )
...@@ -203,7 +203,7 @@ library Lib_RLPWriter { ...@@ -203,7 +203,7 @@ library Lib_RLPWriter {
* @param _x The integer to encode. * @param _x The integer to encode.
* @return _binary RLP encoded bytes. * @return _binary RLP encoded bytes.
*/ */
function toBinary( function _toBinary(
uint _x uint _x
) )
private private
...@@ -239,7 +239,7 @@ library Lib_RLPWriter { ...@@ -239,7 +239,7 @@ library Lib_RLPWriter {
* @param _src Source location. * @param _src Source location.
* @param _len Length of memory to copy. * @param _len Length of memory to copy.
*/ */
function memcpy( function _memcpy(
uint _dest, uint _dest,
uint _src, uint _src,
uint _len uint _len
...@@ -273,7 +273,7 @@ library Lib_RLPWriter { ...@@ -273,7 +273,7 @@ library Lib_RLPWriter {
* @param _list List of byte strings to flatten. * @param _list List of byte strings to flatten.
* @return _flattened The flattened byte string. * @return _flattened The flattened byte string.
*/ */
function flatten( function _flatten(
bytes[] memory _list bytes[] memory _list
) )
private private
...@@ -302,7 +302,7 @@ library Lib_RLPWriter { ...@@ -302,7 +302,7 @@ library Lib_RLPWriter {
uint listPtr; uint listPtr;
assembly { listPtr := add(item, 0x20)} assembly { listPtr := add(item, 0x20)}
memcpy(flattenedPtr, listPtr, item.length); _memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length; flattenedPtr += _list[i].length;
} }
......
...@@ -24,7 +24,7 @@ library Lib_SecureMerkleTrie { ...@@ -24,7 +24,7 @@ library Lib_SecureMerkleTrie {
* of a list of RLP-encoded nodes that make a path down to the target node. * 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 * @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed. * 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( function verifyInclusionProof(
bytes memory _key, bytes memory _key,
...@@ -35,7 +35,7 @@ library Lib_SecureMerkleTrie { ...@@ -35,7 +35,7 @@ library Lib_SecureMerkleTrie {
internal internal
view view
returns ( returns (
bool bool _verified
) )
{ {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
...@@ -43,31 +43,28 @@ library Lib_SecureMerkleTrie { ...@@ -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. * the Merkle trie.
* @param _key Key of the node to search for, as a hex string. * @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 * @param _proof Merkle trie inclusion proof for the node *nearest* the
* target node. We effectively need to show that either the key exists and * target node.
* its value differs, or the key does not exist at all.
* @param _root Known root of the Merkle trie. Used to verify that the * @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed. * 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( function verifyExclusionProof(
bytes memory _key, bytes memory _key,
bytes memory _value,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) )
internal internal
view view
returns ( returns (
bool bool _verified
) )
{ {
bytes memory key = _getSecureKey(_key); 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 { ...@@ -79,7 +76,7 @@ library Lib_SecureMerkleTrie {
* Otherwise, we need to modify the trie to handle the new k/v pair. * 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 * @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed. * included proof is correctly constructed.
* @return Root hash of the newly constructed trie. * @return _updatedRoot Root hash of the newly constructed trie.
*/ */
function update( function update(
bytes memory _key, bytes memory _key,
...@@ -90,7 +87,7 @@ library Lib_SecureMerkleTrie { ...@@ -90,7 +87,7 @@ library Lib_SecureMerkleTrie {
internal internal
view view
returns ( returns (
bytes32 bytes32 _updatedRoot
) )
{ {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
...@@ -102,7 +99,8 @@ library Lib_SecureMerkleTrie { ...@@ -102,7 +99,8 @@ library Lib_SecureMerkleTrie {
* @param _key Key to search for, as hex bytes. * @param _key Key to search for, as hex bytes.
* @param _proof Merkle trie inclusion proof for the key. * @param _proof Merkle trie inclusion proof for the key.
* @param _root Known root of the Merkle trie. * @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( function get(
bytes memory _key, bytes memory _key,
...@@ -112,8 +110,8 @@ library Lib_SecureMerkleTrie { ...@@ -112,8 +110,8 @@ library Lib_SecureMerkleTrie {
internal internal
view view
returns ( returns (
bool, bool _exists,
bytes memory bytes memory _value
) )
{ {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
...@@ -124,7 +122,7 @@ library Lib_SecureMerkleTrie { ...@@ -124,7 +122,7 @@ library Lib_SecureMerkleTrie {
* Computes the root hash for a trie with a single node. * Computes the root hash for a trie with a single node.
* @param _key Key for the single node. * @param _key Key for the single node.
* @param _value Value for the single node. * @param _value Value for the single node.
* @return Hash of the trie. * @return _updatedRoot Hash of the trie.
*/ */
function getSingleNodeRootHash( function getSingleNodeRootHash(
bytes memory _key, bytes memory _key,
...@@ -133,7 +131,7 @@ library Lib_SecureMerkleTrie { ...@@ -133,7 +131,7 @@ library Lib_SecureMerkleTrie {
internal internal
view view
returns ( returns (
bytes32 bytes32 _updatedRoot
) )
{ {
bytes memory key = _getSecureKey(_key); bytes memory key = _getSecureKey(_key);
...@@ -145,13 +143,18 @@ library Lib_SecureMerkleTrie { ...@@ -145,13 +143,18 @@ library Lib_SecureMerkleTrie {
* Private Functions * * 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( function _getSecureKey(
bytes memory _key bytes memory _key
) )
private private
pure pure
returns ( returns (
bytes memory bytes memory _secureKey
) )
{ {
return abi.encodePacked(keccak256(_key)); return abi.encodePacked(keccak256(_key));
......
...@@ -35,15 +35,18 @@ library Lib_ECDSAUtils { ...@@ -35,15 +35,18 @@ library Lib_ECDSAUtils {
) )
{ {
bytes32 messageHash; bytes32 messageHash;
uint8 v;
if (_isEthSignedMessage) { if (_isEthSignedMessage) {
messageHash = getEthSignedMessageHash(_message); messageHash = getEthSignedMessageHash(_message);
v = _v;
} else { } else {
messageHash = getNativeMessageHash(_message); messageHash = getNativeMessageHash(_message);
v = (_v - uint8(_chainId) * 2) - 8;
} }
return ecrecover( return ecrecover(
messageHash, messageHash,
(_v - uint8(_chainId) * 2) - 8, v,
_r, _r,
_s _s
); );
......
...@@ -151,10 +151,10 @@ library Lib_EthUtils { ...@@ -151,10 +151,10 @@ library Lib_EthUtils {
) )
{ {
bytes[] memory encoded = new bytes[](2); bytes[] memory encoded = new bytes[](2);
encoded[0] = Lib_RLPWriter.encodeAddress(_creator); encoded[0] = Lib_RLPWriter.writeAddress(_creator);
encoded[1] = Lib_RLPWriter.encodeUint(_nonce); encoded[1] = Lib_RLPWriter.writeUint(_nonce);
bytes memory encodedList = Lib_RLPWriter.encodeList(encoded); bytes memory encodedList = Lib_RLPWriter.writeList(encoded);
return getAddressFromHash(keccak256(encodedList)); return getAddressFromHash(keccak256(encodedList));
} }
......
...@@ -15,6 +15,11 @@ library Lib_MerkleUtils { ...@@ -15,6 +15,11 @@ library Lib_MerkleUtils {
bytes32 _root bytes32 _root
) )
{ {
require(
_hashes.length > 0,
"Must provide at least one leaf hash."
);
if (_hashes.length == 1) { if (_hashes.length == 1) {
return _hashes[0]; return _hashes[0];
} }
......
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0;
/**
* @title Lib_SafeExecutionManagerWrapper
*/
library Lib_SafeExecutionManagerWrapper {
/**********************
* Internal Functions *
**********************/
/**
* Makes an ovmCALL and performs all the necessary safety checks.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @param _gasLimit Gas limit for the call.
* @param _target Address to call.
* @param _calldata Data to send to the call.
* @return _success Whether or not the call reverted.
* @return _returndata Data returned by the call.
*/
function safeCALL(
address _ovmExecutionManager,
uint256 _gasLimit,
address _target,
bytes memory _calldata
)
internal
returns (
bool _success,
bytes memory _returndata
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_ovmExecutionManager,
abi.encodeWithSignature(
"ovmCALL(uint256,address,bytes)",
_gasLimit,
_target,
_calldata
)
);
return abi.decode(returndata, (bool, bytes));
}
/**
* Performs an ovmCREATE and the necessary safety checks.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @param _gasLimit Gas limit for the creation.
* @param _bytecode Code for the new contract.
* @return _contract Address of the created contract.
*/
function safeCREATE(
address _ovmExecutionManager,
uint256 _gasLimit,
bytes memory _bytecode
)
internal
returns (
address _contract
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_ovmExecutionManager,
_gasLimit,
abi.encodeWithSignature(
"ovmCREATE(bytes)",
_bytecode
)
);
return abi.decode(returndata, (address));
}
/**
* Performs a safe ovmCHAINID call.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @return _CHAINID Result of calling ovmCHAINID.
*/
function safeCHAINID(
address _ovmExecutionManager
)
internal
returns (
uint256 _CHAINID
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_ovmExecutionManager,
abi.encodeWithSignature(
"ovmCHAINID()"
)
);
return abi.decode(returndata, (uint256));
}
/**
* Performs a safe ovmADDRESS call.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @return _ADDRESS Result of calling ovmADDRESS.
*/
function safeADDRESS(
address _ovmExecutionManager
)
internal
returns (
address _ADDRESS
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_ovmExecutionManager,
abi.encodeWithSignature(
"ovmADDRESS()"
)
);
return abi.decode(returndata, (address));
}
/**
* Performs a safe ovmGETNONCE call.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @return _nonce Result of calling ovmGETNONCE.
*/
function safeGETNONCE(
address _ovmExecutionManager
)
internal
returns (
uint256 _nonce
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
_ovmExecutionManager,
abi.encodeWithSignature(
"ovmGETNONCE()"
)
);
return abi.decode(returndata, (uint256));
}
/**
* Performs a safe ovmSETNONCE call.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @param _nonce New account nonce.
*/
function safeSETNONCE(
address _ovmExecutionManager,
uint256 _nonce
)
internal
{
_safeExecutionManagerInteraction(
_ovmExecutionManager,
abi.encodeWithSignature(
"ovmSETNONCE(uint256)",
_nonce
)
);
}
/*********************
* Private Functions *
*********************/
/**
* Performs an ovm interaction and the necessary safety checks.
* @param _ovmExecutionManager Address of the OVM_ExecutionManager.
* @param _gasLimit Gas limit for the interaction.
* @param _calldata Data to send to the OVM_ExecutionManager (encoded with sighash).
* @return _returndata Data sent back by the OVM_ExecutionManager.
*/
function _safeExecutionManagerInteraction(
address _ovmExecutionManager,
uint256 _gasLimit,
bytes memory _calldata
)
private
returns (
bytes memory _returndata
)
{
(
bool success,
bytes memory returndata
) = _ovmExecutionManager.call{gas: _gasLimit}(_calldata);
if (success == false) {
assembly {
revert(add(returndata, 0x20), mload(returndata))
}
} else if (returndata.length == 1) {
assembly {
return(0, 1)
}
} else {
return returndata;
}
}
function _safeExecutionManagerInteraction(
address _ovmExecutionManager,
bytes memory _calldata
)
private
returns (
bytes memory _returndata
)
{
return _safeExecutionManagerInteraction(
_ovmExecutionManager,
gasleft(),
_calldata
);
}
}
...@@ -2,18 +2,38 @@ ...@@ -2,18 +2,38 @@
pragma solidity ^0.7.0; pragma solidity ^0.7.0;
contract Helper_SimpleProxy { contract Helper_SimpleProxy {
address private owner;
address private target; address private target;
constructor( constructor() {
address _target owner = msg.sender;
) {
target = _target;
} }
fallback() fallback()
external external
{ {
(bool success, bytes memory returndata) = target.call(msg.data); makeExternalCall(target, msg.data);
}
function setTarget(
address _target
)
public
{
if (msg.sender == owner) {
target = _target;
} else {
makeExternalCall(target, msg.data);
}
}
function makeExternalCall(
address _target,
bytes memory _calldata
)
private
{
(bool success, bytes memory returndata) = _target.call(_calldata);
if (success) { if (success) {
assembly { assembly {
......
...@@ -8,7 +8,7 @@ import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMC ...@@ -8,7 +8,7 @@ import { Lib_OVMCodec } from "../../optimistic-ethereum/libraries/codec/Lib_OVMC
/** /**
* @title TestLib_OVMCodec * @title TestLib_OVMCodec
*/ */
library TestLib_OVMCodec { contract TestLib_OVMCodec {
function decodeEOATransaction( function decodeEOATransaction(
bytes memory _transaction 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,9 +8,9 @@ import { Lib_RLPWriter } from "../../optimistic-ethereum/libraries/rlp/Lib_RLPWr ...@@ -8,9 +8,9 @@ import { Lib_RLPWriter } from "../../optimistic-ethereum/libraries/rlp/Lib_RLPWr
/** /**
* @title TestLib_RLPWriter * @title TestLib_RLPWriter
*/ */
library TestLib_RLPWriter { contract TestLib_RLPWriter {
function encodeBytes( function writeBytes(
bytes memory _in bytes memory _in
) )
public public
...@@ -19,10 +19,10 @@ library TestLib_RLPWriter { ...@@ -19,10 +19,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeBytes(_in); return Lib_RLPWriter.writeBytes(_in);
} }
function encodeList( function writeList(
bytes[] memory _in bytes[] memory _in
) )
public public
...@@ -31,10 +31,10 @@ library TestLib_RLPWriter { ...@@ -31,10 +31,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeList(_in); return Lib_RLPWriter.writeList(_in);
} }
function encodeString( function writeString(
string memory _in string memory _in
) )
public public
...@@ -43,10 +43,10 @@ library TestLib_RLPWriter { ...@@ -43,10 +43,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeString(_in); return Lib_RLPWriter.writeString(_in);
} }
function encodeAddress( function writeAddress(
address _in address _in
) )
public public
...@@ -55,10 +55,10 @@ library TestLib_RLPWriter { ...@@ -55,10 +55,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeAddress(_in); return Lib_RLPWriter.writeAddress(_in);
} }
function encodeUint( function writeUint(
uint _in uint _in
) )
public public
...@@ -67,10 +67,10 @@ library TestLib_RLPWriter { ...@@ -67,10 +67,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeUint(_in); return Lib_RLPWriter.writeUint(_in);
} }
function encodeInt( function writeInt(
int _in int _in
) )
public public
...@@ -79,10 +79,10 @@ library TestLib_RLPWriter { ...@@ -79,10 +79,10 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeInt(_in); return Lib_RLPWriter.writeInt(_in);
} }
function encodeBool( function writeBool(
bool _in bool _in
) )
public public
...@@ -91,6 +91,6 @@ library TestLib_RLPWriter { ...@@ -91,6 +91,6 @@ library TestLib_RLPWriter {
bytes memory _out bytes memory _out
) )
{ {
return Lib_RLPWriter.encodeBool(_in); return Lib_RLPWriter.writeBool(_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
*/
library 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,
Lib_OVMCodec.ProofMatrix memory _proofMatrix,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountState(
_address,
_accountState,
_proofMatrix,
_stateTrieWitness,
_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 proveAccountState(
address _address,
Lib_OVMCodec.Account memory _accountState,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountState(
_address,
_accountState,
_stateTrieWitness,
_stateTrieRoot
);
}
function proveAccountNonce(
address _address,
uint256 _nonce,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountNonce(
_address,
_nonce,
_stateTrieWitness,
_stateTrieRoot
);
}
function proveAccountBalance(
address _address,
uint256 _balance,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountBalance(
_address,
_balance,
_stateTrieWitness,
_stateTrieRoot
);
}
function proveAccountStorageRoot(
address _address,
bytes32 _storageRoot,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountStorageRoot(
_address,
_storageRoot,
_stateTrieWitness,
_stateTrieRoot
);
}
function proveAccountCodeHash(
address _address,
bytes32 _codeHash,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bool)
{
return Lib_EthMerkleTrie.proveAccountCodeHash(
_address,
_codeHash,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountState(
address _address,
Lib_OVMCodec.EVMAccount memory _accountState,
Lib_OVMCodec.ProofMatrix memory _proofMatrix,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountState(
_address,
_accountState,
_proofMatrix,
_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
);
}
function updateAccountState(
address _address,
Lib_OVMCodec.Account memory _accountState,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountState(
_address,
_accountState,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountNonce(
address _address,
uint256 _nonce,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountNonce(
_address,
_nonce,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountBalance(
address _address,
uint256 _balance,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountBalance(
_address,
_balance,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountStorageRoot(
address _address,
bytes32 _storageRoot,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountStorageRoot(
_address,
_storageRoot,
_stateTrieWitness,
_stateTrieRoot
);
}
function updateAccountCodeHash(
address _address,
bytes32 _codeHash,
bytes memory _stateTrieWitness,
bytes32 _stateTrieRoot
)
public
view
returns (bytes32)
{
return Lib_EthMerkleTrie.updateAccountCodeHash(
_address,
_codeHash,
_stateTrieWitness,
_stateTrieRoot
);
}
}
...@@ -7,7 +7,7 @@ import { Lib_MerkleTrie } from "../../optimistic-ethereum/libraries/trie/Lib_Mer ...@@ -7,7 +7,7 @@ import { Lib_MerkleTrie } from "../../optimistic-ethereum/libraries/trie/Lib_Mer
/** /**
* @title TestLib_MerkleTrie * @title TestLib_MerkleTrie
*/ */
library TestLib_MerkleTrie { contract TestLib_MerkleTrie {
function verifyInclusionProof( function verifyInclusionProof(
bytes memory _key, bytes memory _key,
...@@ -31,7 +31,6 @@ library TestLib_MerkleTrie { ...@@ -31,7 +31,6 @@ library TestLib_MerkleTrie {
function verifyExclusionProof( function verifyExclusionProof(
bytes memory _key, bytes memory _key,
bytes memory _value,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) )
...@@ -43,7 +42,6 @@ library TestLib_MerkleTrie { ...@@ -43,7 +42,6 @@ library TestLib_MerkleTrie {
{ {
return Lib_MerkleTrie.verifyExclusionProof( return Lib_MerkleTrie.verifyExclusionProof(
_key, _key,
_value,
_proof, _proof,
_root _root
); );
......
...@@ -8,7 +8,7 @@ import { Lib_SecureMerkleTrie } from "../../optimistic-ethereum/libraries/trie/L ...@@ -8,7 +8,7 @@ import { Lib_SecureMerkleTrie } from "../../optimistic-ethereum/libraries/trie/L
/** /**
* @title TestLib_SecureMerkleTrie * @title TestLib_SecureMerkleTrie
*/ */
library TestLib_SecureMerkleTrie { contract TestLib_SecureMerkleTrie {
function verifyInclusionProof( function verifyInclusionProof(
bytes memory _key, bytes memory _key,
...@@ -32,7 +32,6 @@ library TestLib_SecureMerkleTrie { ...@@ -32,7 +32,6 @@ library TestLib_SecureMerkleTrie {
function verifyExclusionProof( function verifyExclusionProof(
bytes memory _key, bytes memory _key,
bytes memory _value,
bytes memory _proof, bytes memory _proof,
bytes32 _root bytes32 _root
) )
...@@ -44,7 +43,6 @@ library TestLib_SecureMerkleTrie { ...@@ -44,7 +43,6 @@ library TestLib_SecureMerkleTrie {
{ {
return Lib_SecureMerkleTrie.verifyExclusionProof( return Lib_SecureMerkleTrie.verifyExclusionProof(
_key, _key,
_value,
_proof, _proof,
_root _root
); );
......
...@@ -7,7 +7,7 @@ import { Lib_Bytes32Utils } from "../../optimistic-ethereum/libraries/utils/Lib_ ...@@ -7,7 +7,7 @@ import { Lib_Bytes32Utils } from "../../optimistic-ethereum/libraries/utils/Lib_
/** /**
* @title TestLib_Byte32Utils * @title TestLib_Byte32Utils
*/ */
library TestLib_Bytes32Utils { contract TestLib_Bytes32Utils {
function toBool( function toBool(
bytes32 _in bytes32 _in
......
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.0; pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
/* Library Imports */ /* Library Imports */
import { Lib_BytesUtils } from "../../optimistic-ethereum/libraries/utils/Lib_BytesUtils.sol"; import { Lib_BytesUtils } from "../../optimistic-ethereum/libraries/utils/Lib_BytesUtils.sol";
...@@ -7,7 +8,7 @@ import { Lib_BytesUtils } from "../../optimistic-ethereum/libraries/utils/Lib_By ...@@ -7,7 +8,7 @@ import { Lib_BytesUtils } from "../../optimistic-ethereum/libraries/utils/Lib_By
/** /**
* @title TestLib_BytesUtils * @title TestLib_BytesUtils
*/ */
library TestLib_BytesUtils { contract TestLib_BytesUtils {
function concat( function concat(
bytes memory _preBytes, bytes memory _preBytes,
...@@ -39,24 +40,10 @@ library TestLib_BytesUtils { ...@@ -39,24 +40,10 @@ library TestLib_BytesUtils {
); );
} }
function slice(
bytes memory _bytes,
uint256 _start
)
public
pure
returns (bytes memory)
{
return Lib_BytesUtils.slice(
_bytes,
_start
);
}
function toBytes32( function toBytes32(
bytes memory _bytes bytes memory _bytes
) )
internal public
pure pure
returns (bytes32) returns (bytes32)
{ {
......
...@@ -7,7 +7,7 @@ import { Lib_ECDSAUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EC ...@@ -7,7 +7,7 @@ import { Lib_ECDSAUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EC
/** /**
* @title TestLib_ECDSAUtils * @title TestLib_ECDSAUtils
*/ */
library TestLib_ECDSAUtils { contract TestLib_ECDSAUtils {
function recover( function recover(
bytes memory _message, bytes memory _message,
......
...@@ -8,7 +8,7 @@ import { Lib_EthUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EthU ...@@ -8,7 +8,7 @@ import { Lib_EthUtils } from "../../optimistic-ethereum/libraries/utils/Lib_EthU
/** /**
* @title TestLib_EthUtils * @title TestLib_EthUtils
*/ */
library TestLib_EthUtils { contract TestLib_EthUtils {
function getCode( function getCode(
address _address, address _address,
......
...@@ -8,7 +8,7 @@ import { Lib_MerkleUtils } from "../../optimistic-ethereum/libraries/utils/Lib_M ...@@ -8,7 +8,7 @@ import { Lib_MerkleUtils } from "../../optimistic-ethereum/libraries/utils/Lib_M
/** /**
* @title TestLib_MerkleUtils * @title TestLib_MerkleUtils
*/ */
library TestLib_MerkleUtils { contract TestLib_MerkleUtils {
function getMerkleRoot( function getMerkleRoot(
bytes32[] memory _hashes bytes32[] memory _hashes
......
...@@ -7,15 +7,18 @@ ...@@ -7,15 +7,18 @@
"build": "yarn run build:contracts && yarn run build:typescript && yarn run build:copy", "build": "yarn run build:contracts && yarn run build:typescript && yarn run build:copy",
"build:typescript": "tsc -p .", "build:typescript": "tsc -p .",
"build:contracts": "buidler compile", "build:contracts": "buidler compile",
"build:dump": "ts-node \"bin/take-dump.ts\"",
"build:copy": "copyfiles -u 2 \"contracts/optimistic-ethereum/**/*.sol\" \"build/contracts\"", "build:copy": "copyfiles -u 2 \"contracts/optimistic-ethereum/**/*.sol\" \"build/contracts\"",
"test": "yarn run test:contracts", "test": "yarn run test:contracts",
"test:contracts": "buidler test \"test/contracts/OVM/chain/OVM_StateCommitmentChain.spec.ts\" --show-stack-traces", "test:contracts": "buidler test --show-stack-traces",
"lint": "tslint --format stylish --project .", "lint": "yarn run lint:typescript",
"fix": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"", "lint:typescript": "tslint --format stylish --project .",
"lint:fix": "yarn run lint:fix:typescript",
"lint:fix:typescript": "prettier --config prettier-config.json --write \"buidler.config.ts\" \"{src,test}/**/*.ts\"",
"clean": "rm -rf ./artifacts ./build ./cache" "clean": "rm -rf ./artifacts ./build ./cache"
}, },
"devDependencies": { "devDependencies": {
"@eth-optimism/smock": "^0.1.0", "@eth-optimism/smock": "^0.0.2",
"@nomiclabs/buidler": "^1.4.4", "@nomiclabs/buidler": "^1.4.4",
"@nomiclabs/buidler-ethers": "^2.0.0", "@nomiclabs/buidler-ethers": "^2.0.0",
"@nomiclabs/buidler-waffle": "^2.0.0", "@nomiclabs/buidler-waffle": "^2.0.0",
...@@ -30,9 +33,15 @@ ...@@ -30,9 +33,15 @@
"ethereum-waffle": "3.0.0", "ethereum-waffle": "3.0.0",
"ethers": "5.0.0", "ethers": "5.0.0",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"ganache-core": "^2.12.1",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"merkle-patricia-tree": "git+https://github.com/kfichter/merkle-patricia-tree",
"mkdirp": "^1.0.4",
"mocha": "^8.1.1", "mocha": "^8.1.1",
"prettier": "^2.1.2", "prettier": "^2.1.2",
"random-bytes-seed": "^1.0.3",
"rlp": "^2.2.6",
"seedrandom": "^3.0.5",
"ts-node": "^9.0.0", "ts-node": "^9.0.0",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0", "tslint-config-prettier": "^1.18.0",
......
import * as path from 'path'
import { ethers, ContractFactory, Signer } from 'ethers'
import { Interface } from 'ethers/lib/utils'
export const getContractDefinition = (name: string): any => {
return require(path.join(__dirname, '../artifacts', `${name}.json`))
}
export const getContractInterface = (name: string): Interface => {
const definition = getContractDefinition(name)
return new ethers.utils.Interface(definition.abi)
}
export const getContractFactory = (
name: string,
signer?: Signer
): ContractFactory => {
const definition = getContractDefinition(name)
const contractInterface = getContractInterface(name)
return new ContractFactory(contractInterface, definition.bytecode, signer)
}
/* External Imports */
import { Signer, ContractFactory, Contract } from 'ethers'
/* Internal Imports */
import { getContractFactory } from '../contract-defs'
export interface RollupDeployConfig {
deploymentSigner: Signer
ovmGasMeteringConfig: {
minTransactionGasLimit: number
maxTransactionGasLimit: number
maxGasPerQueuePerEpoch: number
secondsPerEpoch: number
}
transactionChainConfig: {
sequencer: string | Signer
forceInclusionPeriodSeconds: number
}
whitelistConfig: {
owner: string | Signer
allowArbitraryContractDeployment: boolean
}
}
export interface ContractDeployParameters {
factory: ContractFactory
params?: any[]
afterDeploy?: (contracts?: { [name: string]: Contract }) => Promise<void>
}
export interface ContractDeployConfig {
[name: string]: ContractDeployParameters
}
export const makeContractDeployConfig = async (
config: RollupDeployConfig,
AddressManager: Contract
): Promise<ContractDeployConfig> => {
return {
OVM_L1CrossDomainMessenger: {
factory: getContractFactory('OVM_L1CrossDomainMessenger'),
params: [AddressManager.address],
},
OVM_L2CrossDomainMessenger: {
factory: getContractFactory('OVM_L2CrossDomainMessenger'),
params: [AddressManager.address],
},
OVM_CanonicalTransactionChain: {
factory: getContractFactory('OVM_CanonicalTransactionChain'),
params: [
AddressManager.address,
config.transactionChainConfig.forceInclusionPeriodSeconds,
],
afterDeploy: async (): Promise<void> => {
const sequencer = config.transactionChainConfig.sequencer
const sequencerAddress =
typeof sequencer === 'string'
? sequencer
: await sequencer.getAddress()
await AddressManager.setAddress('Sequencer', sequencerAddress)
},
},
OVM_StateCommitmentChain: {
factory: getContractFactory('OVM_StateCommitmentChain'),
params: [AddressManager.address],
},
OVM_ExecutionManager: {
factory: getContractFactory('OVM_ExecutionManager'),
params: [AddressManager.address],
},
OVM_StateManager: {
factory: getContractFactory('OVM_StateManager'),
params: [await config.deploymentSigner.getAddress()],
afterDeploy: async (contracts): Promise<void> => {
await contracts.OVM_StateManager.setExecutionManager(
contracts.OVM_ExecutionManager.address
)
},
},
OVM_StateManagerFactory: {
factory: getContractFactory('OVM_StateManagerFactory'),
},
OVM_L1ToL2TransactionQueue: {
factory: getContractFactory('OVM_L1ToL2TransactionQueue'),
params: [AddressManager.address],
},
OVM_FraudVerifier: {
factory: getContractFactory('OVM_FraudVerifier'),
params: [AddressManager.address],
},
OVM_StateTransitionerFactory: {
factory: getContractFactory('OVM_StateTransitionerFactory'),
},
}
}
/* External Imports */
import { Signer, Contract, ContractFactory } from 'ethers'
/* Internal Imports */
import { RollupDeployConfig, makeContractDeployConfig } from './config'
import { getContractFactory } from '../contract-defs'
export interface DeployResult {
AddressManager: Contract
failedDeployments: string[]
contracts: {
[name: string]: Contract
}
}
export const deploy = async (
config: RollupDeployConfig
): Promise<DeployResult> => {
const Factory__SimpleProxy: ContractFactory = getContractFactory(
'Helper_SimpleProxy',
config.deploymentSigner
)
const AddressManager: Contract = await getContractFactory(
'Lib_AddressManager',
config.deploymentSigner
).deploy()
const contractDeployConfig = await makeContractDeployConfig(
config,
AddressManager
)
const failedDeployments: string[] = []
const contracts: {
[name: string]: Contract
} = {}
for (const [name, contractDeployParameters] of Object.entries(
contractDeployConfig
)) {
const SimpleProxy = await Factory__SimpleProxy.deploy()
await AddressManager.setAddress(name, SimpleProxy.address)
try {
contracts[name] = await contractDeployParameters.factory
.connect(config.deploymentSigner)
.deploy(...contractDeployParameters.params)
await SimpleProxy.setTarget(contracts[name].address)
} catch (err) {
failedDeployments.push(name)
}
}
for (const contractDeployParameters of Object.values(contractDeployConfig)) {
if (contractDeployParameters.afterDeploy) {
await contractDeployParameters.afterDeploy(contracts)
}
}
return {
AddressManager,
failedDeployments,
contracts,
}
}
export { RollupDeployConfig } from './config'
export { deploy } from './deploy'
/* External Imports */
import * as path from 'path'
import { ethers } from 'ethers'
import * as Ganache from 'ganache-core'
/* Internal Imports */
import { deploy, RollupDeployConfig } from './contract-deployment'
import { getContractDefinition } from './contract-defs'
import { keccak256 } from 'ethers/lib/utils'
type Accounts = Array<{
originalAddress: string
address: string
code: string
}>
interface StorageDump {
[key: string]: string
}
export interface StateDump {
contracts: {
ovmExecutionManager: string
ovmStateManager: string
}
accounts: {
[address: string]: {
balance: number
nonce: number
code: string
storage: StorageDump
}
}
}
/**
* Finds the addresses of all accounts changed in the state.
* @param cStateManager Instance of the callback-based internal vm StateManager.
* @returns Array of changed addresses.
*/
const getChangedAccounts = async (cStateManager: any): Promise<string[]> => {
return new Promise<string[]>((resolve, reject) => {
const accounts: string[] = []
const stream = cStateManager._trie.createReadStream()
stream.on('data', (val: any) => {
accounts.push(val.key.toString('hex'))
})
stream.on('end', () => {
resolve(accounts)
})
})
}
/**
* Generates a storage dump for a given address.
* @param cStateManager Instance of the callback-based internal vm StateManager.
* @param address Address to generate a state dump for.
*/
const getStorageDump = async (
cStateManager: any,
address: string
): Promise<StorageDump> => {
return new Promise<StorageDump>((resolve, reject) => {
cStateManager._getStorageTrie(address, (err: any, trie: any) => {
if (err) {
reject(err)
}
const storage: StorageDump = {}
const stream = trie.createReadStream()
stream.on('data', (val: any) => {
storage[val.key.toString('hex')] = val.value.toString('hex')
})
stream.on('end', () => {
resolve(storage)
})
})
})
}
/**
* Replaces old addresses found in a storage dump with new ones.
* @param storageDump Storage dump to sanitize.
* @param accounts Set of accounts to sanitize with.
* @returns Sanitized storage dump.
*/
const sanitizeStorageDump = (
storageDump: StorageDump,
accounts: Accounts
): StorageDump => {
for (const [key, value] of Object.entries(storageDump)) {
let parsedKey = key
let parsedValue = value
for (const account of accounts) {
const re = new RegExp(`${account.originalAddress}`, 'g')
parsedValue = parsedValue.replace(re, account.address)
parsedKey = parsedKey.replace(re, account.address)
}
if (parsedKey !== key) {
delete storageDump[key]
}
storageDump[parsedKey] = parsedValue
}
return storageDump
}
export const makeStateDump = async (): Promise<any> => {
const ganache = (Ganache as any).provider({
gasLimit: 100_000_000,
allowUnlimitedContractSize: true,
accounts: [
{
secretKey:
'0x29f3edee0ad3abf8e2699402e0e28cd6492c9be7eaab00d732a791c33552f797',
balance: 10000000000000000000000000000000000,
},
],
})
const provider = new ethers.providers.Web3Provider(ganache)
const signer = provider.getSigner(0)
const config: RollupDeployConfig = {
deploymentSigner: signer,
ovmGasMeteringConfig: {
minTransactionGasLimit: 0,
maxTransactionGasLimit: 1_000_000_000,
maxGasPerQueuePerEpoch: 1_000_000_000_000,
secondsPerEpoch: 600,
},
transactionChainConfig: {
sequencer: signer,
forceInclusionPeriodSeconds: 600,
},
whitelistConfig: {
owner: signer,
allowArbitraryContractDeployment: true,
},
}
const deploymentResult = await deploy(config)
const pStateManager = ganache.engine.manager.state.blockchain.vm.pStateManager
const cStateManager = pStateManager._wrapped
const ovmExecutionManagerOriginalAddress = deploymentResult.contracts.OVM_ExecutionManager.address
.slice(2)
.toLowerCase()
const ovmExecutionManagerAddress = 'c0dec0dec0dec0dec0dec0dec0dec0dec0de0000'
const ovmStateManagerOriginalAddress = deploymentResult.contracts.OVM_StateManager.address
.slice(2)
.toLowerCase()
const ovmStateManagerAddress = 'c0dec0dec0dec0dec0dec0dec0dec0dec0de0001'
const l2ToL1MessagePasserDef = getContractDefinition(
'OVM_L2ToL1MessagePasser'
)
const l2ToL1MessagePasserHash = keccak256(
l2ToL1MessagePasserDef.deployedBytecode
)
const l2ToL1MessagePasserAddress = '4200000000000000000000000000000000000000'
const l1MessageSenderDef = getContractDefinition('OVM_L1MessageSender')
const l1MessageSenderHash = keccak256(l1MessageSenderDef.deployedBytecode)
const l1MessageSenderAddress = '4200000000000000000000000000000000000001'
const changedAccounts = await getChangedAccounts(cStateManager)
let deadAddressIndex = 0
const accounts: Accounts = []
for (const originalAddress of changedAccounts) {
const code = (
await pStateManager.getContractCode(originalAddress)
).toString('hex')
const codeHash = keccak256('0x' + code)
if (code.length === 0) {
continue
}
// Sorry for this one!
let address = originalAddress
if (codeHash === l2ToL1MessagePasserHash) {
address = l2ToL1MessagePasserAddress
} else if (codeHash === l1MessageSenderHash) {
address = l1MessageSenderAddress
} else if (originalAddress === ovmExecutionManagerOriginalAddress) {
address = ovmExecutionManagerAddress
} else if (originalAddress === ovmStateManagerOriginalAddress) {
address = ovmStateManagerAddress
} else {
address = `deaddeaddeaddeaddeaddeaddeaddeaddead${deadAddressIndex
.toString(16)
.padStart(4, '0')}`
deadAddressIndex++
}
accounts.push({
originalAddress,
address,
code,
})
}
const dump: StateDump = {
contracts: {
ovmExecutionManager: '0x' + ovmExecutionManagerAddress,
ovmStateManager: '0x' + ovmStateManagerAddress,
},
accounts: {},
}
for (const account of accounts) {
const storageDump = sanitizeStorageDump(
await getStorageDump(cStateManager, account.originalAddress),
accounts
)
dump.accounts[account.address] = {
balance: 0,
nonce: 0,
code: account.code,
storage: storageDump,
}
}
return dump
}
export const getLatestStateDump = (): StateDump => {
return require(path.join(__dirname, '../dumps', `state-dump.latest.json`))
}
export * from './contract-defs'
export * from './contract-dumps'
export * from './contract-deployment'
This diff is collapsed.
...@@ -11,6 +11,8 @@ import { ...@@ -11,6 +11,8 @@ import {
setProxyTarget, setProxyTarget,
NON_NULL_BYTES32, NON_NULL_BYTES32,
ZERO_ADDRESS, ZERO_ADDRESS,
toHexString32,
getEthTime,
} from '../../../helpers' } from '../../../helpers'
import { keccak256 } from 'ethers/lib/utils' import { keccak256 } from 'ethers/lib/utils'
...@@ -112,6 +114,7 @@ describe('OVM_StateCommitmentChain', () => { ...@@ -112,6 +114,7 @@ describe('OVM_StateCommitmentChain', () => {
batch.length batch.length
) )
await OVM_StateCommitmentChain.appendStateBatch(batch) await OVM_StateCommitmentChain.appendStateBatch(batch)
batchHeader.extraData = toHexString32(await getEthTime(ethers.provider))
}) })
describe('when the sender is not the OVM_FraudVerifier', () => { describe('when the sender is not the OVM_FraudVerifier', () => {
......
...@@ -71,7 +71,6 @@ const test_run: TestDefinition = { ...@@ -71,7 +71,6 @@ const test_run: TestDefinition = {
parameters: [ parameters: [
{ {
name: 'run => ovmCALL(ADDRESS_1) => ovmADDRESS', name: 'run => ovmCALL(ADDRESS_1) => ovmADDRESS',
focus: true,
steps: [ steps: [
{ {
functionName: 'run', functionName: 'run',
......
...@@ -17,7 +17,7 @@ describe('OVM_SafetyChecker', () => { ...@@ -17,7 +17,7 @@ describe('OVM_SafetyChecker', () => {
OVM_SafetyChecker = await Factory__OVM_SafetyChecker.deploy() OVM_SafetyChecker = await Factory__OVM_SafetyChecker.deploy()
}) })
describe('isBytecodeSafe()', () => { describe.skip('isBytecodeSafe()', () => {
for (const testName of Object.keys(SAFETY_CHECKER_TEST_JSON)) { for (const testName of Object.keys(SAFETY_CHECKER_TEST_JSON)) {
const test = SAFETY_CHECKER_TEST_JSON[testName] const test = SAFETY_CHECKER_TEST_JSON[testName]
it(`should correctly classify: ${testName}`, async () => { it(`should correctly classify: ${testName}`, async () => {
......
...@@ -10,8 +10,8 @@ import { DUMMY_ACCOUNTS, DUMMY_BYTES32, ZERO_ADDRESS } from '../../../helpers' ...@@ -10,8 +10,8 @@ import { DUMMY_ACCOUNTS, DUMMY_BYTES32, ZERO_ADDRESS } from '../../../helpers'
const EMPTY_ACCOUNT_CODE_HASH = const EMPTY_ACCOUNT_CODE_HASH =
'0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000' '0x00004B1DC0DE000000004B1DC0DE000000004B1DC0DE000000004B1DC0DE0000'
const RLP_NULL_HASH = const KECCAK_256_NULL =
'0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421' '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
describe('OVM_StateManager', () => { describe('OVM_StateManager', () => {
let signer1: Signer let signer1: Signer
...@@ -321,7 +321,7 @@ describe('OVM_StateManager', () => { ...@@ -321,7 +321,7 @@ describe('OVM_StateManager', () => {
) )
).to.deep.include({ ).to.deep.include({
nonce: BigNumber.from(1), nonce: BigNumber.from(1),
codeHash: RLP_NULL_HASH, codeHash: KECCAK_256_NULL,
isFresh: true, isFresh: true,
}) })
}) })
......
/* tslint:disable:no-empty */
import { expect } from '../../../setup'
describe('Lib_OVMCodec', () => {
describe('decodeEOATransaction', () => {
describe('when given a valid RLP-encoded transaction', () => {
it('should return the decoded transaction struct', async () => {})
})
})
describe('encodeTransaction', () => {
it('should ABI encode (packed) the given transaction', async () => {})
})
describe('hashTransaction', () => {
it('should return the hash of the encoded transaction', 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)
})
})
/* tslint:disable:no-empty */
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract } from 'ethers'
/* Internal Imports */
import { Lib_RLPWriter_TEST_JSON } from '../../../data'
const encode = async (Lib_RLPWriter: Contract, input: any): Promise<void> => {
if (Array.isArray(input)) {
const elements = await Promise.all(
input.map(async (el) => {
return encode(Lib_RLPWriter, el)
})
)
return Lib_RLPWriter.writeList(elements)
} else if (Number.isInteger(input)) {
return Lib_RLPWriter.writeUint(input)
} else if (input[0] === '#') {
return Lib_RLPWriter.writeInt(input.slice(1))
} else {
return Lib_RLPWriter.writeString(input)
}
}
describe('Lib_RLPWriter', () => {
let Lib_RLPWriter: Contract
before(async () => {
Lib_RLPWriter = await (
await ethers.getContractFactory('TestLib_RLPWriter')
).deploy()
})
describe('Official Ethereum RLP Tests', () => {
for (const [key, test] of Object.entries(Lib_RLPWriter_TEST_JSON)) {
it(`should properly encode: ${key}`, async () => {
expect(await encode(Lib_RLPWriter, test.in)).to.equal(test.out)
})
}
})
})
import { expect } from '../../../setup'
/* External Imports */
import { ethers } from '@nomiclabs/buidler'
import { Contract } from 'ethers'
/* Internal Imports */
import { TrieTestGenerator } from '../../../helpers'
const NODE_COUNTS = [1, 2, 128, 256, 512, 1024, 2048, 4096]
describe('Lib_MerkleTrie', () => {
let Lib_MerkleTrie: Contract
before(async () => {
Lib_MerkleTrie = await (
await ethers.getContractFactory('TestLib_MerkleTrie')
).deploy()
})
describe('verifyInclusionProof', () => {
for (const nodeCount of NODE_COUNTS) {
describe(`inside a trie with ${nodeCount} nodes`, () => {
let generator: TrieTestGenerator
before(async () => {
generator = await TrieTestGenerator.fromRandom({
seed: `seed.incluson.${nodeCount}`,
nodeCount,
secure: false,
})
})
for (
let i = 0;
i < nodeCount;
i += nodeCount / (nodeCount > 8 ? 8 : 1)
) {
it(`should correctly prove inclusion for node #${i}`, async () => {
const test = await generator.makeInclusionProofTest(i)
expect(
await Lib_MerkleTrie.verifyInclusionProof(
test.key,
test.val,
test.proof,
test.root
)
).to.equal(true)
})
}
})
}
})
describe('update', () => {
for (const nodeCount of NODE_COUNTS) {
describe(`inside a trie with ${nodeCount} nodes`, () => {
let generator: TrieTestGenerator
before(async () => {
generator = await TrieTestGenerator.fromRandom({
seed: `seed.update.${nodeCount}`,
nodeCount,
secure: false,
})
})
for (
let i = 0;
i < nodeCount;
i += nodeCount / (nodeCount > 8 ? 8 : 1)
) {
it(`should correctly update node #${i}`, async () => {
const test = await generator.makeNodeUpdateTest(
i,
'0x1234123412341234'
)
expect(
await Lib_MerkleTrie.update(
test.key,
test.val,
test.proof,
test.root
)
).to.equal(test.newRoot)
})
}
})
}
})
describe('get', () => {
for (const nodeCount of NODE_COUNTS) {
describe(`inside a trie with ${nodeCount} nodes`, () => {
let generator: TrieTestGenerator
before(async () => {
generator = await TrieTestGenerator.fromRandom({
seed: `seed.get.${nodeCount}`,
nodeCount,
secure: false,
})
})
for (
let i = 0;
i < nodeCount;
i += nodeCount / (nodeCount > 8 ? 8 : 1)
) {
it(`should correctly get the value of node #${i}`, async () => {
const test = await generator.makeInclusionProofTest(i)
expect(
await Lib_MerkleTrie.get(test.key, test.proof, test.root)
).to.deep.equal([true, test.val])
})
}
})
}
})
})
/* Internal Imports */
import { Lib_Bytes32Utils_TEST_JSON } from '../../../data'
import { runJsonTest } from '../../../helpers'
describe('Lib_Bytes32Utils', () => {
describe('JSON tests', () => {
runJsonTest('TestLib_Bytes32Utils', Lib_Bytes32Utils_TEST_JSON)
})
})
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
export * from './trie-test-generator'
This diff is collapsed.
This diff is collapsed.
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