Commit 0c515ad5 authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: migrate hh tasks to go

parent beb6a4d9
This diff is collapsed.
...@@ -2,11 +2,16 @@ package main ...@@ -2,11 +2,16 @@ package main
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"sync"
"time" "time"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings" legacy_bindings "github.com/ethereum-optimism/optimism/op-bindings/legacy-bindings"
...@@ -14,6 +19,7 @@ import ( ...@@ -14,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind" "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/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
...@@ -28,8 +34,8 @@ func main() { ...@@ -28,8 +34,8 @@ func main() {
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "fetch", Name: "deposits",
Usage: "Fetches batches in the specified range", Usage: "Ensures that all deposits have been ingested into L2",
Flags: flags, Flags: flags,
Action: func(cliCtx *cli.Context) error { Action: func(cliCtx *cli.Context) error {
clients, err := util.NewClients(cliCtx) clients, err := util.NewClients(cliCtx)
...@@ -100,28 +106,86 @@ func main() { ...@@ -100,28 +106,86 @@ func main() {
for { for {
bn := new(big.Int).SetUint64(blockNumber) bn := new(big.Int).SetUint64(blockNumber)
// TODO: Cannot use BlockByNumber, need to make a low level log.Info("Checking L2 block", "number", bn)
// call so that it can parse the legacy system's diff
block, err := clients.L2Client.BlockByNumber(context.Background(), bn) block, err := clients.L2Client.BlockByNumber(context.Background(), bn)
if err != nil { if err != nil {
return err return err
} }
fmt.Println(block)
blockNumber--
// TODO: remove if length := len(block.Transactions()); length != 1 {
break return fmt.Errorf("unexpected number of transactions in block: %d", length)
}
tx := block.Transactions()[0]
hash := tx.Hash()
json, err := legacyTransactionByHash(clients.L2RpcClient, hash)
if err != nil {
return err
}
if json.QueueOrigin == "l1" {
if json.QueueIndex == nil {
// This should never happen
return errors.New("queue index is nil")
}
queueIndex := uint64(*json.QueueIndex)
if queueIndex == queueLength.Uint64()-1 {
log.Info("Found final deposit in l2geth", "queue-index", queueIndex)
break
}
if queueIndex < queueLength.Uint64() {
return errors.New("missed final deposit")
}
}
blockNumber--
} }
finalPending, err := ctc.GetNumPendingQueueElements(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("Remaining deposits that must be submitted", "count", finalPending)
return nil return nil
}, },
}, },
{ {
// TODO Name: "batches",
Name: "", Usage: "Ensures that all batches have been submitted to L1",
Usage: "", Flags: flags,
Flags: []cli.Flag{},
Action: func(cliCtx *cli.Context) error { Action: func(cliCtx *cli.Context) error {
clients, err := util.NewClients(cliCtx)
if err != nil {
return err
}
addresses, err := util.NewAddresses(cliCtx)
if err != nil {
return err
}
ctc, err := legacy_bindings.NewCanonicalTransactionChain(addresses.CanonicalTransactionChain, clients.L1Client)
if err != nil {
return err
}
scc, err := legacy_bindings.NewStateCommitmentChain(addresses.StateCommitmentChain, clients.L1Client)
if err != nil {
return err
}
var wg sync.WaitGroup
log.Info("Waiting for CanonicalTransactionChain")
wg.Add(1)
go waitForTotalElements(wg, ctc, clients.L2Client)
log.Info("Waiting for StateCommitmentChain")
wg.Add(1)
go waitForTotalElements(wg, scc, clients.L2Client)
wg.Wait()
log.Info("All batches have been submitted")
return nil return nil
}, },
}, },
...@@ -131,3 +195,94 @@ func main() { ...@@ -131,3 +195,94 @@ func main() {
log.Crit("Application failed", "message", err) log.Crit("Application failed", "message", err)
} }
} }
// RollupContract represents a legacy rollup contract interface that
// exposes the GetTotalElements function. Both the StateCommitmentChain
// and the CanonicalTransactionChain implement this interface.
type RollupContract interface {
GetTotalElements(opts *bind.CallOpts) (*big.Int, error)
}
// waitForTotalElements will poll to see
func waitForTotalElements(wg sync.WaitGroup, contract RollupContract, client *ethclient.Client) error {
defer wg.Done()
for {
bn, err := client.BlockNumber(context.Background())
if err != nil {
return err
}
totalElements, err := contract.GetTotalElements(&bind.CallOpts{})
if err != nil {
return err
}
if totalElements.Cmp(bn) == 0 {
return nil
}
log.Info("Waiting for elements to be submitted", "count", totalElements.Uint64()-bn.Uint64(), "height", bn.Uint64(), "total-elements", totalElements.Uint64())
time.Sleep(3 * time.Second)
}
return nil
}
// legacyTransactionByHash will fetch a transaction by hash and be sure to decode
// the additional fields added to legacy transactions.
func legacyTransactionByHash(client *rpc.Client, hash common.Hash) (*RPCTransaction, error) {
var json *RPCTransaction
err := client.CallContext(context.Background(), &json, "eth_getTransactionByHash", hash)
if err != nil {
return nil, err
}
return json, nil
}
// toBlockNumArg is able to handle the conversion between a big.Int and a
// string blocktag. This function should be used in JSON RPC interactions
// when fetching data by block number.
func toBlockNumArg(number *big.Int) string {
if number == nil {
return "latest"
}
pending := big.NewInt(-1)
if number.Cmp(pending) == 0 {
return "pending"
}
finalized := big.NewInt(int64(rpc.FinalizedBlockNumber))
if number.Cmp(finalized) == 0 {
return "finalized"
}
safe := big.NewInt(int64(rpc.SafeBlockNumber))
if number.Cmp(safe) == 0 {
return "safe"
}
return hexutil.EncodeBig(number)
}
// RPCTransaction represents a transaction that will serialize to the RPC representation of a
// transaction. This handles the extra legacy fields added to transactions.
type RPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
QueueOrigin string `json:"queueOrigin"`
L1TxOrigin *common.Address `json:"l1TxOrigin"`
L1BlockNumber *hexutil.Big `json:"l1BlockNumber"`
L1Timestamp hexutil.Uint64 `json:"l1Timestamp"`
Index *hexutil.Uint64 `json:"index"`
QueueIndex *hexutil.Uint64 `json:"queueIndex"`
RawTransaction hexutil.Bytes `json:"rawTransaction"`
}
...@@ -85,7 +85,7 @@ func NewClients(ctx *cli.Context) (*Clients, error) { ...@@ -85,7 +85,7 @@ func NewClients(ctx *cli.Context) (*Clients, error) {
}, nil }, nil
} }
// ClientsFlags // ClientsFlags represent the flags associated with creating RPC clients.
var ClientsFlags = []cli.Flag{ var ClientsFlags = []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "l1-rpc-url", Name: "l1-rpc-url",
...@@ -109,9 +109,10 @@ type Addresses struct { ...@@ -109,9 +109,10 @@ type Addresses struct {
L1StandardBridge common.Address L1StandardBridge common.Address
L1CrossDomainMessenger common.Address L1CrossDomainMessenger common.Address
CanonicalTransactionChain common.Address CanonicalTransactionChain common.Address
StateCommitmentChain common.Address
} }
// AddressesFlags // AddressesFlags represent the flags associated with address parsing.
var AddressesFlags = []cli.Flag{ var AddressesFlags = []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "address-manager-address", Name: "address-manager-address",
...@@ -138,6 +139,11 @@ var AddressesFlags = []cli.Flag{ ...@@ -138,6 +139,11 @@ var AddressesFlags = []cli.Flag{
Usage: "CanonicalTransactionChain address", Usage: "CanonicalTransactionChain address",
EnvVars: []string{"CANONICAL_TRANSACTION_CHAIN_ADDRESS"}, EnvVars: []string{"CANONICAL_TRANSACTION_CHAIN_ADDRESS"},
}, },
&cli.StringFlag{
Name: "state-commitment-chain-address",
Usage: "StateCommitmentChain address",
EnvVars: []string{"STATE_COMMITMENT_CHAIN_ADDRESS"},
},
} }
// NewAddresses populates an Addresses struct given a [cli.Context]. // NewAddresses populates an Addresses struct given a [cli.Context].
...@@ -166,6 +172,10 @@ func NewAddresses(ctx *cli.Context) (*Addresses, error) { ...@@ -166,6 +172,10 @@ func NewAddresses(ctx *cli.Context) (*Addresses, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
addresses.StateCommitmentChain, err = parseAddress(ctx, "state-commitment-chain-address")
if err != nil {
return nil, err
}
return &addresses, nil return &addresses, nil
} }
......
...@@ -7,7 +7,7 @@ if [ ! -d "$OUTDIR" ]; then ...@@ -7,7 +7,7 @@ if [ ! -d "$OUTDIR" ]; then
exit 1 exit 1
fi fi
CONTRACTS=("CanonicalTransactionChain") CONTRACTS=("CanonicalTransactionChain" "StateCommitmentChain")
PKG=legacy_bindings PKG=legacy_bindings
for contract in ${CONTRACTS[@]}; do for contract in ${CONTRACTS[@]}; do
......
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