Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
9ddbe51a
Unverified
Commit
9ddbe51a
authored
Sep 28, 2021
by
Kelvin Fichter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: rework msg sender for l1 to l2 messages
parent
973589da
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
404 additions
and
321 deletions
+404
-321
SimpleStorage.sol
integration-tests/contracts/SimpleStorage.sol
+3
-0
basic-l1-l2-communication.spec.ts
integration-tests/test/basic-l1-l2-communication.spec.ts
+28
-1
queue-ingestion.spec.ts
integration-tests/test/queue-ingestion.spec.ts
+2
-2
simulated.go
l2geth/accounts/abi/bind/backends/simulated.go
+3
-4
evm.go
l2geth/core/evm.go
+13
-25
state_processor.go
l2geth/core/state_processor.go
+2
-14
state_transition.go
l2geth/core/state_transition.go
+0
-1
transaction.go
l2geth/core/types/transaction.go
+21
-23
evm.go
l2geth/core/vm/evm.go
+1
-2
instructions.go
l2geth/core/vm/instructions.go
+0
-5
jump_table.go
l2geth/core/vm/jump_table.go
+0
-7
opcodes.go
l2geth/core/vm/opcodes.go
+4
-7
interfaces.go
l2geth/interfaces.go
+3
-4
api.go
l2geth/internal/ethapi/api.go
+1
-1
L1CrossDomainMessenger.sol
...ntracts/contracts/L1/messaging/L1CrossDomainMessenger.sol
+4
-1
CanonicalTransactionChain.sol
...ntracts/contracts/L1/rollup/CanonicalTransactionChain.sol
+15
-2
L2CrossDomainMessenger.sol
...ntracts/contracts/L2/messaging/L2CrossDomainMessenger.sol
+12
-52
iOVM_L1MessageSender.sol
...ontracts/contracts/L2/predeploys/iOVM_L1MessageSender.sol
+0
-14
AddressAliasHelper.sol
...ages/contracts/contracts/standards/AddressAliasHelper.sol
+44
-0
TestLib_AddressAliasHelper.sol
...s/test-libraries/standards/TestLib_AddressAliasHelper.sol
+34
-0
connect-contracts.ts
packages/contracts/src/connect-contracts.ts
+0
-5
contract-data.ts
packages/contracts/src/contract-data.ts
+0
-5
make-genesis.ts
packages/contracts/src/make-genesis.ts
+4
-8
predeploys.ts
packages/contracts/src/predeploys.ts
+0
-1
L1CrossDomainMessenger.spec.ts
...est/contracts/L1/messaging/L1CrossDomainMessenger.spec.ts
+35
-39
L2CrossDomainMessenger.spec.ts
...est/contracts/L2/messaging/L2CrossDomainMessenger.spec.ts
+46
-98
AddressAliasHelper.spec.ts
.../contracts/libraries/standards/AddressAliasHelper.spec.ts
+51
-0
alias.ts
packages/core-utils/src/alias.ts
+33
-0
index.ts
packages/core-utils/src/index.ts
+1
-0
alias.spec.ts
packages/core-utils/test/alias.spec.ts
+44
-0
No files found.
integration-tests/contracts/SimpleStorage.sol
View file @
9ddbe51a
...
...
@@ -6,12 +6,14 @@ contract ICrossDomainMessenger {
contract SimpleStorage {
address public msgSender;
address public txOrigin;
address public xDomainSender;
bytes32 public value;
uint256 public totalCount;
function setValue(bytes32 newValue) public {
msgSender = msg.sender;
txOrigin = tx.origin;
xDomainSender = ICrossDomainMessenger(msg.sender)
.xDomainMessageSender();
value = newValue;
...
...
@@ -20,6 +22,7 @@ contract SimpleStorage {
function setValueNotXDomain(bytes32 newValue) public {
msgSender = msg.sender;
txOrigin = tx.origin;
value = newValue;
totalCount++;
}
...
...
integration-tests/test/basic-l1-l2-communication.spec.ts
View file @
9ddbe51a
...
...
@@ -2,7 +2,7 @@ import { expect } from 'chai'
/* Imports: External */
import
{
Contract
,
ContractFactory
}
from
'
ethers
'
import
{
predeploys
,
getContractInterface
}
from
'
@eth-optimism/contract
s
'
import
{
applyL1ToL2Alias
,
sleep
}
from
'
@eth-optimism/core-util
s
'
/* Imports: Internal */
import
simpleStorageJson
from
'
../artifacts/contracts/SimpleStorage.sol/SimpleStorage.json
'
...
...
@@ -90,6 +90,9 @@ describe('Basic L1<>L2 Communication', async () => {
expect
(
await
L2SimpleStorage
.
msgSender
()).
to
.
equal
(
env
.
l2Messenger
.
address
)
expect
(
await
L2SimpleStorage
.
txOrigin
()).
to
.
equal
(
applyL1ToL2Alias
(
env
.
l1Messenger
.
address
)
)
expect
(
await
L2SimpleStorage
.
xDomainSender
()).
to
.
equal
(
env
.
l1Wallet
.
address
)
...
...
@@ -97,6 +100,30 @@ describe('Basic L1<>L2 Communication', async () => {
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
1
)
})
it
(
'
should deposit from L1 -> L2 directly via enqueue
'
,
async
()
=>
{
const
value
=
`0x
${
'
42
'
.
repeat
(
32
)}
`
// Send L1 -> L2 message.
await
env
.
ctc
.
connect
(
env
.
l1Wallet
)
.
enqueue
(
L2SimpleStorage
.
address
,
5000000
,
L2SimpleStorage
.
interface
.
encodeFunctionData
(
'
setValueNotXDomain
'
,
[
value
,
])
)
// TODO: We need to have a function that can wait for enqueued txs.
await
sleep
(
10000
)
// No aliasing when an EOA goes directly to L2.
expect
(
await
L2SimpleStorage
.
msgSender
()).
to
.
equal
(
env
.
l1Wallet
.
address
)
expect
(
await
L2SimpleStorage
.
txOrigin
()).
to
.
equal
(
env
.
l1Wallet
.
address
)
expect
(
await
L2SimpleStorage
.
value
()).
to
.
equal
(
value
)
expect
((
await
L2SimpleStorage
.
totalCount
()).
toNumber
()).
to
.
equal
(
1
)
})
it
(
'
should have a receipt with a status of 1 for a successful message
'
,
async
()
=>
{
const
value
=
`0x
${
'
42
'
.
repeat
(
32
)}
`
...
...
integration-tests/test/queue-ingestion.spec.ts
View file @
9ddbe51a
...
...
@@ -2,7 +2,7 @@ import { expect } from 'chai'
/* Imports: Internal */
import
{
providers
}
from
'
ethers
'
import
{
injectL2Context
}
from
'
@eth-optimism/core-utils
'
import
{
injectL2Context
,
applyL1ToL2Alias
}
from
'
@eth-optimism/core-utils
'
/* Imports: External */
import
{
OptimismEnv
}
from
'
./shared/env
'
...
...
@@ -57,7 +57,7 @@ describe('Queue Ingestion', () => {
expect
(
params
.
_target
).
to
.
equal
(
'
0x
'
+
`
${
i
}
`
.
repeat
(
40
))
expect
(
l2Tx
.
queueOrigin
).
to
.
equal
(
'
l1
'
)
expect
(
l2Tx
.
l1TxOrigin
.
toLowerCase
()).
to
.
equal
(
env
.
l1Messenger
.
address
.
toLowerCase
()
applyL1ToL2Alias
(
env
.
l1Messenger
.
address
)
.
toLowerCase
()
)
expect
(
l2Tx
.
l1BlockNumber
).
to
.
equal
(
l1TxReceipt
.
blockNumber
)
}
...
...
l2geth/accounts/abi/bind/backends/simulated.go
View file @
9ddbe51a
...
...
@@ -603,10 +603,9 @@ func (m callmsg) Data() []byte { return m.CallMsg.Data }
// UsingOVM
// These getters return OVM specific fields
func
(
m
callmsg
)
L1Timestamp
()
uint64
{
return
m
.
CallMsg
.
L1Timestamp
}
func
(
m
callmsg
)
L1BlockNumber
()
*
big
.
Int
{
return
m
.
CallMsg
.
L1BlockNumber
}
func
(
m
callmsg
)
L1MessageSender
()
*
common
.
Address
{
return
m
.
CallMsg
.
L1MessageSender
}
func
(
m
callmsg
)
QueueOrigin
()
types
.
QueueOrigin
{
return
m
.
CallMsg
.
QueueOrigin
}
func
(
m
callmsg
)
L1Timestamp
()
uint64
{
return
m
.
CallMsg
.
L1Timestamp
}
func
(
m
callmsg
)
L1BlockNumber
()
*
big
.
Int
{
return
m
.
CallMsg
.
L1BlockNumber
}
func
(
m
callmsg
)
QueueOrigin
()
types
.
QueueOrigin
{
return
m
.
CallMsg
.
QueueOrigin
}
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
...
...
l2geth/core/evm.go
View file @
9ddbe51a
...
...
@@ -27,10 +27,6 @@ import (
"github.com/ethereum/go-ethereum/rollup/rcfg"
)
// DefaultL1MessageSender is the default L1MessageSender value attached to a transaction that is
// not an L1 to L2 message.
var
DefaultL1MessageSender
=
common
.
HexToAddress
(
"0x00000000000000000000000000000000000beef"
)
// ChainContext supports retrieving headers and consensus parameters from the
// current blockchain to be used during transaction processing.
type
ChainContext
interface
{
...
...
@@ -52,28 +48,20 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
}
if
rcfg
.
UsingOVM
{
// When using the OVM, we must:
// (1) Attach the L1MessageSender context value and
// (2) Set the BlockNumber to be the msg.L1BlockNumber
// (3) Set the Time to be the msg.L1Timestamp
var
l1MessageSender
common
.
Address
if
msg
.
L1MessageSender
()
==
nil
{
l1MessageSender
=
DefaultL1MessageSender
}
else
{
l1MessageSender
=
*
msg
.
L1MessageSender
()
}
// - Set the BlockNumber to be the msg.L1BlockNumber
// - Set the Time to be the msg.L1Timestamp
return
vm
.
Context
{
CanTransfer
:
CanTransfer
,
Transfer
:
Transfer
,
GetHash
:
GetHashFn
(
header
,
chain
),
Origin
:
msg
.
From
(),
Coinbase
:
dump
.
OvmFeeWallet
,
// Coinbase is the fee vault.
BlockNumber
:
new
(
big
.
Int
)
.
Set
(
header
.
Number
),
Time
:
new
(
big
.
Int
)
.
SetUint64
(
msg
.
L1Timestamp
()),
Difficulty
:
new
(
big
.
Int
),
// Difficulty always returns zero.
GasLimit
:
header
.
GasLimit
,
GasPrice
:
new
(
big
.
Int
)
.
Set
(
msg
.
GasPrice
()),
L1MessageSender
:
l1MessageSender
,
L1BlockNumber
:
msg
.
L1BlockNumber
(),
CanTransfer
:
CanTransfer
,
Transfer
:
Transfer
,
GetHash
:
GetHashFn
(
header
,
chain
),
Origin
:
msg
.
From
(),
Coinbase
:
dump
.
OvmFeeWallet
,
// Coinbase is the fee vault.
BlockNumber
:
new
(
big
.
Int
)
.
Set
(
header
.
Number
),
Time
:
new
(
big
.
Int
)
.
SetUint64
(
msg
.
L1Timestamp
()),
Difficulty
:
new
(
big
.
Int
),
// Difficulty always returns zero.
GasLimit
:
header
.
GasLimit
,
GasPrice
:
new
(
big
.
Int
)
.
Set
(
msg
.
GasPrice
()),
L1BlockNumber
:
msg
.
L1BlockNumber
(),
}
}
else
{
return
vm
.
Context
{
...
...
l2geth/core/state_processor.go
View file @
9ddbe51a
...
...
@@ -26,7 +26,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/fees"
"github.com/ethereum/go-ethereum/rollup/rcfg"
)
// StateProcessor is a basic Processor, which takes care of transitioning
...
...
@@ -89,19 +88,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// indicating the block was invalid.
func
ApplyTransaction
(
config
*
params
.
ChainConfig
,
bc
ChainContext
,
author
*
common
.
Address
,
gp
*
GasPool
,
statedb
*
state
.
StateDB
,
header
*
types
.
Header
,
tx
*
types
.
Transaction
,
usedGas
*
uint64
,
cfg
vm
.
Config
)
(
*
types
.
Receipt
,
error
)
{
msg
,
err
:=
tx
.
AsMessage
(
types
.
MakeSigner
(
config
,
header
.
Number
))
if
rcfg
.
UsingOVM
{
if
err
!=
nil
{
// This should only be allowed to pass if the transaction is in the ctc
// already. The presence of `Index` should specify this.
index
:=
tx
.
GetMeta
()
.
Index
if
index
==
nil
&&
msg
.
QueueOrigin
()
!=
types
.
QueueOriginL1ToL2
{
return
nil
,
err
}
}
}
else
{
if
err
!=
nil
{
return
nil
,
err
}
if
err
!=
nil
{
return
nil
,
err
}
// Create a new context to be used in the EVM environment
context
:=
NewEVMContext
(
msg
,
header
,
bc
,
author
)
...
...
l2geth/core/state_transition.go
View file @
9ddbe51a
...
...
@@ -82,7 +82,6 @@ type Message interface {
L1Timestamp
()
uint64
L1BlockNumber
()
*
big
.
Int
L1MessageSender
()
*
common
.
Address
QueueOrigin
()
types
.
QueueOrigin
}
...
...
l2geth/core/types/transaction.go
View file @
9ddbe51a
...
...
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rollup/rcfg"
)
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
...
...
@@ -295,20 +296,20 @@ func (tx *Transaction) AsMessage(s Signer) (Message, error) {
data
:
tx
.
data
.
Payload
,
checkNonce
:
true
,
l1Timestamp
:
tx
.
meta
.
L1Timestamp
,
l1BlockNumber
:
tx
.
meta
.
L1BlockNumber
,
l1MessageSender
:
tx
.
meta
.
L1MessageSender
,
queueOrigin
:
tx
.
meta
.
QueueOrigin
,
l1Timestamp
:
tx
.
meta
.
L1Timestamp
,
l1BlockNumber
:
tx
.
meta
.
L1BlockNumber
,
queueOrigin
:
tx
.
meta
.
QueueOrigin
,
}
var
err
error
msg
.
from
,
err
=
Sender
(
s
,
tx
)
if
tx
.
meta
.
L1MessageSender
!=
nil
{
msg
.
l1MessageSender
=
tx
.
meta
.
L1MessageSender
if
rcfg
.
UsingOVM
{
if
tx
.
meta
.
QueueOrigin
==
QueueOriginL1ToL2
&&
tx
.
meta
.
L1MessageSender
!=
nil
{
msg
.
from
=
*
tx
.
meta
.
L1MessageSender
}
else
{
msg
.
from
,
err
=
Sender
(
s
,
tx
)
}
}
else
{
addr
:=
common
.
Address
{}
msg
.
l1MessageSender
=
&
addr
msg
.
from
,
err
=
Sender
(
s
,
tx
)
}
return
msg
,
err
...
...
@@ -479,13 +480,12 @@ type Message struct {
data
[]
byte
checkNonce
bool
l1Timestamp
uint64
l1BlockNumber
*
big
.
Int
l1MessageSender
*
common
.
Address
queueOrigin
QueueOrigin
l1Timestamp
uint64
l1BlockNumber
*
big
.
Int
queueOrigin
QueueOrigin
}
func
NewMessage
(
from
common
.
Address
,
to
*
common
.
Address
,
nonce
uint64
,
amount
*
big
.
Int
,
gasLimit
uint64
,
gasPrice
*
big
.
Int
,
data
[]
byte
,
checkNonce
bool
,
l1
MessageSender
*
common
.
Address
,
l1
BlockNumber
*
big
.
Int
,
l1Timestamp
uint64
,
queueOrigin
QueueOrigin
)
Message
{
func
NewMessage
(
from
common
.
Address
,
to
*
common
.
Address
,
nonce
uint64
,
amount
*
big
.
Int
,
gasLimit
uint64
,
gasPrice
*
big
.
Int
,
data
[]
byte
,
checkNonce
bool
,
l1BlockNumber
*
big
.
Int
,
l1Timestamp
uint64
,
queueOrigin
QueueOrigin
)
Message
{
return
Message
{
from
:
from
,
to
:
to
,
...
...
@@ -496,10 +496,9 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *b
data
:
data
,
checkNonce
:
checkNonce
,
l1Timestamp
:
l1Timestamp
,
l1BlockNumber
:
l1BlockNumber
,
l1MessageSender
:
l1MessageSender
,
queueOrigin
:
queueOrigin
,
l1Timestamp
:
l1Timestamp
,
l1BlockNumber
:
l1BlockNumber
,
queueOrigin
:
queueOrigin
,
}
}
...
...
@@ -512,7 +511,6 @@ func (m Message) Nonce() uint64 { return m.nonce }
func
(
m
Message
)
Data
()
[]
byte
{
return
m
.
data
}
func
(
m
Message
)
CheckNonce
()
bool
{
return
m
.
checkNonce
}
func
(
m
Message
)
L1Timestamp
()
uint64
{
return
m
.
l1Timestamp
}
func
(
m
Message
)
L1BlockNumber
()
*
big
.
Int
{
return
m
.
l1BlockNumber
}
func
(
m
Message
)
L1MessageSender
()
*
common
.
Address
{
return
m
.
l1MessageSender
}
func
(
m
Message
)
QueueOrigin
()
QueueOrigin
{
return
m
.
queueOrigin
}
func
(
m
Message
)
L1Timestamp
()
uint64
{
return
m
.
l1Timestamp
}
func
(
m
Message
)
L1BlockNumber
()
*
big
.
Int
{
return
m
.
l1BlockNumber
}
func
(
m
Message
)
QueueOrigin
()
QueueOrigin
{
return
m
.
queueOrigin
}
l2geth/core/vm/evm.go
View file @
9ddbe51a
...
...
@@ -98,8 +98,7 @@ type Context struct {
Difficulty
*
big
.
Int
// Provides information for DIFFICULTY
// OVM information
L1MessageSender
common
.
Address
// Provides information for L1MESSAGESENDER
L1BlockNumber
*
big
.
Int
// Provides information for L1BLOCKNUMBER
L1BlockNumber
*
big
.
Int
// Provides information for L1BLOCKNUMBER
}
// EVM is the Ethereum Virtual Machine base object and provides
...
...
l2geth/core/vm/instructions.go
View file @
9ddbe51a
...
...
@@ -969,11 +969,6 @@ func makeSwap(size int64) executionFunc {
}
// OVM opcodes
func
opL1MessageSender
(
pc
*
uint64
,
interpreter
*
EVMInterpreter
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
stack
.
push
(
interpreter
.
intPool
.
get
()
.
SetBytes
(
interpreter
.
evm
.
L1MessageSender
.
Bytes
()))
return
nil
,
nil
}
func
opL1BlockNumber
(
pc
*
uint64
,
interpreter
*
EVMInterpreter
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
stack
.
push
(
math
.
U256
(
interpreter
.
intPool
.
get
()
.
Set
(
interpreter
.
evm
.
L1BlockNumber
)))
return
nil
,
nil
...
...
l2geth/core/vm/jump_table.go
View file @
9ddbe51a
...
...
@@ -1155,13 +1155,6 @@ func newFrontierInstructionSet() JumpTable {
valid
:
true
,
writes
:
true
,
},
L1MESSAGESENDER
:
{
execute
:
opL1MessageSender
,
constantGas
:
GasQuickStep
,
minStack
:
minStack
(
0
,
1
),
maxStack
:
maxStack
(
0
,
1
),
valid
:
true
,
},
L1BLOCKNUMBER
:
{
execute
:
opL1BlockNumber
,
constantGas
:
GasQuickStep
,
...
...
l2geth/core/vm/opcodes.go
View file @
9ddbe51a
...
...
@@ -104,8 +104,7 @@ const (
CHAINID
=
0x46
SELFBALANCE
=
0x47
L1MESSAGESENDER
=
0x4A
L1BLOCKNUMBER
=
0x4B
L1BLOCKNUMBER
=
0x4B
)
// 0x50 range - 'storage' and execution.
...
...
@@ -286,9 +285,8 @@ var opCodeToString = map[OpCode]string{
SELFBALANCE
:
"SELFBALANCE"
,
// OVM opcodes
// 0x4A
L1MESSAGESENDER
:
"L1MESSAGESENDER"
,
L1BLOCKNUMBER
:
"L1BLOCKNUMBER"
,
// 0x4B
L1BLOCKNUMBER
:
"L1BLOCKNUMBER"
,
// 0x50 range - 'storage' and execution.
POP
:
"POP"
,
...
...
@@ -548,8 +546,7 @@ var stringToOp = map[string]OpCode{
"SELFDESTRUCT"
:
SELFDESTRUCT
,
// OVM opcodes
"L1MESSAGESENDER"
:
L1MESSAGESENDER
,
"L1BLOCKNUMBER"
:
L1BLOCKNUMBER
,
"L1BLOCKNUMBER"
:
L1BLOCKNUMBER
,
}
// StringToOp finds the opcode whose name is stored in `str`.
...
...
l2geth/interfaces.go
View file @
9ddbe51a
...
...
@@ -120,10 +120,9 @@ type CallMsg struct {
Value
*
big
.
Int
// amount of wei sent along with the call
Data
[]
byte
// input data, usually an ABI-encoded contract method invocation
L1Timestamp
uint64
L1BlockNumber
*
big
.
Int
L1MessageSender
*
common
.
Address
QueueOrigin
types
.
QueueOrigin
L1Timestamp
uint64
L1BlockNumber
*
big
.
Int
QueueOrigin
types
.
QueueOrigin
}
// A ContractCaller provides contract calls, essentially transactions that are executed by
...
...
l2geth/internal/ethapi/api.go
View file @
9ddbe51a
...
...
@@ -883,7 +883,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
}
// Create new call message
msg
:=
types
.
NewMessage
(
addr
,
args
.
To
,
0
,
value
,
gas
,
gasPrice
,
data
,
false
,
&
addr
,
blockNumber
,
timestamp
,
types
.
QueueOriginSequencer
)
msg
:=
types
.
NewMessage
(
addr
,
args
.
To
,
0
,
value
,
gas
,
gasPrice
,
data
,
false
,
blockNumber
,
timestamp
,
types
.
QueueOriginSequencer
)
// Setup context so it may be cancelled the call has completed
// or, in case of unmetered gas, setup a context with a timeout.
...
...
packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol
View file @
9ddbe51a
...
...
@@ -2,6 +2,7 @@
pragma solidity ^0.8.8;
/* Library Imports */
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressManager } from "../../libraries/resolver/Lib_AddressManager.sol";
...
...
@@ -62,6 +63,7 @@ contract L1CrossDomainMessenger is
address internal xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
/***************
* Constructor *
***************/
...
...
@@ -75,6 +77,7 @@ contract L1CrossDomainMessenger is
Lib_AddressResolver(address(0))
{}
/**********************
* Function Modifiers *
**********************/
...
...
@@ -299,7 +302,7 @@ contract L1CrossDomainMessenger is
// Compute the transactionHash
bytes32 transactionHash = keccak256(
abi.encode(
address(this
),
AddressAliasHelper.applyL1ToL2Alias(address(this)
),
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
_gasLimit,
_message
...
...
packages/contracts/contracts/L1/rollup/CanonicalTransactionChain.sol
View file @
9ddbe51a
...
...
@@ -2,6 +2,7 @@
pragma solidity ^0.8.8;
/* Library Imports */
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
...
...
@@ -279,9 +280,21 @@ contract CanonicalTransactionChain is ICanonicalTransactionChain, Lib_AddressRes
}
}
// Apply an aliasing unless msg.sender == tx.origin. This prevents an attack in which a
// contract on L1 has the same address as a contract on L2 but doesn't have the same code.
// We can safely ignore this for EOAs because they're guaranteed to have the same "code"
// (i.e. no code at all). This also makes it possible for users to interact with contracts
// on L2 even when the Sequencer is down.
address sender;
if (msg.sender == tx.origin) {
sender = msg.sender;
} else {
sender = AddressAliasHelper.applyL1ToL2Alias(msg.sender);
}
bytes32 transactionHash = keccak256(
abi.encode(
msg.
sender,
sender,
_target,
_gasLimit,
_data
...
...
@@ -304,7 +317,7 @@ contract CanonicalTransactionChain is ICanonicalTransactionChain, Lib_AddressRes
// to divide by 2 and subtract 1.
uint256 queueIndex = queueRef.length() / 2 - 1;
emit TransactionEnqueued(
msg.
sender,
sender,
_target,
_gasLimit,
_data,
...
...
packages/contracts/contracts/L2/messaging/L2CrossDomainMessenger.sol
View file @
9ddbe51a
...
...
@@ -2,18 +2,15 @@
pragma solidity ^0.8.8;
/* Library Imports */
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
import { Lib_CrossDomainUtils } from "../../libraries/bridge/Lib_CrossDomainUtils.sol";
import { Lib_DefaultValues } from "../../libraries/constants/Lib_DefaultValues.sol";
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
/* Interface Imports */
import { IL2CrossDomainMessenger } from "./IL2CrossDomainMessenger.sol";
import { iOVM_L1MessageSender } from "../predeploys/iOVM_L1MessageSender.sol";
import { iOVM_L2ToL1MessagePasser } from "../predeploys/iOVM_L2ToL1MessagePasser.sol";
/* External Imports */
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/**
* @title L2CrossDomainMessenger
* @dev The L2 Cross Domain Messenger contract sends messages from L2 to L1, and is the entry point
...
...
@@ -21,8 +18,7 @@ import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuar
*
*/
contract L2CrossDomainMessenger is
IL2CrossDomainMessenger,
ReentrancyGuard
IL2CrossDomainMessenger
{
/*************
...
...
@@ -36,18 +32,18 @@ contract L2CrossDomainMessenger is
address internal xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
address public l1CrossDomainMessenger;
/***************
* Constructor *
***************/
constructor(
address _l1CrossDomainMessenger
)
ReentrancyGuard()
{
) {
l1CrossDomainMessenger = _l1CrossDomainMessenger;
}
/********************
* Public Functions *
********************/
...
...
@@ -85,9 +81,13 @@ contract L2CrossDomainMessenger is
sentMessages[keccak256(xDomainCalldata)] = true;
_sendXDomainMessage(xDomainCalldata, _gasLimit);
emit SentMessage(_target, msg.sender, _message, messageNonce, _gasLimit);
// Actually send the message.
iOVM_L2ToL1MessagePasser(
Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER
).passMessageToL1(xDomainCalldata);
// Emit an event before we bump the nonce or the nonce will be off by one.
emit SentMessage(_target, msg.sender, _message, messageNonce, _gasLimit);
messageNonce += 1;
}
...
...
@@ -101,11 +101,10 @@ contract L2CrossDomainMessenger is
bytes memory _message,
uint256 _messageNonce
)
nonReentrant
public
{
require(
_verifyXDomainMessage() == true
,
AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1CrossDomainMessenger
,
"Provided message could not be verified."
);
...
...
@@ -157,43 +156,4 @@ contract L2CrossDomainMessenger is
relayedMessages[relayId] = true;
}
/**********************
* Internal Functions *
**********************/
/**
* Verifies that a received cross domain message is valid.
* @return _valid Whether or not the message is valid.
*/
function _verifyXDomainMessage()
internal
view
returns (
bool _valid
)
{
return (
iOVM_L1MessageSender(
Lib_PredeployAddresses.L1_MESSAGE_SENDER
).getL1MessageSender() == l1CrossDomainMessenger
);
}
/**
* 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
)
internal
{
iOVM_L2ToL1MessagePasser(
Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER
).passMessageToL1(_message);
}
}
packages/contracts/contracts/L2/predeploys/iOVM_L1MessageSender.sol
deleted
100644 → 0
View file @
973589da
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
/**
* @title iOVM_L1MessageSender
*/
interface iOVM_L1MessageSender {
/********************
* Public Functions *
********************/
function getL1MessageSender() external view returns (address);
}
packages/contracts/contracts/standards/AddressAliasHelper.sol
0 → 100644
View file @
9ddbe51a
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.7;
library AddressAliasHelper {
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
/// @notice Utility function that converts the address in the L1 that submitted a tx to
/// the inbox to the msg.sender viewed in the L2
/// @param l1Address the address in the L1 that triggered the tx to L2
/// @return l2Address L2 address as viewed in msg.sender
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + offset);
}
}
/// @notice Utility function that converts the msg.sender viewed in the L2 to the
/// address in the L1 that submitted a tx to the inbox
/// @param l2Address L2 address as viewed in msg.sender
/// @return l1Address the address in the L1 that triggered the tx to L2
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
unchecked {
l1Address = address(uint160(l2Address) - offset);
}
}
}
packages/contracts/contracts/test-libraries/standards/TestLib_AddressAliasHelper.sol
0 → 100644
View file @
9ddbe51a
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
/* Library Imports */
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
/**
* @title TestLib_AddressAliasHelper
*/
contract TestLib_AddressAliasHelper {
function applyL1ToL2Alias(
address _address
)
public
pure
returns (
address
)
{
return AddressAliasHelper.applyL1ToL2Alias(_address);
}
function undoL1ToL2Alias(
address _address
)
public
pure
returns (
address
)
{
return AddressAliasHelper.undoL1ToL2Alias(_address);
}
}
packages/contracts/src/connect-contracts.ts
View file @
9ddbe51a
...
...
@@ -17,7 +17,6 @@ interface L2Contracts {
eth
:
Contract
xDomainMessenger
:
Contract
messagePasser
:
Contract
messageSender
:
Contract
deployerWhiteList
:
Contract
}
...
...
@@ -90,10 +89,6 @@ export const connectL2Contracts = async (
eth
:
getEthersContract
(
'
OVM_ETH
'
),
xDomainMessenger
:
getEthersContract
(
'
L2CrossDomainMessenger
'
),
messagePasser
:
getEthersContract
(
'
OVM_L2ToL1MessagePasser
'
),
messageSender
:
getEthersContract
(
'
OVM_L1MessageSender
'
,
'
iOVM_L1MessageSender
'
),
deployerWhiteList
:
getEthersContract
(
'
OVM_DeployerWhitelist
'
),
}
}
packages/contracts/src/contract-data.ts
View file @
9ddbe51a
...
...
@@ -67,7 +67,6 @@ export const getL1ContractData = (network: Network) => {
const
OVM_ETH
=
require
(
'
../artifacts/contracts/L2/predeploys/OVM_ETH.sol/OVM_ETH.json
'
)
const
L2CrossDomainMessenger
=
require
(
'
../artifacts/contracts/L2/messaging/L2CrossDomainMessenger.sol/L2CrossDomainMessenger.json
'
)
const
OVM_L2ToL1MessagePasser
=
require
(
'
../artifacts/contracts/L2/predeploys/OVM_L2ToL1MessagePasser.sol/OVM_L2ToL1MessagePasser.json
'
)
const
OVM_L1MessageSender
=
require
(
'
../artifacts/contracts/L2/predeploys/iOVM_L1MessageSender.sol/iOVM_L1MessageSender.json
'
)
const
OVM_DeployerWhitelist
=
require
(
'
../artifacts/contracts/L2/predeploys/OVM_DeployerWhitelist.sol/OVM_DeployerWhitelist.json
'
)
export
const
getL2ContractData
=
()
=>
{
...
...
@@ -84,10 +83,6 @@ export const getL2ContractData = () => {
abi
:
OVM_L2ToL1MessagePasser
.
abi
,
address
:
l2Addresses
.
OVM_L2ToL1MessagePasser
,
},
OVM_L1MessageSender
:
{
abi
:
OVM_L1MessageSender
.
abi
,
address
:
l2Addresses
.
OVM_L1MessageSender
,
},
OVM_DeployerWhitelist
:
{
abi
:
OVM_DeployerWhitelist
.
abi
,
address
:
l2Addresses
.
OVM_DeployerWhitelist
,
...
...
packages/contracts/src/make-genesis.ts
View file @
9ddbe51a
...
...
@@ -79,7 +79,6 @@ export const makeL2GenesisFile = async (
_symbol
:
'
ETH
'
,
},
L2CrossDomainMessenger
:
{
_status
:
1
,
l1CrossDomainMessenger
:
cfg
.
l1CrossDomainMessengerAddress
,
},
}
...
...
@@ -92,14 +91,11 @@ export const makeL2GenesisFile = async (
storage
:
{},
}
if
(
predeployName
===
'
OVM_L1
MessageSend
er
'
)
{
// OVM_L1
MessageSend
er is a special case where we just inject a specific bytecode string.
// We do this because it uses the custom L1
MESSAGESENDER opcode (0x4A
) which cannot be
// directly used in Solidity (yet). This bytecode string simply executes the 0x4
A
opcode
if
(
predeployName
===
'
OVM_L1
BlockNumb
er
'
)
{
// OVM_L1
BlockNumb
er is a special case where we just inject a specific bytecode string.
// We do this because it uses the custom L1
BLOCKNUMBER opcode (0x4B
) which cannot be
// directly used in Solidity (yet). This bytecode string simply executes the 0x4
B
opcode
// and returns the address given by that opcode.
dump
[
predeployAddress
].
code
=
'
0x4A60005260206000F3
'
}
else
if
(
predeployName
===
'
OVM_L1BlockNumber
'
)
{
// Same as above but for OVM_L1BlockNumber (0x4B).
dump
[
predeployAddress
].
code
=
'
0x4B60005260206000F3
'
}
else
{
const
artifact
=
getContractArtifact
(
predeployName
)
...
...
packages/contracts/src/predeploys.ts
View file @
9ddbe51a
...
...
@@ -9,7 +9,6 @@
*/
export
const
predeploys
=
{
OVM_L2ToL1MessagePasser
:
'
0x4200000000000000000000000000000000000000
'
,
OVM_L1MessageSender
:
'
0x4200000000000000000000000000000000000001
'
,
OVM_DeployerWhitelist
:
'
0x4200000000000000000000000000000000000002
'
,
L2CrossDomainMessenger
:
'
0x4200000000000000000000000000000000000007
'
,
OVM_GasPriceOracle
:
'
0x420000000000000000000000000000000000000F
'
,
...
...
packages/contracts/test/contracts/L1/messaging/L1CrossDomainMessenger.spec.ts
View file @
9ddbe51a
...
...
@@ -4,7 +4,11 @@ import { expect } from '../../../setup'
import
{
ethers
}
from
'
hardhat
'
import
{
Signer
,
ContractFactory
,
Contract
,
BigNumber
}
from
'
ethers
'
import
{
smockit
,
MockContract
}
from
'
@eth-optimism/smock
'
import
{
remove0x
,
toHexString
}
from
'
@eth-optimism/core-utils
'
import
{
remove0x
,
toHexString
,
applyL1ToL2Alias
,
}
from
'
@eth-optimism/core-utils
'
/* Internal Imports */
import
{
...
...
@@ -20,7 +24,6 @@ import {
getNextBlockNumber
,
encodeXDomainCalldata
,
}
from
'
../../../helpers
'
import
{
keccak256
}
from
'
ethers/lib/utils
'
import
{
predeploys
}
from
'
../../../../src
'
const
MAX_GAS_LIMIT
=
8
_000_000
...
...
@@ -157,26 +160,6 @@ describe('L1CrossDomainMessenger', () => {
})
})
const
getTransactionHash
=
(
sender
:
string
,
target
:
string
,
gasLimit
:
number
,
data
:
string
):
string
=>
{
return
keccak256
(
encodeQueueTransaction
(
sender
,
target
,
gasLimit
,
data
))
}
const
encodeQueueTransaction
=
(
sender
:
string
,
target
:
string
,
gasLimit
:
number
,
data
:
string
):
string
=>
{
return
ethers
.
utils
.
defaultAbiCoder
.
encode
(
[
'
address
'
,
'
address
'
,
'
uint256
'
,
'
bytes
'
],
[
sender
,
target
,
gasLimit
,
data
]
)
}
describe
(
'
sendMessage
'
,
()
=>
{
const
target
=
NON_ZERO_ADDRESS
const
message
=
NON_NULL_BYTES32
...
...
@@ -193,13 +176,17 @@ describe('L1CrossDomainMessenger', () => {
message
,
0
)
const
transactionHash
=
getTransactionHash
(
L1CrossDomainMessenger
.
address
,
Mock__L2CrossDomainMessenger
.
address
,
gasLimit
,
calldata
const
transactionHash
=
ethers
.
utils
.
keccak256
(
ethers
.
utils
.
defaultAbiCoder
.
encode
(
[
'
address
'
,
'
address
'
,
'
uint256
'
,
'
bytes
'
],
[
applyL1ToL2Alias
(
L1CrossDomainMessenger
.
address
),
Mock__L2CrossDomainMessenger
.
address
,
gasLimit
,
calldata
,
]
)
)
const
queueLength
=
await
CanonicalTransactionChain
.
getQueueLength
()
const
queueElement
=
await
CanonicalTransactionChain
.
getQueueElement
(
queueLength
-
1
...
...
@@ -274,9 +261,10 @@ describe('L1CrossDomainMessenger', () => {
messageNonce
)
const
storageKey
=
keccak256
(
keccak256
(
calldata
+
remove0x
(
Mock__L2CrossDomainMessenger
.
address
))
+
'
00
'
.
repeat
(
32
)
const
storageKey
=
ethers
.
utils
.
keccak256
(
ethers
.
utils
.
keccak256
(
calldata
+
remove0x
(
Mock__L2CrossDomainMessenger
.
address
)
)
+
'
00
'
.
repeat
(
32
)
)
const
storageGenerator
=
await
TrieTestGenerator
.
fromNodes
({
nodes
:
[
...
...
@@ -294,7 +282,7 @@ describe('L1CrossDomainMessenger', () => {
address
:
predeploys
.
OVM_L2ToL1MessagePasser
,
nonce
:
0
,
balance
:
0
,
codeHash
:
keccak256
(
'
0x1234
'
),
codeHash
:
ethers
.
utils
.
keccak256
(
'
0x1234
'
),
storageRoot
:
toHexString
(
storageGenerator
.
_trie
.
root
),
},
],
...
...
@@ -436,12 +424,14 @@ describe('L1CrossDomainMessenger', () => {
)
expect
(
await
L1CrossDomainMessenger
.
successfulMessages
(
keccak256
(
calldata
))
await
L1CrossDomainMessenger
.
successfulMessages
(
ethers
.
utils
.
keccak256
(
calldata
)
)
).
to
.
equal
(
true
)
expect
(
await
L1CrossDomainMessenger
.
relayedMessages
(
keccak256
(
ethers
.
utils
.
keccak256
(
calldata
+
remove0x
(
await
signer
.
getAddress
())
+
remove0x
(
BigNumber
.
from
(
blockNumber
).
toHexString
()).
padStart
(
...
...
@@ -495,16 +485,18 @@ describe('L1CrossDomainMessenger', () => {
it
(
'
should revert if called by an account other than the owner
'
,
async
()
=>
{
const
L1CrossDomainMessenger2
=
L1CrossDomainMessenger
.
connect
(
signer2
)
await
expect
(
L1CrossDomainMessenger2
.
blockMessage
(
keccak256
(
calldata
))
L1CrossDomainMessenger2
.
blockMessage
(
ethers
.
utils
.
keccak256
(
calldata
))
).
to
.
be
.
revertedWith
(
'
Ownable: caller is not the owner
'
)
await
expect
(
L1CrossDomainMessenger2
.
allowMessage
(
keccak256
(
calldata
))
L1CrossDomainMessenger2
.
allowMessage
(
ethers
.
utils
.
keccak256
(
calldata
))
).
to
.
be
.
revertedWith
(
'
Ownable: caller is not the owner
'
)
})
it
(
'
should revert if the message is blocked
'
,
async
()
=>
{
await
L1CrossDomainMessenger
.
blockMessage
(
keccak256
(
calldata
))
await
L1CrossDomainMessenger
.
blockMessage
(
ethers
.
utils
.
keccak256
(
calldata
)
)
await
expect
(
L1CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
,
proof
)
...
...
@@ -512,13 +504,17 @@ describe('L1CrossDomainMessenger', () => {
})
it
(
'
should succeed if the message is blocked, then unblocked
'
,
async
()
=>
{
await
L1CrossDomainMessenger
.
blockMessage
(
keccak256
(
calldata
))
await
L1CrossDomainMessenger
.
blockMessage
(
ethers
.
utils
.
keccak256
(
calldata
)
)
await
expect
(
L1CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
,
proof
)
).
to
.
be
.
revertedWith
(
'
Provided message has been blocked.
'
)
await
L1CrossDomainMessenger
.
allowMessage
(
keccak256
(
calldata
))
await
L1CrossDomainMessenger
.
allowMessage
(
ethers
.
utils
.
keccak256
(
calldata
)
)
await
expect
(
L1CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
,
proof
)
...
...
packages/contracts/test/contracts/L2/messaging/L2CrossDomainMessenger.spec.ts
View file @
9ddbe51a
import
{
expect
}
from
'
../../../setup
'
/* External Imports */
import
{
ethers
}
from
'
hardhat
'
import
{
Signer
,
ContractFactory
,
Contract
,
constants
}
from
'
ethers
'
import
hre
,
{
ethers
}
from
'
hardhat
'
import
{
Signer
,
ContractFactory
,
Contract
}
from
'
ethers
'
import
{
smockit
,
MockContract
}
from
'
@eth-optimism/smock
'
import
{
solidityKeccak256
}
from
'
ethers/lib/
utils
'
import
{
applyL1ToL2Alias
}
from
'
@eth-optimism/core-
utils
'
/* Internal Imports */
import
{
NON_NULL_BYTES32
,
NON_ZERO_ADDRESS
,
encodeXDomainCalldata
,
getNextBlockNumber
,
}
from
'
../../../helpers
'
import
{
getContractInterface
,
predeploys
}
from
'
../../../../src
'
import
{
predeploys
}
from
'
../../../../src
'
describe
(
'
L2CrossDomainMessenger
'
,
()
=>
{
let
signer
:
Signer
...
...
@@ -23,7 +22,6 @@ describe('L2CrossDomainMessenger', () => {
let
Mock__TargetContract
:
MockContract
let
Mock__L1CrossDomainMessenger
:
MockContract
let
Mock__OVM_L1MessageSender
:
MockContract
let
Mock__OVM_L2ToL1MessagePasser
:
MockContract
before
(
async
()
=>
{
Mock__TargetContract
=
await
smockit
(
...
...
@@ -32,16 +30,30 @@ describe('L2CrossDomainMessenger', () => {
Mock__L1CrossDomainMessenger
=
await
smockit
(
await
ethers
.
getContractFactory
(
'
L1CrossDomainMessenger
'
)
)
Mock__OVM_L1MessageSender
=
await
smockit
(
getContractInterface
(
'
iOVM_L1MessageSender
'
),
{
address
:
predeploys
.
OVM_L1MessageSender
}
)
Mock__OVM_L2ToL1MessagePasser
=
await
smockit
(
await
ethers
.
getContractFactory
(
'
OVM_L2ToL1MessagePasser
'
),
{
address
:
predeploys
.
OVM_L2ToL1MessagePasser
}
)
})
let
impersonatedL1CrossDomainMessengerSender
:
Signer
before
(
async
()
=>
{
const
impersonatedAddress
=
applyL1ToL2Alias
(
Mock__L1CrossDomainMessenger
.
address
)
await
hre
.
network
.
provider
.
request
({
method
:
'
hardhat_impersonateAccount
'
,
params
:
[
impersonatedAddress
],
})
await
hre
.
network
.
provider
.
request
({
method
:
'
hardhat_setBalance
'
,
params
:
[
impersonatedAddress
,
'
0xFFFFFFFFFFFFFFFFF
'
],
})
impersonatedL1CrossDomainMessengerSender
=
await
ethers
.
getSigner
(
impersonatedAddress
)
})
let
Factory__L2CrossDomainMessenger
:
ContractFactory
before
(
async
()
=>
{
Factory__L2CrossDomainMessenger
=
await
ethers
.
getContractFactory
(
...
...
@@ -94,24 +106,21 @@ describe('L2CrossDomainMessenger', () => {
sender
=
await
signer
.
getAddress
()
})
beforeEach
(
async
()
=>
{
Mock__OVM_L1MessageSender
.
smocked
.
getL1MessageSender
.
will
.
return
.
with
(
Mock__L1CrossDomainMessenger
.
address
)
})
it
(
'
should revert if the L1 message sender is not the L1CrossDomainMessenger
'
,
async
()
=>
{
Mock__OVM_L1MessageSender
.
smocked
.
getL1MessageSender
.
will
.
return
.
with
(
constants
.
AddressZero
)
await
expect
(
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
L2CrossDomainMessenger
.
connect
(
signer
).
relayMessage
(
target
,
sender
,
message
,
0
)
).
to
.
be
.
revertedWith
(
'
Provided message could not be verified.
'
)
})
it
(
'
should send a call to the target contract
'
,
async
()
=>
{
await
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
await
L2CrossDomainMessenger
.
connect
(
impersonatedL1CrossDomainMessengerSender
).
relayMessage
(
target
,
sender
,
message
,
0
)
expect
(
Mock__TargetContract
.
smocked
.
setTarget
.
calls
[
0
]).
to
.
deep
.
equal
([
NON_ZERO_ADDRESS
,
...
...
@@ -122,40 +131,38 @@ describe('L2CrossDomainMessenger', () => {
await
expect
(
L2CrossDomainMessenger
.
xDomainMessageSender
()
).
to
.
be
.
revertedWith
(
'
xDomainMessageSender is not set
'
)
await
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
await
L2CrossDomainMessenger
.
connect
(
impersonatedL1CrossDomainMessengerSender
).
relayMessage
(
target
,
sender
,
message
,
0
)
await
expect
(
L2CrossDomainMessenger
.
xDomainMessageSender
()
).
to
.
be
.
revertedWith
(
'
xDomainMessageSender is not set
'
)
})
it
(
'
should revert if trying to send the same message twice
'
,
async
()
=>
{
Mock__OVM_L1MessageSender
.
smocked
.
getL1MessageSender
.
will
.
return
.
with
(
Mock__L1CrossDomainMessenger
.
address
)
await
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
await
L2CrossDomainMessenger
.
connect
(
impersonatedL1CrossDomainMessengerSender
).
relayMessage
(
target
,
sender
,
message
,
0
)
await
expect
(
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
L2CrossDomainMessenger
.
connect
(
impersonatedL1CrossDomainMessengerSender
).
relayMessage
(
target
,
sender
,
message
,
0
)
).
to
.
be
.
revertedWith
(
'
Provided message has already been received.
'
)
})
it
(
'
should not make a call if the target is the L2 MessagePasser
'
,
async
()
=>
{
Mock__OVM_L1MessageSender
.
smocked
.
getL1MessageSender
.
will
.
return
.
with
(
Mock__L1CrossDomainMessenger
.
address
)
target
=
predeploys
.
OVM_L2ToL1MessagePasser
message
=
Mock__OVM_L2ToL1MessagePasser
.
interface
.
encodeFunctionData
(
'
passMessageToL1(bytes)
'
,
[
NON_NULL_BYTES32
]
)
const
resProm
=
L2CrossDomainMessenger
.
relayMessage
(
target
,
sender
,
message
,
0
)
const
resProm
=
L2CrossDomainMessenger
.
connect
(
impersonatedL1CrossDomainMessengerSender
).
relayMessage
(
target
,
sender
,
message
,
0
)
// The call to relayMessage() should succeed.
await
expect
(
resProm
).
to
.
not
.
be
.
reverted
...
...
@@ -173,71 +180,12 @@ describe('L2CrossDomainMessenger', () => {
// The message should be registered as successful.
expect
(
await
L2CrossDomainMessenger
.
successfulMessages
(
solidityKeccak256
(
ethers
.
utils
.
solidityKeccak256
(
[
'
bytes
'
],
[
encodeXDomainCalldata
(
target
,
sender
,
message
,
0
)]
)
)
).
to
.
be
.
true
})
it
(
'
should revert if trying to reenter `relayMessage`
'
,
async
()
=>
{
Mock__OVM_L1MessageSender
.
smocked
.
getL1MessageSender
.
will
.
return
.
with
(
Mock__L1CrossDomainMessenger
.
address
)
const
reentrantMessage
=
L2CrossDomainMessenger
.
interface
.
encodeFunctionData
(
'
relayMessage
'
,
[
target
,
sender
,
message
,
1
,
])
// Calculate xDomainCallData used for indexing
// (within the first call to the L2 Messenger).
const
xDomainCallData
=
encodeXDomainCalldata
(
L2CrossDomainMessenger
.
address
,
sender
,
reentrantMessage
,
0
)
// Make the call.
await
L2CrossDomainMessenger
.
relayMessage
(
L2CrossDomainMessenger
.
address
,
sender
,
reentrantMessage
,
0
)
// We can't test for the nonReentrant revert string because it occurs in the second call frame,
// and target.call() won't "bubble up" the revert. So we need to use other criteria to ensure the
// right things are happening.
// Criteria 1: the reentrant message is NOT listed in successful messages.
expect
(
await
L2CrossDomainMessenger
.
successfulMessages
(
solidityKeccak256
([
'
bytes
'
],
[
xDomainCallData
])
)
).
to
.
be
.
false
// Criteria 2: the relayID of the reentrant message is recorded.
// Get blockNumber at time of the call.
const
blockNumber
=
(
await
getNextBlockNumber
(
ethers
.
provider
))
-
1
const
relayId
=
solidityKeccak256
(
[
'
bytes
'
],
[
ethers
.
utils
.
solidityPack
(
[
'
bytes
'
,
'
address
'
,
'
uint256
'
],
[
xDomainCallData
,
sender
,
blockNumber
]
),
]
)
expect
(
await
L2CrossDomainMessenger
.
relayedMessages
(
relayId
)).
to
.
be
.
true
// Criteria 3: the target contract did not receive a call.
expect
(
Mock__TargetContract
.
smocked
.
setTarget
.
calls
[
0
]).
to
.
be
.
undefined
})
})
})
packages/contracts/test/contracts/libraries/standards/AddressAliasHelper.spec.ts
0 → 100644
View file @
9ddbe51a
import
{
expect
}
from
'
../../../setup
'
/* External Imports */
import
{
ethers
}
from
'
hardhat
'
import
{
Contract
}
from
'
ethers
'
import
{
applyL1ToL2Alias
,
undoL1ToL2Alias
}
from
'
@eth-optimism/core-utils
'
describe
(
'
AddressAliasHelper
'
,
()
=>
{
let
AddressAliasHelper
:
Contract
before
(
async
()
=>
{
AddressAliasHelper
=
await
(
await
ethers
.
getContractFactory
(
'
TestLib_AddressAliasHelper
'
)
).
deploy
()
})
describe
(
'
applyL1ToL2Alias
'
,
()
=>
{
it
(
'
should be able to apply the alias to a valid address
'
,
async
()
=>
{
expect
(
await
AddressAliasHelper
.
applyL1ToL2Alias
(
'
0x0000000000000000000000000000000000000000
'
)
).
to
.
equal
(
applyL1ToL2Alias
(
'
0x0000000000000000000000000000000000000000
'
))
})
it
(
'
should be able to apply the alias even if the operation overflows
'
,
async
()
=>
{
expect
(
await
AddressAliasHelper
.
applyL1ToL2Alias
(
'
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
'
)
).
to
.
equal
(
applyL1ToL2Alias
(
'
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
'
))
})
})
describe
(
'
undoL1ToL2Alias
'
,
()
=>
{
it
(
'
should be able to undo the alias from a valid address
'
,
async
()
=>
{
expect
(
await
AddressAliasHelper
.
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001111
'
)
).
to
.
equal
(
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001111
'
))
})
it
(
'
should be able to undo the alias even if the operation underflows
'
,
async
()
=>
{
expect
(
await
AddressAliasHelper
.
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001110
'
)
).
to
.
equal
(
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001110
'
))
})
})
})
packages/core-utils/src/alias.ts
0 → 100644
View file @
9ddbe51a
import
{
ethers
}
from
'
ethers
'
export
const
L1_TO_L2_ALIAS_OFFSET
=
'
0x1111000000000000000000000000000000001111
'
const
bnToAddress
=
(
bn
:
ethers
.
BigNumber
):
string
=>
{
if
(
bn
.
isNegative
())
{
bn
=
ethers
.
BigNumber
.
from
(
'
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
'
)
.
add
(
bn
)
.
add
(
1
)
}
const
addr
=
bn
.
toHexString
().
slice
(
2
).
padStart
(
40
,
'
0
'
)
return
ethers
.
utils
.
getAddress
(
'
0x
'
+
addr
.
slice
(
addr
.
length
-
40
,
addr
.
length
)
)
}
export
const
applyL1ToL2Alias
=
(
address
:
string
):
string
=>
{
if
(
!
ethers
.
utils
.
isAddress
(
address
))
{
throw
new
Error
(
`not a valid address:
${
address
}
`
)
}
return
bnToAddress
(
ethers
.
BigNumber
.
from
(
address
).
add
(
L1_TO_L2_ALIAS_OFFSET
))
}
export
const
undoL1ToL2Alias
=
(
address
:
string
):
string
=>
{
if
(
!
ethers
.
utils
.
isAddress
(
address
))
{
throw
new
Error
(
`not a valid address:
${
address
}
`
)
}
return
bnToAddress
(
ethers
.
BigNumber
.
from
(
address
).
sub
(
L1_TO_L2_ALIAS_OFFSET
))
}
packages/core-utils/src/index.ts
View file @
9ddbe51a
...
...
@@ -7,3 +7,4 @@ export * from './batches'
export
*
from
'
./bcfg
'
export
*
from
'
./fees
'
export
*
from
'
./provider
'
export
*
from
'
./alias
'
packages/core-utils/test/alias.spec.ts
0 → 100644
View file @
9ddbe51a
import
{
expect
}
from
'
./setup
'
import
{
applyL1ToL2Alias
,
undoL1ToL2Alias
}
from
'
../src/alias
'
describe
(
'
address aliasing utils
'
,
()
=>
{
describe
(
'
applyL1ToL2Alias
'
,
()
=>
{
it
(
'
should be able to apply the alias to a valid address
'
,
()
=>
{
expect
(
applyL1ToL2Alias
(
'
0x0000000000000000000000000000000000000000
'
)
).
to
.
equal
(
'
0x1111000000000000000000000000000000001111
'
)
})
it
(
'
should be able to apply the alias even if the operation overflows
'
,
()
=>
{
expect
(
applyL1ToL2Alias
(
'
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
'
)
).
to
.
equal
(
'
0x1111000000000000000000000000000000001110
'
)
})
it
(
'
should throw if the input is not a valid address
'
,
()
=>
{
expect
(()
=>
{
applyL1ToL2Alias
(
'
0x1234
'
)
}).
to
.
throw
})
})
describe
(
'
undoL1ToL2Alias
'
,
()
=>
{
it
(
'
should be able to undo the alias from a valid address
'
,
()
=>
{
expect
(
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001111
'
)
).
to
.
equal
(
'
0x0000000000000000000000000000000000000000
'
)
})
it
(
'
should be able to undo the alias even if the operation underflows
'
,
()
=>
{
expect
(
undoL1ToL2Alias
(
'
0x1111000000000000000000000000000000001110
'
)
).
to
.
equal
(
'
0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
'
)
})
it
(
'
should throw if the input is not a valid address
'
,
()
=>
{
expect
(()
=>
{
undoL1ToL2Alias
(
'
0x1234
'
)
}).
to
.
throw
})
})
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment