Commit db1a81ed authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into inphi/fpp-comms

parents 7b425259 3d990967
...@@ -660,6 +660,45 @@ jobs: ...@@ -660,6 +660,45 @@ jobs:
command: npx depcheck command: npx depcheck
working_directory: integration-tests working_directory: integration-tests
atst-tests:
docker:
- image: ethereumoptimism/ci-builder:latest
resource_class: large
steps:
- checkout
- attach_workspace: { at: '.' }
- check-changed:
patterns: atst,contracts-periphery
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-v2-{{ checksum "yarn.lock" }}
- run:
name: anvil
background: true
command: anvil --fork-url $ANVIL_L2_FORK_URL_MAINNET --fork-block-number 92093723
- run:
name: build
command: yarn build
working_directory: packages/atst
- run:
name: typecheck
command: yarn typecheck
working_directory: packages/atst
- run:
name: lint
command: yarn lint:check
working_directory: packages/atst
- run:
name: make sure anvil is up
command: npx wait-on tcp:8545 && cast block-number --rpc-url http://localhost:8545
- run:
name: test
command: yarn test
no_output_timeout: 5m
working_directory: packages/atst
go-lint: go-lint:
parameters: parameters:
module: module:
...@@ -1094,6 +1133,9 @@ workflows: ...@@ -1094,6 +1133,9 @@ workflows:
- op-bindings-build: - op-bindings-build:
requires: requires:
- yarn-monorepo - yarn-monorepo
- atst-tests:
requires:
- yarn-monorepo
- js-lint-test: - js-lint-test:
name: actor-tests-tests name: actor-tests-tests
coverage_flag: actor-tests-tests coverage_flag: actor-tests-tests
......
...@@ -11,7 +11,8 @@ One easy way to do this is to use [Blockscout](https://www.blockscout.com/). ...@@ -11,7 +11,8 @@ One easy way to do this is to use [Blockscout](https://www.blockscout.com/).
### Archive mode ### Archive mode
Blockscout expects to interact with an Ethereum execution client in [archive mode](https://www.alchemy.com/overviews/archive-nodes#archive-nodes). Blockscout expects to interact with an Ethereum execution client in [archive mode](https://www.alchemy.com/overviews/archive-nodes#archive-nodes).
To create such a node, follow the [directions to add a node](./getting-started.md#adding-nodes), but in the command you use to start `op-geth` replace: If your `op-geth` is running in full mode, you can create a separate archive node.
To do so, follow the [directions to add a node](./getting-started.md#adding-nodes), but in the command you use to start `op-geth` replace:
```sh ```sh
--gcmode=full \ --gcmode=full \
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
oppcl "github.com/ethereum-optimism/optimism/op-program/client" oppcl "github.com/ethereum-optimism/optimism/op-program/client"
opp "github.com/ethereum-optimism/optimism/op-program/host" opp "github.com/ethereum-optimism/optimism/op-program/host"
oppconf "github.com/ethereum-optimism/optimism/op-program/host/config" oppconf "github.com/ethereum-optimism/optimism/op-program/host/config"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
...@@ -39,26 +40,51 @@ func TestVerifyL2OutputRoot(t *testing.T) { ...@@ -39,26 +40,51 @@ func TestVerifyL2OutputRoot(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
rollupClient := sources.NewRollupClient(client.NewBaseRPCClient(rollupRPCClient)) rollupClient := sources.NewRollupClient(client.NewBaseRPCClient(rollupRPCClient))
// TODO (CLI-3855): Actually perform some tx to set up a more complex chain. t.Log("Sending transactions to setup existing state, prior to challenged period")
aliceKey := cfg.Secrets.Alice
// Wait for the safe head to reach block 10 opts, err := bind.NewKeyedTransactorWithChainID(aliceKey, cfg.L1ChainIDBig())
require.NoError(t, waitForSafeHead(ctx, 10, rollupClient)) require.Nil(t, err)
SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *DepositTxOpts) {
// Use block 5 as the agreed starting block on L2 l2Opts.Value = big.NewInt(100_000_000)
l2AgreedBlock, err := l2Seq.BlockByNumber(ctx, big.NewInt(5)) })
require.NoError(t, err, "could not retrieve l2 genesis") SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *TxOpts) {
l2Head := l2AgreedBlock.Hash() // Agreed starting L2 block opts.ToAddr = &cfg.Secrets.Addresses().Bob
opts.Value = big.NewInt(1_000)
// Get the expected output at block 10 opts.Nonce = 1
l2ClaimBlockNumber := uint64(10) })
SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *WithdrawalTxOpts) {
opts.Value = big.NewInt(500)
opts.Nonce = 2
})
t.Log("Capture current L2 head as agreed starting point")
l2AgreedBlock, err := l2Seq.BlockByNumber(ctx, nil)
require.NoError(t, err, "could not retrieve l2 agreed block")
l2Head := l2AgreedBlock.Hash()
t.Log("Sending transactions to modify existing state, within challenged period")
SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *DepositTxOpts) {
l2Opts.Value = big.NewInt(5_000)
})
SendL2Tx(t, cfg, l2Seq, cfg.Secrets.Bob, func(opts *TxOpts) {
opts.ToAddr = &cfg.Secrets.Addresses().Alice
opts.Value = big.NewInt(100)
})
SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *WithdrawalTxOpts) {
opts.Value = big.NewInt(100)
opts.Nonce = 4
})
t.Log("Determine L2 claim")
l2ClaimBlockNumber, err := l2Seq.BlockNumber(ctx)
require.NoError(t, err, "get L2 claim block number")
l2Output, err := rollupClient.OutputAtBlock(ctx, l2ClaimBlockNumber) l2Output, err := rollupClient.OutputAtBlock(ctx, l2ClaimBlockNumber)
require.NoError(t, err, "could not get expected output") require.NoError(t, err, "could not get expected output")
l2Claim := l2Output.OutputRoot l2Claim := l2Output.OutputRoot
// Find the current L1 head t.Log("Determine L1 head that includes all batches required for L2 claim block")
l1BlockNumber, err := l1Client.BlockNumber(ctx) require.NoError(t, waitForSafeHead(ctx, l2ClaimBlockNumber, rollupClient))
require.NoError(t, err, "get l1 head block number") l1HeadBlock, err := l1Client.BlockByNumber(ctx, nil)
l1HeadBlock, err := l1Client.BlockByNumber(ctx, new(big.Int).SetUint64(l1BlockNumber))
require.NoError(t, err, "get l1 head block") require.NoError(t, err, "get l1 head block")
l1Head := l1HeadBlock.Hash() l1Head := l1HeadBlock.Hash()
...@@ -73,7 +99,11 @@ func TestVerifyL2OutputRoot(t *testing.T) { ...@@ -73,7 +99,11 @@ func TestVerifyL2OutputRoot(t *testing.T) {
err = opp.FaultProofProgram(log, fppConfig) err = opp.FaultProofProgram(log, fppConfig)
require.NoError(t, err) require.NoError(t, err)
t.Log("Shutting down network")
// Shutdown the nodes from the actual chain. Should now be able to run using only the pre-fetched data. // Shutdown the nodes from the actual chain. Should now be able to run using only the pre-fetched data.
sys.BatchSubmitter.StopIfRunning(context.Background())
sys.L2OutputSubmitter.Stop()
sys.L2OutputSubmitter = nil
for _, node := range sys.Nodes { for _, node := range sys.Nodes {
require.NoError(t, node.Close()) require.NoError(t, node.Close())
} }
......
...@@ -6,18 +6,17 @@ import ( ...@@ -6,18 +6,17 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-node/eth" "github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-program/client/l1" "github.com/ethereum-optimism/optimism/op-program/client/l1"
"github.com/ethereum-optimism/optimism/op-program/client/l2" "github.com/ethereum-optimism/optimism/op-program/client/l2"
"github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-program/client/mpt"
"github.com/ethereum-optimism/optimism/op-program/host/kvstore" "github.com/ethereum-optimism/optimism/op-program/host/kvstore"
"github.com/ethereum-optimism/optimism/op-program/preimage" "github.com/ethereum-optimism/optimism/op-program/preimage"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
) )
type L1Source interface { type L1Source interface {
...@@ -33,6 +32,7 @@ type L2Source interface { ...@@ -33,6 +32,7 @@ type L2Source interface {
} }
type Prefetcher struct { type Prefetcher struct {
logger log.Logger
l1Fetcher L1Source l1Fetcher L1Source
l2Fetcher L2Source l2Fetcher L2Source
lastHint string lastHint string
...@@ -41,6 +41,7 @@ type Prefetcher struct { ...@@ -41,6 +41,7 @@ type Prefetcher struct {
func NewPrefetcher(logger log.Logger, l1Fetcher L1Source, l2Fetcher L2Source, kvStore kvstore.KV) *Prefetcher { func NewPrefetcher(logger log.Logger, l1Fetcher L1Source, l2Fetcher L2Source, kvStore kvstore.KV) *Prefetcher {
return &Prefetcher{ return &Prefetcher{
logger: logger,
l1Fetcher: NewRetryingL1Source(logger, l1Fetcher), l1Fetcher: NewRetryingL1Source(logger, l1Fetcher),
l2Fetcher: NewRetryingL2Source(logger, l2Fetcher), l2Fetcher: NewRetryingL2Source(logger, l2Fetcher),
kvStore: kvStore, kvStore: kvStore,
...@@ -71,6 +72,7 @@ func (p *Prefetcher) prefetch(ctx context.Context, hint string) error { ...@@ -71,6 +72,7 @@ func (p *Prefetcher) prefetch(ctx context.Context, hint string) error {
if err != nil { if err != nil {
return err return err
} }
p.logger.Debug("Prefetching", "type", hintType, "hash", hash)
switch hintType { switch hintType {
case l1.HintL1BlockHeader: case l1.HintL1BlockHeader:
header, err := p.l1Fetcher.InfoByHash(ctx, hash) header, err := p.l1Fetcher.InfoByHash(ctx, hash)
...@@ -143,8 +145,11 @@ func (p *Prefetcher) storeTransactions(txs types.Transactions) error { ...@@ -143,8 +145,11 @@ func (p *Prefetcher) storeTransactions(txs types.Transactions) error {
func (p *Prefetcher) storeTrieNodes(values []hexutil.Bytes) error { func (p *Prefetcher) storeTrieNodes(values []hexutil.Bytes) error {
_, nodes := mpt.WriteTrie(values) _, nodes := mpt.WriteTrie(values)
for _, node := range nodes { for _, node := range nodes {
err := p.kvStore.Put(preimage.Keccak256Key(crypto.Keccak256Hash(node)).PreimageKey(), node) key := preimage.Keccak256Key(crypto.Keccak256Hash(node)).PreimageKey()
if err != nil { if err := p.kvStore.Put(key, node); errors.Is(err, kvstore.ErrAlreadyExists) {
// It's not uncommon for different tries to contain common nodes (esp for receipts)
continue
} else if err != nil {
return fmt.Errorf("failed to store node: %w", err) return fmt.Errorf("failed to store node: %w", err)
} }
} }
......
...@@ -129,6 +129,28 @@ func TestFetchL1Receipts(t *testing.T) { ...@@ -129,6 +129,28 @@ func TestFetchL1Receipts(t *testing.T) {
require.EqualValues(t, hash, header.Hash()) require.EqualValues(t, hash, header.Hash())
assertReceiptsEqual(t, receipts, actualReceipts) assertReceiptsEqual(t, receipts, actualReceipts)
}) })
// Blocks may have identical RLP receipts for different transactions.
// Check that the node already existing is handled
t.Run("CommonTrieNodes", func(t *testing.T) {
prefetcher, l1Cl, _, kv := createPrefetcher(t)
l1Cl.ExpectInfoByHash(hash, eth.BlockToInfo(block), nil)
l1Cl.ExpectInfoAndTxsByHash(hash, eth.BlockToInfo(block), block.Transactions(), nil)
l1Cl.ExpectFetchReceipts(hash, eth.BlockToInfo(block), receipts, nil)
defer l1Cl.AssertExpectations(t)
// Pre-store one receipt node (but not the whole trie leading to it)
// This would happen if an identical receipt was in an earlier block
opaqueRcpts, err := eth.EncodeReceipts(receipts)
require.NoError(t, err)
_, nodes := mpt.WriteTrie(opaqueRcpts)
require.NoError(t, kv.Put(preimage.Keccak256Key(crypto.Keccak256Hash(nodes[0])).PreimageKey(), nodes[0]))
oracle := l1.NewPreimageOracle(asOracleFn(t, prefetcher), asHinter(t, prefetcher))
header, actualReceipts := oracle.ReceiptsByBlockHash(hash)
require.EqualValues(t, hash, header.Hash())
assertReceiptsEqual(t, receipts, actualReceipts)
})
} }
func TestFetchL2Block(t *testing.T) { func TestFetchL2Block(t *testing.T) {
......
...@@ -55,6 +55,14 @@ func (k Keccak256Key) PreimageKey() (out common.Hash) { ...@@ -55,6 +55,14 @@ func (k Keccak256Key) PreimageKey() (out common.Hash) {
return return
} }
func (k Keccak256Key) String() string {
return common.Hash(k).String()
}
func (k Keccak256Key) TerminalString() string {
return common.Hash(k).String()
}
// Hint is an interface to enable any program type to function as a hint, // Hint is an interface to enable any program type to function as a hint,
// when passed to the Hinter interface, returning a string representation // when passed to the Hinter interface, returning a string representation
// of what data the host should prepare pre-images for. // of what data the host should prepare pre-images for.
......
...@@ -18,7 +18,7 @@ Vitest snapshots for the vitest tests ...@@ -18,7 +18,7 @@ Vitest snapshots for the vitest tests
CLI implementations of atst read and write CLI implementations of atst read and write
## contants ## constants
Internal and external constants Internal and external constants
......
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