Skip to content

Commit

Permalink
deposits: docs & fail externally sent deposits in opsimulator (#285)
Browse files Browse the repository at this point in the history
* deposit.docs

* fail deposit txs send externally
  • Loading branch information
hamdiallam authored Dec 2, 2024
1 parent 3bf3be4 commit ac5f803
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 16 deletions.
8 changes: 7 additions & 1 deletion anvil/anvil.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ func (a *Anvil) Start(ctx context.Context) error {
if a.cmd != nil {
return errors.New("anvil already started")
}
if a.cfg.Host == "" {
a.cfg.Host = "127.0.0.1"
}

args := []string{
"--host", a.cfg.Host,
Expand Down Expand Up @@ -233,7 +236,10 @@ func (a *Anvil) Stop(_ context.Context) error {
return nil // someone else stopped
}

a.rpcClient.Close()
if a.rpcClient != nil {
a.rpcClient.Close()
}

a.resourceCancel()
<-a.stoppedCh
return nil
Expand Down
2 changes: 1 addition & 1 deletion docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

# Guides

- [Sending deposit transactions](./guides/deposit-transactions.md)
- [Deposit Transactions](./guides/deposit-transactions.md)
- [Interoperability](./guides/interop/README.md)
- [Cross Chain Contract Calls (PingPong)](./guides/interop/cross-chain-contract-calls-pingpong.md)
- [Cross Chain Event Reading (TicTacToe)](./guides/interop/cross-chain-event-reads-tictactoe.md)
Expand Down
82 changes: 82 additions & 0 deletions docs/src/guides/deposit-transactions.md
Original file line number Diff line number Diff line change
@@ -1 +1,83 @@
# Deposit transactions

Supersim supports deposits transactions as described in the [explainer](https://docs.optimism.io/stack/transactions/deposit-flow). However in a very lightweight manner without the op-node derivation pipeline by listening directly to the `TransactionDeposited` events on the OptimsimPortal contract and simply forwarding the transaction to the applicable L2.

This implies the the exeuction engine used with Supersim must support the optimism [Deposit Transaction Type](https://specs.optimism.io/protocol/deposits.html#the-deposited-transaction-type).

## OptimismPortal

When starting Supersim, the L1 contracts for each L2 chain are emitted as output to the console. The `L1CrossDomainMessenger`, `L1StandardBridge`, and `OptimismPortal` can be used to initiate deposits in the same manner as one would on a production network like OP Mainnet or Base.

```bash
Chain Configuration
-----------------------
L1: Name: Local ChainID: 900 RPC: http://127.0.0.1:8545 LogPath: ...

L2: Predeploy Contracts Spec ( https://specs.optimism.io/protocol/predeploys.html )

* Name: OPChainA ChainID: 901 RPC: http://127.0.0.1:9545 LogPath: ...
L1 Contracts:
- OptimismPortal: 0x37a418800d0c812A9dE83Bc80e993A6b76511B57
- L1CrossDomainMessenger: 0xcd712b03bc6424BF45cE6C29Fc90FFDece228F6E
- L1StandardBridge: 0x8d515eb0e5F293B16B6bBCA8275c060bAe0056B0

...
```

If running Supersim in fork mode, the production contracts will be used for each of the forked networks.

```bash
Chain Configuration
-----------------------
L1: Name: mainnet ChainID: 1 RPC: http://127.0.0.1:8545 LogPath: ...

L2: Predeploy Contracts Spec ( https://specs.optimism.io/protocol/predeploys.html )

* Name: op ChainID: 10 RPC: http://127.0.0.1:9545 LogPath: ...
L1 Contracts:
- OptimismPortal: 0xbEb5Fc579115071764c7423A4f12eDde41f106Ed
- L1CrossDomainMessenger: 0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1
- L1StandardBridge: 0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1

* Name: mode ChainID: 34443 RPC: http://127.0.0.1:9546 LogPath: ...
L1 Contracts:
- OptimismPortal: 0x8B34b14c7c7123459Cf3076b8Cb929BE097d0C07
- L1CrossDomainMessenger: 0x95bDCA6c8EdEB69C98Bd5bd17660BaCef1298A6f
- L1StandardBridge: 0x735aDBbE72226BD52e818E7181953f42E3b0FF21

...
```

## Sample Deposit Flow

We'll run through a sample deposit directly with the optimism portal using cast

1. **Run Supersim**

```bash
supersim
```

2. **Observe OptimismPortal Contract Address**

```bash
...
* Name: OPChainA ChainID: 901 ...
L1 Contracts:
- OptimismPortal: 0x37a418800d0c812A9dE83Bc80e993A6b76511B57
...
```

3. **Send Deposit Transaction On L1**

We'll be using the first pre-funded account to send this deposit with 1 ether

```bash
cast send 0x37a418800d0c812A9dE83Bc80e993A6b76511B57 --value 1ether --rpc-url http://localhost:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
```

4. **Verify With Supersim Logs**

```bash
INFO [11-28|13:56:06.756] OptimismPortal#depositTransaction chain.id=901 l2TxHash=0x592d6e13016751332115df1fce59904176bfe447854196ed1b97ee00f14be469
```
19 changes: 16 additions & 3 deletions opsimulator/opsimulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ func (opSim *OpSimulator) Stop(ctx context.Context) error {
}

opSim.bgTasksCancel()
return opSim.httpServer.Stop(ctx)
if opSim.httpServer != nil {
return opSim.httpServer.Stop(ctx)
}

return nil
}

func (opSim *OpSimulator) EthClient() *ethclient.Client {
Expand Down Expand Up @@ -292,12 +296,21 @@ func (opSim *OpSimulator) handler(ctx context.Context) http.HandlerFunc {
batchRes[i] = msg.errorResponse(err)
continue
}

txHash := tx.Hash()

// Simulate the tx. If this fails, we let it pass through with a warning
// Deposits should not be directly sendable to the L2
if tx.IsDepositTx() {
opSim.log.Error("rejecting deposit tx", "hash", txHash.String())
batchRes[i] = msg.errorResponse(&jsonError{Code: InvalidParams, Message: "cannot process deposit tx"})
continue
}

// Simulate the tx.
logs, err := opSim.SimulatedLogs(ctx, tx)
if err != nil {
opSim.log.Warn("failed to simulate transaction!!! filtering tx...", "err", err, "hash", txHash)
opSim.log.Warn("failed to simulate transaction!!!", "err", err, "hash", txHash)
batchRes[i] = msg.errorResponse(&jsonError{Code: InvalidParams, Message: "failed tx simulation"})
continue
} else {
if err := opSim.checkInteropInvariants(ctx, logs); err != nil {
Expand Down
15 changes: 7 additions & 8 deletions orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,17 @@ func NewOrchestrator(log log.Logger, closeApp context.CancelCauseFunc, networkCo
}
}

a := admin.NewAdminServer(log, adminPort, networkConfig, o.l2ToL2MsgIndexer)

o.AdminServer = a

o.AdminServer = admin.NewAdminServer(log, adminPort, networkConfig, o.l2ToL2MsgIndexer)
return &o, nil
}

func (o *Orchestrator) Start(ctx context.Context) error {
o.log.Debug("starting orchestrator")

// Start Chains
if err := o.l1Chain.Start(ctx); err != nil {
return fmt.Errorf("l1 chain %s failed to start: %w", o.l1Chain.Config().Name, err)
}

for _, chain := range o.l2Chains {
if err := chain.Start(ctx); err != nil {
return fmt.Errorf("l2 chain %s failed to start: %w", chain.Config().Name, err)
Expand Down Expand Up @@ -118,8 +115,11 @@ func (o *Orchestrator) Start(ctx context.Context) error {
var wg sync.WaitGroup
wg.Add(len(o.l2Chains))
errs := make([]error, len(o.l2Chains))
for i, chain := range o.L2Chains() {
go func(i int) {

// Iterate over the underlying l2Chains for configuration as it relies
// on deposit txs from system addresses which opsimulator will reject
for i, chain := range o.l2Chains {
go func(i uint64) {
if err := interop.Configure(ctx, chain); err != nil {
errs[i] = fmt.Errorf("failed to configure interop for chain %s: %w", chain.Config().Name, err)
}
Expand All @@ -128,7 +128,6 @@ func (o *Orchestrator) Start(ctx context.Context) error {
}

wg.Wait()

if err := errors.Join(errs...); err != nil {
return err
}
Expand Down
22 changes: 19 additions & 3 deletions supersim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ func TestAccountBalances(t *testing.T) {
}
}

func TestDepositTxSimpleEthDeposit(t *testing.T) {
func TestOptimismPortalDeposit(t *testing.T) {
t.Parallel()

testSuite := createTestSuite(t, &config.CLIConfig{})
Expand Down Expand Up @@ -338,6 +338,23 @@ func TestDepositTxSimpleEthDeposit(t *testing.T) {
wg.Wait()
}

func TestDirectDepositTxFails(t *testing.T) {
t.Parallel()

testSuite := createTestSuite(t, &config.CLIConfig{})
l2Chain := testSuite.Supersim.Orchestrator.L2Chains()[0]

l2EthClient, err := ethclient.Dial(l2Chain.Endpoint())
require.NoError(t, err)
defer l2EthClient.Close()

// Create a deposit transaction
depositTx := &types.DepositTx{Mint: big.NewInt(1e18), Value: big.NewInt(0)}

// Fails when sent to the L2
require.Error(t, l2EthClient.SendTransaction(context.Background(), types.NewTx(depositTx)))
}

func TestDependencySet(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -819,7 +836,6 @@ func TestAutoRelaySimpleStorageCallSucceeds(t *testing.T) {
}

func TestAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) {

testSuite := createInteropTestSuite(t, config.CLIConfig{InteropAutoRelay: true})
privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0))
require.NoError(t, err)
Expand Down Expand Up @@ -1023,7 +1039,6 @@ func TestInteropInvariantFailsWhenDelayTimeNotPassed(t *testing.T) {
}

func TestAdminGetL2ToL2MessageByMsgHash(t *testing.T) {

testSuite := createInteropTestSuite(t, config.CLIConfig{InteropAutoRelay: true})
privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0))
require.NoError(t, err)
Expand Down Expand Up @@ -1079,6 +1094,7 @@ func TestAdminGetL2ToL2MessageByMsgHash(t *testing.T) {
assert.NoError(t, waitErr)

var message *JSONL2ToL2Message

// msgHash for the above sendERC20 txn
msgHash := "0x3656fd893944321663b2877d10db2895fb68e2346fd7e3f648ce5b986c200166"
rpcErr := client.CallContext(context.Background(), &message, "admin_getL2ToL2MessageByMsgHash", msgHash)
Expand Down

0 comments on commit ac5f803

Please sign in to comment.