Commit 21e47e1f authored by ben's avatar ben Committed by Mark Tyneway

fix(contracts): prevent L2->L1 calls to system contracts

parent 26b39199
---
'@eth-optimism/contracts': patch
---
A small change to the L1 Messenger, which prevents an L2 to L1 call from send calling the CTC.
...@@ -252,6 +252,11 @@ contract OVM_L1CrossDomainMessenger is ...@@ -252,6 +252,11 @@ contract OVM_L1CrossDomainMessenger is
"Provided message has been blocked." "Provided message has been blocked."
); );
require(
_target != resolve("OVM_CanonicalTransactionChain"),
"Cannot send L2->L1 messages to L1 system contracts."
);
xDomainMsgSender = _sender; xDomainMsgSender = _sender;
(bool success, ) = _target.call(_message); (bool success, ) = _target.call(_message);
xDomainMsgSender = DEFAULT_XDOMAIN_SENDER; xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
......
...@@ -66,8 +66,8 @@ Implementation addresses. DO NOT use these addresses directly. ...@@ -66,8 +66,8 @@ Implementation addresses. DO NOT use these addresses directly.
Use their proxied counterparts seen above. Use their proxied counterparts seen above.
OVM_L1CrossDomainMessenger: OVM_L1CrossDomainMessenger:
- 0x16393737D09d2722AD13DcA3cA8C3DB957699F1D - 0xbfba066b5cA610Fe70AdCE45FcB622F945891bb0
- https://etherscan.io/address/0x16393737D09d2722AD13DcA3cA8C3DB957699F1D - https://etherscan.io/address/0xbfba066b5cA610Fe70AdCE45FcB622F945891bb0)
OVM_L1ETHGateway: OVM_L1ETHGateway:
- 0x40c9067ec8087EcF101FC10d2673636955b81A32 - 0x40c9067ec8087EcF101FC10d2673636955b81A32
...@@ -100,8 +100,8 @@ Implementation addresses. DO NOT use these addresses directly. ...@@ -100,8 +100,8 @@ Implementation addresses. DO NOT use these addresses directly.
Use their proxied counterparts seen above. Use their proxied counterparts seen above.
OVM_L1CrossDomainMessenger: OVM_L1CrossDomainMessenger:
- 0xa172330C2E6Ec2bF04662Bb9b67ae857910b7f7f - 0x333d2674E2D7e1e7327dc076030ce9615183709C
- https://kovan.etherscan.io/address/0xa172330C2E6Ec2bF04662Bb9b67ae857910b7f7f) - https://kovan.etherscan.io/address/0x333d2674E2D7e1e7327dc076030ce9615183709C)
OVM_L1StandardBridge: OVM_L1StandardBridge:
- 0x8293ab0dc701a1387031a13786276f1baa3fcd4e - 0x8293ab0dc701a1387031a13786276f1baa3fcd4e
- https://kovan.etherscan.io/address/0x8293ab0dc701a1387031a13786276f1baa3fcd4e) - https://kovan.etherscan.io/address/0x8293ab0dc701a1387031a13786276f1baa3fcd4e)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -257,10 +257,71 @@ describe('OVM_L1CrossDomainMessenger', () => { ...@@ -257,10 +257,71 @@ describe('OVM_L1CrossDomainMessenger', () => {
}) })
}) })
const generateMockRelayMessageProof = async (
target: string,
sender: string,
message: string,
messageNonce: number = 0
): Promise<{
calldata: string
proof: any
}> => {
const calldata = encodeXDomainCalldata(
target,
sender,
message,
messageNonce
)
const storageKey = keccak256(
keccak256(calldata + remove0x(Mock__OVM_L2CrossDomainMessenger.address)) +
'00'.repeat(32)
)
const storageGenerator = await TrieTestGenerator.fromNodes({
nodes: [
{
key: storageKey,
val: '0x' + '01'.padStart(2, '0'),
},
],
secure: true,
})
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
address: predeploys.OVM_L2ToL1MessagePasser,
nonce: 0,
balance: 0,
codeHash: keccak256('0x1234'),
storageRoot: toHexString(storageGenerator._trie.root),
},
],
secure: true,
})
const proof = {
stateRoot: toHexString(generator._trie.root),
stateRootBatchHeader: DUMMY_BATCH_HEADERS[0],
stateRootProof: DUMMY_BATCH_PROOFS[0],
stateTrieWitness: (
await generator.makeAccountProofTest(predeploys.OVM_L2ToL1MessagePasser)
).accountTrieWitness,
storageTrieWitness: (
await storageGenerator.makeInclusionProofTest(storageKey)
).proof,
}
return {
calldata,
proof,
}
}
describe('relayMessage', () => { describe('relayMessage', () => {
let target: string let target: string
let message: string
let sender: string let sender: string
let message: string
let proof: any let proof: any
let calldata: string let calldata: string
before(async () => { before(async () => {
...@@ -270,49 +331,13 @@ describe('OVM_L1CrossDomainMessenger', () => { ...@@ -270,49 +331,13 @@ describe('OVM_L1CrossDomainMessenger', () => {
]) ])
sender = await signer.getAddress() sender = await signer.getAddress()
calldata = encodeXDomainCalldata(target, sender, message, 0) const mockProof = await generateMockRelayMessageProof(
target,
const storageKey = keccak256( sender,
keccak256( message
calldata + remove0x(Mock__OVM_L2CrossDomainMessenger.address)
) + '00'.repeat(32)
) )
const storageGenerator = await TrieTestGenerator.fromNodes({ proof = mockProof.proof
nodes: [ calldata = mockProof.calldata
{
key: storageKey,
val: '0x' + '01'.padStart(2, '0'),
},
],
secure: true,
})
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
address: predeploys.OVM_L2ToL1MessagePasser,
nonce: 0,
balance: 0,
codeHash: keccak256('0x1234'),
storageRoot: toHexString(storageGenerator._trie.root),
},
],
secure: true,
})
proof = {
stateRoot: toHexString(generator._trie.root),
stateRootBatchHeader: DUMMY_BATCH_HEADERS[0],
stateRootProof: DUMMY_BATCH_PROOFS[0],
stateTrieWitness: (
await generator.makeAccountProofTest(
predeploys.OVM_L2ToL1MessagePasser
)
).accountTrieWitness,
storageTrieWitness: (
await storageGenerator.makeInclusionProofTest(storageKey)
).proof,
}
}) })
beforeEach(async () => { beforeEach(async () => {
...@@ -348,6 +373,26 @@ describe('OVM_L1CrossDomainMessenger', () => { ...@@ -348,6 +373,26 @@ describe('OVM_L1CrossDomainMessenger', () => {
).to.be.revertedWith('Provided message could not be verified.') ).to.be.revertedWith('Provided message could not be verified.')
}) })
it('should revert if attempting to relay a message sent to an L1 system contract', async () => {
const maliciousProof = await generateMockRelayMessageProof(
OVM_CanonicalTransactionChain.address,
sender,
message
)
await expect(
OVM_L1CrossDomainMessenger.relayMessage(
OVM_CanonicalTransactionChain.address,
sender,
message,
0,
maliciousProof.proof
)
).to.be.revertedWith(
'Cannot send L2->L1 messages to L1 system contracts.'
)
})
it('should revert if provided an invalid state root proof', async () => { it('should revert if provided an invalid state root proof', async () => {
Mock__OVM_StateCommitmentChain.smocked.verifyStateCommitment.will.return.with( Mock__OVM_StateCommitmentChain.smocked.verifyStateCommitment.will.return.with(
false false
......
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