Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/pink-cameras-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@eth-optimism/contracts": patch
"@eth-optimism/hardhat-ovm": patch
---

Use optimistic-solc to compile the SequencerEntrypoint. Also introduces a cache invalidation mechanism for hardhat-ovm so that we can push new compiler versions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// SPDX-License-Identifier: MIT
// @unsupported: evm
pragma solidity >0.5.0 <0.8.0;

/* Interface Imports */
import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContractAccount.sol";

/* Library Imports */
import { Lib_BytesUtils } from "../../libraries/utils/Lib_BytesUtils.sol";
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_ECDSAUtils } from "../../libraries/utils/Lib_ECDSAUtils.sol";
import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_SafeExecutionManagerWrapper.sol";
import { Lib_ExecutionManagerWrapper } from "../../libraries/wrappers/Lib_ExecutionManagerWrapper.sol";

/**
* @title OVM_SequencerEntrypoint
Expand All @@ -15,7 +19,7 @@ import { Lib_SafeExecutionManagerWrapper } from "../../libraries/wrappers/Lib_Sa
* This contract is the implementation referenced by the Proxy Sequencer Entrypoint, thus enabling
* the Optimism team to upgrade the decompression of calldata from the Sequencer.
*
* Compiler used: solc
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_SequencerEntrypoint {
Expand Down Expand Up @@ -59,43 +63,56 @@ contract OVM_SequencerEntrypoint {
bytes memory compressedTx = Lib_BytesUtils.slice(msg.data, 66);
bool isEthSignedMessage = transactionType == TransactionType.ETH_SIGNED_MESSAGE;

// Grab the chain ID for the current network.
uint256 chainId;
assembly {
chainId := chainid()
}

// Need to decompress and then re-encode the transaction based on the original encoding.
bytes memory encodedTx = Lib_OVMCodec.encodeEIP155Transaction(
Lib_OVMCodec.decompressEIP155Transaction(compressedTx),
Lib_OVMCodec.decompressEIP155Transaction(
compressedTx,
chainId
),
isEthSignedMessage
);

address target = Lib_ECDSAUtils.recover(
encodedTx,
isEthSignedMessage,
uint8(v),
v,
r,
s
);

if (Lib_SafeExecutionManagerWrapper.safeEXTCODESIZE(target) == 0) {
bool isEmptyContract;
assembly {
isEmptyContract := iszero(extcodesize(target))
}

if (isEmptyContract) {
// ProxyEOA has not yet been deployed for this EOA.
bytes32 messageHash = Lib_ECDSAUtils.getMessageHash(encodedTx, isEthSignedMessage);
Lib_SafeExecutionManagerWrapper.safeCREATEEOA(messageHash, uint8(v), r, s);
Lib_ExecutionManagerWrapper.ovmCREATEEOA(messageHash, v, r, s);
}

// ProxyEOA has been deployed for this EOA, continue to CALL.
bytes memory callbytes = abi.encodeWithSignature(
"execute(bytes,uint8,uint8,bytes32,bytes32)",
Lib_OVMCodec.EOASignatureType sigtype;
if (isEthSignedMessage) {
sigtype = Lib_OVMCodec.EOASignatureType.ETH_SIGNED_MESSAGE;
} else {
sigtype = Lib_OVMCodec.EOASignatureType.EIP155_TRANSACTION;
}

iOVM_ECDSAContractAccount(target).execute(
encodedTx,
isEthSignedMessage,
uint8(v),
sigtype,
v,
r,
s
);

Lib_SafeExecutionManagerWrapper.safeCALL(
gasleft(),
target,
callbytes
);
}


/**********************
* Internal Functions *
Expand All @@ -119,9 +136,7 @@ contract OVM_SequencerEntrypoint {
} if (_transactionType == 2) {
return TransactionType.ETH_SIGNED_MESSAGE;
} else {
Lib_SafeExecutionManagerWrapper.safeREVERT(
"Transaction type must be 0 or 2"
);
revert("Transaction type must be 0 or 2");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,12 @@ library Lib_OVMCodec {
/**
* Decompresses a compressed EIP155 transaction.
* @param _transaction Compressed EIP155 transaction bytes.
* @param _chainId Chain ID this transaction was signed with.
* @return Transaction parsed into a struct.
*/
function decompressEIP155Transaction(
bytes memory _transaction
bytes memory _transaction,
uint256 _chainId
)
internal
returns (
Expand All @@ -171,7 +173,7 @@ library Lib_OVMCodec {
nonce: Lib_BytesUtils.toUint24(_transaction, 6),
to: Lib_BytesUtils.toAddress(_transaction, 9),
data: Lib_BytesUtils.slice(_transaction, 29),
chainId: Lib_SafeExecutionManagerWrapper.safeCHAINID(),
chainId: _chainId,
value: 0
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: MIT
// @unsupported: evm
pragma solidity >0.5.0 <0.8.0;

/* Library Imports */
import { Lib_ErrorUtils } from "../utils/Lib_ErrorUtils.sol";

/**
* @title Lib_ExecutionManagerWrapper
*
* Compiler used: solc
* Runtime target: OVM
*/
library Lib_ExecutionManagerWrapper {

/**********************
* Internal Functions *
**********************/

/**
* Performs a safe ovmGETNONCE call.
* @return _nonce Result of calling ovmGETNONCE.
*/
function ovmGETNONCE()
internal
returns (
uint256 _nonce
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmGETNONCE()"
)
);

return abi.decode(returndata, (uint256));
}

/**
* Performs a safe ovmINCREMENTNONCE call.
*/
function ovmINCREMENTNONCE()
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmINCREMENTNONCE()"
)
);
}

/**
* Performs a safe ovmCREATEEOA call.
* @param _messageHash Message hash which was signed by EOA
* @param _v v value of signature (0 or 1)
* @param _r r value of signature
* @param _s s value of signature
*/
function ovmCREATEEOA(
bytes32 _messageHash,
uint8 _v,
bytes32 _r,
bytes32 _s
)
internal
{
_safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmCREATEEOA(bytes32,uint8,bytes32,bytes32)",
_messageHash,
_v,
_r,
_s
)
);
}

/**
* Calls the ovmL1TXORIGIN opcode.
* @return Address that sent this message from L1.
*/
function ovmL1TXORIGIN()
internal
returns (
address
)
{
bytes memory returndata = _safeExecutionManagerInteraction(
abi.encodeWithSignature(
"ovmL1TXORIGIN()"
)
);

return abi.decode(returndata, (address));
}


/*********************
* Private Functions *
*********************/

/**
* Performs an ovm interaction and the necessary safety checks.
* @param _calldata Data to send to the OVM_ExecutionManager (encoded with sighash).
* @return _returndata Data sent back by the OVM_ExecutionManager.
*/
function _safeExecutionManagerInteraction(
bytes memory _calldata
)
private
returns (
bytes memory
)
{
bytes memory returndata;
assembly {
// kall is a custom yul builtin within optimistic-solc that allows us to directly call
// the execution manager (since `call` would be compiled).
kall(add(_calldata, 0x20), mload(_calldata), 0x0, 0x0)
let size := returndatasize()
returndata := mload(0x40)
mstore(0x40, add(returndata, and(add(add(size, 0x20), 0x1f), not(0x1f))))
mstore(returndata, size)
returndatacopy(add(returndata, 0x20), 0x0, size)
}
return returndata;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ contract TestLib_OVMCodec {
}

function decompressEIP155Transaction(
bytes memory _transaction
bytes memory _transaction,
uint256 _chainId
)
public
returns (
Lib_OVMCodec.EIP155Transaction memory _decompressed
)
{
return Lib_OVMCodec.decompressEIP155Transaction(_transaction);
return Lib_OVMCodec.decompressEIP155Transaction(
_transaction,
_chainId
);
}
}
3 changes: 3 additions & 0 deletions packages/contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ const config: HardhatUserConfig = {
},
},
},
ovm: {
solcVersion: '0.7.6-allow_kall_2', // temporary until we fix the build for 0.7.6
},
typechain: {
outDir: 'dist/types',
target: 'ethers-v5',
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/contract-deployment/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const makeContractDeployConfig = async (
factory: getContractFactory('OVM_ECDSAContractAccount'),
},
OVM_SequencerEntrypoint: {
factory: getContractFactory('OVM_SequencerEntrypoint'),
factory: getContractFactory('OVM_SequencerEntrypoint', undefined, true),
},
OVM_ProxySequencerEntrypoint: {
factory: getContractFactory('OVM_ProxySequencerEntrypoint'),
Expand Down
10 changes: 9 additions & 1 deletion packages/contracts/src/contract-dumps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
const ovmCompiled = [
'OVM_L2ToL1MessagePasser',
'OVM_L2CrossDomainMessenger',
'OVM_SequencerEntrypoint',
'Lib_AddressManager',
'OVM_ETH',
]
Expand Down Expand Up @@ -211,12 +212,19 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
predeploys[name] ||
`0xdeaddeaddeaddeaddeaddeaddeaddeaddead${i.toString(16).padStart(4, '0')}`

let def: any
try {
def = getContractDefinition(name.replace('Proxy__', ''))
} catch (err) {
def = getContractDefinition(name.replace('Proxy__', ''), true)
}

dump.accounts[name] = {
address: deadAddress,
code,
codeHash: keccak256(code),
storage: await getStorageDump(cStateManager, contract.address),
abi: getContractDefinition(name.replace('Proxy__', '')).abi,
abi: def.abi,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { remove0x } from '@eth-optimism/core-utils'

/* Internal Imports */
import { decodeSolidityError } from '../../../helpers'
import { getContractFactory } from '../../../../src'

const callPredeploy = async (
Helper_PredeployCaller: Contract,
Expand Down Expand Up @@ -59,8 +60,10 @@ describe('OVM_ProxySequencerEntrypoint', () => {

Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address)

OVM_SequencerEntrypoint = await (
await ethers.getContractFactory('OVM_SequencerEntrypoint')
OVM_SequencerEntrypoint = await getContractFactory(
'OVM_SequencerEntrypoint',
wallet,
true
).deploy()
})

Expand Down
Loading