Skip to content

Commit f0847db

Browse files
committed
WIP
1 parent 92c7446 commit f0847db

File tree

1 file changed

+110
-102
lines changed

1 file changed

+110
-102
lines changed

pages/interop/tutorials/message-passing/manual-relay.mdx

Lines changed: 110 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Learn to relay transactions directly by sending the correct transaction.
5959

6060
### What you'll build
6161

62-
* A program to relay messages without using [the JavaScript library](https://www.npmjs.com/package/@eth-optimism/viem)
62+
* A program to relay messages using [the JavaScript library](https://www.npmjs.com/package/@eth-optimism/viem)
6363
* A shell script to relay messages using [`cast`](https://book.getfoundry.sh/cast/)
6464

6565
## Setup
@@ -103,7 +103,7 @@ These steps are necessary to run the tutorial, regardless of whether you are usi
103103
mkdir -p manual-relay/offchain
104104
cd manual-relay/offchain
105105
npm init -y
106-
npm install --save-dev -y viem @eth-optimism/viem
106+
npm install --save-dev viem @eth-optimism/viem
107107
mkdir src
108108
```
109109

@@ -183,132 +183,140 @@ These steps are necessary to run the tutorial, regardless of whether you are usi
183183

184184
## Manual relay using `cast`
185185

186-
Run this script:
187-
188-
```sh
189-
./manual-relay/sendAndRelay.sh
190-
```
186+
You can see an example of how to manually relay using `cast` in `manual-relay/sendAndRelay.sh`.
187+
It is somewhat complicated, so the setup creates one that is tailored to your environment.
191188

192-
### What does the script do?
189+
<details>
190+
<summary>Explanation</summary>
191+
192+
```sh
193+
#! /bin/sh
194+
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
195+
USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
196+
URL_CHAIN_A=http://localhost:9545
197+
URL_CHAIN_B=http://localhost:9546
198+
GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
199+
GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
200+
CHAIN_ID_B=902
201+
```
193202

194-
```sh
195-
#! /bin/sh
196-
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
197-
USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
198-
URL_CHAIN_A=http://localhost:9545
199-
URL_CHAIN_B=http://localhost:9546
200-
GREETER_A_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
201-
GREETER_B_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
202-
CHAIN_ID_B=902
203-
```
203+
This is the configuration.
204+
The greeter addresses are identical because the nonce for the user address has an identical nonce on both chains.
204205

205-
This is the configuration.
206-
The greeter addresses are identical because the nonce for the user address has an identical nonce on both chains.
206+
```sh
207+
cast send -q --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A $$"
208+
```
207209

208-
```sh
209-
cast send -q --private-key $PRIVATE_KEY --rpc-url $URL_CHAIN_A $GREETER_A_ADDRESS "setGreeting(string)" "Hello from chain A $$"
210-
```
210+
Send a message from chain A to chain B. The `$$` is the process ID, so if you rerun the script you'll see that the information changes.
211211

212-
Send a message from chain A to chain B. The `$$` is the process ID, so if you rerun the script you'll see that the information changes.
212+
```sh
213+
cast logs "SentMessage(uint256,address,uint256,address,bytes)" --rpc-url $URL_CHAIN_A | tail -14 > log-entry
214+
```
213215

214-
```sh
215-
cast logs "SentMessage(uint256,address,uint256,address,bytes)" --rpc-url $URL_CHAIN_A | tail -14 > log-entry
216-
```
216+
Whenever `L2ToL2CrossDomainMessenger` sends a message to a different blockchain, it emits a [`SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L83-L91) event.
217+
Extract only the latest `SendMessage` event from the logs.
218+
219+
<details>
220+
<summary>Example `log-entry`</summary>
221+
222+
```yaml
223+
- address: 0x4200000000000000000000000000000000000023
224+
blockHash: 0xcd0be97ffb41694faf3a172ac612a23f224afc1bfecd7cb737a7a464cf5d133e
225+
blockNumber: 426
226+
data: 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064a41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001948656c6c6f2066726f6d20636861696e2041203131333030370000000000000000000000000000000000000000000000000000000000000000000000
227+
logIndex: 0
228+
removed: false
229+
topics: [
230+
0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320
231+
0x0000000000000000000000000000000000000000000000000000000000000386
232+
0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3
233+
0x0000000000000000000000000000000000000000000000000000000000000000
234+
]
235+
transactionHash: 0x1d6f2e5e2c8f3eb055e95741380ca36492f784b9782848b66b66c65c5937ff3a
236+
transactionIndex: 0
237+
```
238+
</details>
239+
240+
```sh
241+
TOPICS=`cat log-entry | grep -A4 topics | awk '{print $1}' | tail -4 | sed 's/0x//'`
242+
TOPICS=`echo $TOPICS | sed 's/ //g'`
243+
```
217244

218-
Whenever `L2ToL2CrossDomainMessenger` sends a message to a different blockchain, it emits a [`SendMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L83-L91) event.
219-
Extract only the latest `SendMessage` event from the logs.
245+
Consolidate the log topics into a single hex string.
220246

221-
<details>
222-
<summary>Example `log-entry`</summary>
223-
224-
```yaml
225-
- address: 0x4200000000000000000000000000000000000023
226-
blockHash: 0xcd0be97ffb41694faf3a172ac612a23f224afc1bfecd7cb737a7a464cf5d133e
227-
blockNumber: 426
228-
data: 0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064a41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001948656c6c6f2066726f6d20636861696e2041203131333030370000000000000000000000000000000000000000000000000000000000000000000000
229-
logIndex: 0
230-
removed: false
231-
topics: [
232-
0x382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f320
233-
0x0000000000000000000000000000000000000000000000000000000000000386
234-
0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3
235-
0x0000000000000000000000000000000000000000000000000000000000000000
236-
]
237-
transactionHash: 0x1d6f2e5e2c8f3eb055e95741380ca36492f784b9782848b66b66c65c5937ff3a
238-
transactionIndex: 0
247+
```sh
248+
ORIGIN=0x4200000000000000000000000000000000000023
249+
BLOCK_NUMBER=`cat log-entry | awk '/blockNumber/ {print $2}'`
250+
LOG_INDEX=`cat log-entry | awk '/logIndex/ {print $2}'`
251+
TIMESTAMP=`cast block $BLOCK_NUMBER --rpc-url $URL_CHAIN_A | awk '/timestamp/ {print $2}'`
252+
CHAIN_ID_A=`cast chain-id --rpc-url $URL_CHAIN_A`
253+
SENT_MESSAGE=`cat log-entry | awk '/data/ {print $2}'`
239254
```
240-
</details>
241255

242-
```sh
243-
TOPICS=`cat log-entry | grep -A4 topics | awk '{print $1}' | tail -4 | sed 's/0x//'`
244-
TOPICS=`echo $TOPICS | sed 's/ //g'`
245-
```
256+
Read additional fields from the log entry.
246257

247-
Consolidate the log topics into a single hex string.
258+
```sh
259+
LOG_ENTRY=0x`echo $TOPICS$SENT_MESSAGE | sed 's/0x//'`
260+
```
248261

249-
```sh
250-
ORIGIN=0x4200000000000000000000000000000000000023
251-
BLOCK_NUMBER=`cat log-entry | awk '/blockNumber/ {print $2}'`
252-
LOG_INDEX=`cat log-entry | awk '/logIndex/ {print $2}'`
253-
TIMESTAMP=`cast block $BLOCK_NUMBER --rpc-url $URL_CHAIN_A | awk '/timestamp/ {print $2}'`
254-
CHAIN_ID_A=`cast chain-id --rpc-url $URL_CHAIN_A`
255-
SENT_MESSAGE=`cat log-entry | awk '/data/ {print $2}'`
256-
```
262+
Consolidate the entire log entry.
263+
264+
```sh
265+
RPC_PARAMS=$(cat <<INNER_END_OF_FILE
266+
{
267+
"origin": "$ORIGIN",
268+
"blockNumber": "$BLOCK_NUMBER",
269+
"logIndex": "$LOG_INDEX",
270+
"timestamp": "$TIMESTAMP",
271+
"chainId": "$CHAIN_ID_A",
272+
"payload": "$LOG_ENTRY"
273+
}
274+
INNER_END_OF_FILE
275+
)
276+
277+
ACCESS_LIST=`cast rpc admin_getAccessListForIdentifier --rpc-url http://localhost:8420 "$RPC_PARAMS" | jq .accessList`
278+
```
257279
258-
Read additional fields from the log entry.
280+
To secure cross-chain messaging and prevent potential [denial-of-service attacks](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/interop-access-list.md), relay transactions require properly formatted access lists that include a checksum derived from the message data.
281+
This lets sequencers know what executing messages to expect in a transaction, which makes it easy not to include transactions that are invalid because they rely on messages that were never sent.
259282
260-
```sh
261-
LOG_ENTRY=0x`echo $TOPICS$SENT_MESSAGE | sed 's/0x//'`
262-
```
283+
The [algorithm to calculate the access list](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L87-L115) is a bit complicated, but you don't need to worry about it.
284+
Supersim exposes [RPC calls](https://supersim.pages.dev/guides/interop/cast?highlight=manuall#7-construct-the-access-list-for-the-message) that calculates it for you on port 8420.
285+
The code above will calculate the correct access list even if you're using a different interop cluster where autorelay is not functioning.
286+
This is because the code implements a [pure function](https://en.wikipedia.org/wiki/Pure_function), which produces consistent results regardless of external state.
287+
In contrast, the `admin_getAccessListByMsgHash` RPC call is not a pure function, it is dependent on system state and therefore less flexible in these situations.
263288
264-
Consolidate the entire log entry.
289+
```sh
290+
echo Old greeting
291+
cast call $GREETER_B_ADDRESS "greet()(string)" --rpc-url $URL_CHAIN_B
292+
```
265293
266-
```sh
267-
RPC_PARAMS=$(cat <<INNER_END_OF_FILE
268-
{
269-
"origin": "$ORIGIN",
270-
"blockNumber": "$BLOCK_NUMBER",
271-
"logIndex": "$LOG_INDEX",
272-
"timestamp": "$TIMESTAMP",
273-
"chainId": "$CHAIN_ID_A",
274-
"payload": "$LOG_ENTRY"
275-
}
276-
INNER_END_OF_FILE
277-
)
278-
279-
ACCESS_LIST=`cast rpc admin_getAccessListForIdentifier --rpc-url http://localhost:8420 "$RPC_PARAMS" | jq .accessList`
280-
```
294+
Show the current greeting.
295+
The message has not been relayed yet, so it's still the old greeting.
281296
282-
To secure cross-chain messaging and prevent potential [denial-of-service attacks](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/interop-access-list.md), relay transactions require properly formatted access lists that include a checksum derived from the message data.
283-
This lets sequencers know what executing messages to expect in a transaction, which makes it easy not to include transactions that are invalid because they rely on messages that were never sent.
297+
```sh
298+
cast send -q $ORIGIN "relayMessage((address,uint256,uint256,uint256,uint256),bytes)" "($ORIGIN,$BLOCK_NUMBER,$LOG_INDEX,$TIMESTAMP,$CHAIN_ID_A)" $LOG_ENTRY --access-list "$ACCESS_LIST" --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY
299+
```
284300
285-
The [algorithm to calculate the access list](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol#L87-L115) is a bit complicated, but you don't need to worry about it.
286-
Supersim exposes [RPC calls](https://supersim.pages.dev/guides/interop/cast?highlight=manuall#7-construct-the-access-list-for-the-message) that calculates it for you on port 8420.
287-
The code above will calculate the correct access list even if you're using a different interop cluster where autorelay is not functioning.
288-
This is because the code implements a [pure function](https://en.wikipedia.org/wiki/Pure_function), which produces consistent results regardless of external state.
289-
In contrast, the `admin_getAccessListByMsgHash` RPC call is not a pure function, it is dependent on system state and therefore less flexible in these situations.
301+
Call [`relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L197-L256) to relay the message.
290302
291-
```sh
292-
echo Old greeting
293-
cast call $GREETER_B_ADDRESS "greet()(string)" --rpc-url $URL_CHAIN_B
294-
```
303+
```sh
304+
echo New greeting
305+
cast call $GREETER_B_ADDRESS "greet()(string)" --rpc-url $URL_CHAIN_B
306+
```
295307
296-
Show the current greeting.
297-
The message has not been relayed yet, so it's still the old greeting.
308+
Again, show the current greeting.
309+
Now it's the new one.
310+
311+
</details>
298312
299-
```sh
300-
cast send -q $ORIGIN "relayMessage((address,uint256,uint256,uint256,uint256),bytes)" "($ORIGIN,$BLOCK_NUMBER,$LOG_INDEX,$TIMESTAMP,$CHAIN_ID_A)" $LOG_ENTRY --access-list "$ACCESS_LIST" --rpc-url $URL_CHAIN_B --private-key $PRIVATE_KEY
301-
```
302313
303-
Call [`relayMessage`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol#L197-L256) to relay the message.
314+
Run this script:
304315
305316
```sh
306-
echo New greeting
307-
cast call $GREETER_B_ADDRESS "greet()(string)" --rpc-url $URL_CHAIN_B
317+
./manual-relay/sendAndRelay.sh
308318
```
309319
310-
Again, show the current greeting.
311-
Now it's the new one.
312320
313321
## Next steps
314322

0 commit comments

Comments
 (0)