Commit 59132e13 authored by Adrian Sutton's avatar Adrian Sutton

Merge branch 'develop' into aj/deploy-dispute-game-e2e

parents 9b93ae25 677bff37
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
"changelog": ["@changesets/changelog-github", { "repo": "ethereum-optimism/optimism" }], "changelog": ["@changesets/changelog-github", { "repo": "ethereum-optimism/optimism" }],
"commit": false, "commit": false,
"fixed": [], "fixed": [],
"linked": [["contracts-bedrock", "contracts-ts"]], "linked": [["@eth-optimism/contracts-bedrock", "@eth-optimism/contracts-ts"]],
"access": "public", "access": "public",
"baseBranch": "develop", "baseBranch": "develop",
"updateInternalDependencies": "patch", "updateInternalDependencies": "patch",
......
---
'@eth-optimism/sdk': minor
---
Added to and from block filters to several methods in CrossChainMessenger
...@@ -197,7 +197,7 @@ jobs: ...@@ -197,7 +197,7 @@ jobs:
fi fi
IMAGE_BASE="<<parameters.registry>>/<<parameters.repo>>/<<parameters.docker_name>>" IMAGE_BASE="<<parameters.registry>>/<<parameters.repo>>/<<parameters.docker_name>>"
DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|") DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|")
docker build \ docker build --progress plain \
$(echo -ne $DOCKER_TAGS | tr '\n' ' ') \ $(echo -ne $DOCKER_TAGS | tr '\n' ' ') \
-f <<parameters.docker_file>> \ -f <<parameters.docker_file>> \
<<parameters.docker_context>> <<parameters.docker_context>>
...@@ -266,7 +266,7 @@ jobs: ...@@ -266,7 +266,7 @@ jobs:
DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|") DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|")
docker context create buildx-build docker context create buildx-build
docker buildx create --use buildx-build docker buildx create --use buildx-build
docker buildx build --platform=<<parameters.platforms>> --target "<<parameters.docker_target>>" --push \ docker buildx build --progress plain --platform=<<parameters.platforms>> --target "<<parameters.docker_target>>" --push \
$(echo -ne $DOCKER_TAGS | tr '\n' ' ') \ $(echo -ne $DOCKER_TAGS | tr '\n' ' ') \
-f <<parameters.docker_file>> \ -f <<parameters.docker_file>> \
<<parameters.docker_context>> <<parameters.docker_context>>
...@@ -321,7 +321,7 @@ jobs: ...@@ -321,7 +321,7 @@ jobs:
DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|") DOCKER_TAGS=$(echo -ne <<parameters.docker_tags>> | sed "s/,/\n/g" | sed "s/[^a-zA-Z0-9\n]/-/g" | sed -e "s|^|-t ${IMAGE_BASE}:|")
docker context create buildx-build docker context create buildx-build
docker buildx create --use buildx-build docker buildx create --use buildx-build
docker buildx build --platform=<<parameters.platforms>> --target "<<parameters.docker_target>>" --push \ docker buildx build --progress plain --platform=<<parameters.platforms>> --target "<<parameters.docker_target>>" --push \
$(echo -ne $DOCKER_TAGS | tr '\n' ' ') \ $(echo -ne $DOCKER_TAGS | tr '\n' ' ') \
-f <<parameters.docker_file>> \ -f <<parameters.docker_file>> \
<<parameters.docker_context>> <<parameters.docker_context>>
...@@ -1745,6 +1745,21 @@ workflows: ...@@ -1745,6 +1745,21 @@ workflows:
- oplabs-gcr-release - oplabs-gcr-release
requires: requires:
- hold - hold
- docker-release:
name: op-ufm-docker-release
filters:
tags:
only: /^op-ufm\/v.*/
branches:
ignore: /.*/
docker_file: op-ufm/Dockerfile
docker_name: op-ufm
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
docker_context: .
context:
- oplabs-gcr-release
requires:
- hold
- docker-release: - docker-release:
name: proxyd-docker-release name: proxyd-docker-release
filters: filters:
......
...@@ -18,13 +18,14 @@ on: ...@@ -18,13 +18,14 @@ on:
required: true required: true
type: choice type: choice
options: options:
- ci-builder
- fault-detector
- indexer
- op-node - op-node
- op-batcher - op-batcher
- op-proposer - op-proposer
- op-ufm
- proxyd - proxyd
- indexer
- fault-detector
- ci-builder
prerelease: prerelease:
description: Increment major/minor/patch as prerelease? description: Increment major/minor/patch as prerelease?
required: false required: false
......
--- ---
title: Using the SDK with OP Stack title: Using the OP Stack Client SDK
lang: en-US lang: en-US
--- ---
When building applications for use with your OP Stack, you can continue to use [the Optimism JavaScript SDK](https://sdk.optimism.io/).
The main difference is you need to provide some contract addresses to the `CrossDomainMessenger` because they aren't preconfigured.
## Natively supported chains
## Contract addresses [The OP Stack Client SDK](https://sdk.optimism.io/) natively supports multiple OP Chains: OP, Base, etc.
To see whether a specific OP Chain is supported directly, [see the documentation](https://sdk.optimism.io/enums/l2chainid).
### L1 contract addresses ## Not natively supported chains
The contract addresses are in `.../optimism/packages/contracts-bedrock/deployments/getting-started`, which you created when you deployed the L1 contracts. If you are using a chain that is *not* natively supported, for example an OP Stack chain [you just created](./getting-started.md), you can continue to use [the OP Stack Client SDK](https://sdk.optimism.io/).
You just need to provide some contract addresses to the `CrossDomainMessenger` because they aren't preconfigured.
### Getting contract addresses
#### L1 contract addresses
If you followed the directions in [Getting Started](./getting-started.md), the contract addresses are in `.../optimism/packages/contracts-bedrock/deployments/getting-started`, which you created when you deployed the L1 contracts.
| Contract name when creating `CrossDomainMessenger` | File with address | | Contract name when creating `CrossDomainMessenger` | File with address |
| - | - | | - | - |
...@@ -22,9 +29,9 @@ The contract addresses are in `.../optimism/packages/contracts-bedrock/deploymen ...@@ -22,9 +29,9 @@ The contract addresses are in `.../optimism/packages/contracts-bedrock/deploymen
| `L2OutputOracle` | `L2OutputOracleProxy.json` | `L2OutputOracle` | `L2OutputOracleProxy.json`
### Unneeded contract addresses #### Unneeded contract addresses
Some contracts are required by the SDK, but not actually used. Some contracts are required by the SDK as a sanity check, but are not actually used.
For these contracts you can just specify the zero address: For these contracts you can just specify the zero address:
- `StateCommitmentChain` - `StateCommitmentChain`
...@@ -33,7 +40,7 @@ For these contracts you can just specify the zero address: ...@@ -33,7 +40,7 @@ For these contracts you can just specify the zero address:
In JavaScript you can create the zero address using the expression `"0x".padEnd(42, "0")`. In JavaScript you can create the zero address using the expression `"0x".padEnd(42, "0")`.
## The CrossChainMessenger object ### The CrossChainMessenger object
These directions assume you are inside the [Hardhat console](https://hardhat.org/hardhat-runner/docs/guides/hardhat-console). These directions assume you are inside the [Hardhat console](https://hardhat.org/hardhat-runner/docs/guides/hardhat-console).
They further assume that your project already includes the Optimism SDK [`@eth-optimism/sdk`](https://www.npmjs.com/package/@eth-optimism/sdk). They further assume that your project already includes the Optimism SDK [`@eth-optimism/sdk`](https://www.npmjs.com/package/@eth-optimism/sdk).
...@@ -113,7 +120,7 @@ They further assume that your project already includes the Optimism SDK [`@eth-o ...@@ -113,7 +120,7 @@ They further assume that your project already includes the Optimism SDK [`@eth-o
}) })
``` ```
## Verify SDK functionality ### Verify SDK functionality
To verify the SDK's functionality, transfer some ETH from L1 to L2. To verify the SDK's functionality, transfer some ETH from L1 to L2.
......
...@@ -49,7 +49,7 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) { ...@@ -49,7 +49,7 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) {
func (ap *AlphabetProvider) AbsolutePreState() []byte { func (ap *AlphabetProvider) AbsolutePreState() []byte {
out := make([]byte, 32) out := make([]byte, 32)
out[31] = 140 // ascii character 140 is "`" out[31] = 96 // ascii character 96 is "`"
return out return out
} }
......
...@@ -10,6 +10,7 @@ import ( ...@@ -10,6 +10,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -40,6 +41,10 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) ( ...@@ -40,6 +41,10 @@ func (m *mockTxManager) Send(ctx context.Context, candidate txmgr.TxCandidate) (
), nil ), nil
} }
func (m *mockTxManager) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
panic("unimplemented")
}
func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) { func (m *mockTxManager) BlockNumber(ctx context.Context) (uint64, error) {
panic("not implemented") panic("not implemented")
} }
......
...@@ -44,6 +44,9 @@ type fakeTxMgr struct { ...@@ -44,6 +44,9 @@ type fakeTxMgr struct {
func (f fakeTxMgr) From() common.Address { func (f fakeTxMgr) From() common.Address {
return f.from return f.from
} }
func (f fakeTxMgr) Call(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
panic("unimplemented")
}
func (f fakeTxMgr) BlockNumber(_ context.Context) (uint64, error) { func (f fakeTxMgr) BlockNumber(_ context.Context) (uint64, error) {
panic("unimplemented") panic("unimplemented")
} }
......
...@@ -4,9 +4,12 @@ package mocks ...@@ -4,9 +4,12 @@ package mocks
import ( import (
context "context" context "context"
big "math/big"
common "github.com/ethereum/go-ethereum/common" common "github.com/ethereum/go-ethereum/common"
ethereum "github.com/ethereum/go-ethereum"
mock "github.com/stretchr/testify/mock" mock "github.com/stretchr/testify/mock"
txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr" txmgr "github.com/ethereum-optimism/optimism/op-service/txmgr"
...@@ -43,6 +46,32 @@ func (_m *TxManager) BlockNumber(ctx context.Context) (uint64, error) { ...@@ -43,6 +46,32 @@ func (_m *TxManager) BlockNumber(ctx context.Context) (uint64, error) {
return r0, r1 return r0, r1
} }
// Call provides a mock function with given fields: ctx, msg, blockNumber
func (_m *TxManager) Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
ret := _m.Called(ctx, msg, blockNumber)
var r0 []byte
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) ([]byte, error)); ok {
return rf(ctx, msg, blockNumber)
}
if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg, *big.Int) []byte); ok {
r0 = rf(ctx, msg, blockNumber)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
if rf, ok := ret.Get(1).(func(context.Context, ethereum.CallMsg, *big.Int) error); ok {
r1 = rf(ctx, msg, blockNumber)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// From provides a mock function with given fields: // From provides a mock function with given fields:
func (_m *TxManager) From() common.Address { func (_m *TxManager) From() common.Address {
ret := _m.Called() ret := _m.Called()
......
...@@ -45,6 +45,10 @@ type TxManager interface { ...@@ -45,6 +45,10 @@ type TxManager interface {
// NOTE: Send can be called concurrently, the nonce will be managed internally. // NOTE: Send can be called concurrently, the nonce will be managed internally.
Send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error) Send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error)
// Call is used to call a contract.
// Internally, it uses the [ethclient.Client.CallContract] method.
Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
// From returns the sending address associated with the instance of the transaction manager. // From returns the sending address associated with the instance of the transaction manager.
// It is static for a single instance of a TxManager. // It is static for a single instance of a TxManager.
From() common.Address From() common.Address
...@@ -59,6 +63,9 @@ type ETHBackend interface { ...@@ -59,6 +63,9 @@ type ETHBackend interface {
// BlockNumber returns the most recent block number. // BlockNumber returns the most recent block number.
BlockNumber(ctx context.Context) (uint64, error) BlockNumber(ctx context.Context) (uint64, error)
// CallContract executes an eth_call against the provided contract.
CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
// TransactionReceipt queries the backend for a receipt associated with // TransactionReceipt queries the backend for a receipt associated with
// txHash. If lookup does not fail, but the transaction is not found, // txHash. If lookup does not fail, but the transaction is not found,
// nil should be returned for both values. // nil should be returned for both values.
...@@ -155,6 +162,12 @@ func (m *SimpleTxManager) Send(ctx context.Context, candidate TxCandidate) (*typ ...@@ -155,6 +162,12 @@ func (m *SimpleTxManager) Send(ctx context.Context, candidate TxCandidate) (*typ
return receipt, err return receipt, err
} }
// Call is used to call a contract.
// Internally, it uses the [ethclient.Client.CallContract] method.
func (m *SimpleTxManager) Call(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
return m.backend.CallContract(ctx, msg, blockNumber)
}
// send performs the actual transaction creation and sending. // send performs the actual transaction creation and sending.
func (m *SimpleTxManager) send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error) { func (m *SimpleTxManager) send(ctx context.Context, candidate TxCandidate) (*types.Receipt, error) {
if m.cfg.TxSendTimeout != 0 { if m.cfg.TxSendTimeout != 0 {
......
...@@ -194,6 +194,11 @@ func (b *mockBackend) BlockNumber(ctx context.Context) (uint64, error) { ...@@ -194,6 +194,11 @@ func (b *mockBackend) BlockNumber(ctx context.Context) (uint64, error) {
return b.blockHeight, nil return b.blockHeight, nil
} }
// Call mocks a call to the EVM.
func (b *mockBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
return nil, nil
}
func (b *mockBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { func (b *mockBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
return &types.Header{ return &types.Header{
BaseFee: b.g.basefee(), BaseFee: b.g.basefee(),
...@@ -649,6 +654,10 @@ func (b *failingBackend) HeaderByNumber(_ context.Context, _ *big.Int) (*types.H ...@@ -649,6 +654,10 @@ func (b *failingBackend) HeaderByNumber(_ context.Context, _ *big.Int) (*types.H
}, nil }, nil
} }
func (b *failingBackend) CallContract(_ context.Context, _ ethereum.CallMsg, _ *big.Int) ([]byte, error) {
return nil, errors.New("unimplemented")
}
func (b *failingBackend) SendTransaction(_ context.Context, _ *types.Transaction) error { func (b *failingBackend) SendTransaction(_ context.Context, _ *types.Transaction) error {
return errors.New("unimplemented") return errors.New("unimplemented")
} }
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
"l1GenesisBlockTimestamp": "0x64935846", "l1GenesisBlockTimestamp": "0x64935846",
"l1StartingBlockTag": "earliest", "l1StartingBlockTag": "earliest",
"l2GenesisRegolithTimeOffset": "0x0", "l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": 140, "faultGameAbsolutePrestate": 96,
"faultGameMaxDepth": 4, "faultGameMaxDepth": 4,
"faultGameMaxDuration": 604800 "faultGameMaxDuration": 604800
} }
\ No newline at end of file
// public rpcs are heavily throttled/rate limited so replace these with rpcs with apikeys. These are meant to be testnet rpcs
// in future these will get renamed to VITE_E2E_RPC_URL_GOERLI etc.
VITE_E2E_RPC_URL_L1=https://ethereum-goerli.publicnode.com
VITE_E2E_RPC_URL_L2=https://goerli.optimism.io
\ No newline at end of file
This diff is collapsed.
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
- The new tests for the next version of sdk will use vitest - The new tests for the next version of sdk will use vitest
- The vitest tests are kept here seperated from mocha tests for now - The vitest tests are kept here seperated from mocha tests for now
- Can find values needed in a `.env` file in `example.env`
...@@ -11,22 +11,40 @@ const crossChainMessenger = new CrossChainMessenger({ ...@@ -11,22 +11,40 @@ const crossChainMessenger = new CrossChainMessenger({
bedrock: true, bedrock: true,
}) })
describe('prove message', () => { describe('getMessageStatus', () => {
it(`should be able to correctly find a finalized withdrawal`, async () => { it(`should be able to correctly find a finalized withdrawal`, async () => {
/** /**
* Tx hash of legacy withdrawal that was claimed * Tx hash of a withdrawal
* *
* @see https://goerli-optimism.etherscan.io/tx/0xda9e9c8dfc7718bc1499e1e64d8df6cddbabc46e819475a6c755db286a41b9fa * @see https://goerli-optimism.etherscan.io/tx/0x8fb235a61079f3fa87da66e78c9da075281bc4ba5f1af4b95197dd9480e03bb5
*/ */
const txWithdrawalHash = const txWithdrawalHash =
'0xda9e9c8dfc7718bc1499e1e64d8df6cddbabc46e819475a6c755db286a41b9fa' '0x8fb235a61079f3fa87da66e78c9da075281bc4ba5f1af4b95197dd9480e03bb5'
const txReceipt = await l2Provider.getTransactionReceipt(txWithdrawalHash) const txReceipt = await l2Provider.getTransactionReceipt(txWithdrawalHash)
expect(txReceipt).toBeDefined() expect(txReceipt).toBeDefined()
expect(await crossChainMessenger.getMessageStatus(txWithdrawalHash)).toBe( expect(
MessageStatus.RELAYED await crossChainMessenger.getMessageStatus(
) txWithdrawalHash,
0,
9370789 - 1000,
9370789
)
).toBe(MessageStatus.RELAYED)
}, 20_000)
it(`should return READY_FOR_RELAY if not in block range`, async () => {
const txWithdrawalHash =
'0x8fb235a61079f3fa87da66e78c9da075281bc4ba5f1af4b95197dd9480e03bb5'
const txReceipt = await l2Provider.getTransactionReceipt(txWithdrawalHash)
expect(txReceipt).toBeDefined()
expect(
await crossChainMessenger.getMessageStatus(txWithdrawalHash, 0, 0, 0)
).toBe(MessageStatus.READY_FOR_RELAY)
}, 20_000) }, 20_000)
}) })
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