Commit a25acbbd authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Refactor the SyncService to more closely implement the specification (#552)

* l2geth: add Backend enums and config parsing

* l2geth: move OVMContext to types file

* l2geth: implement syncservice spec

* l2geth: fix error handling for get tx batch

* l2geth: update tests to compile and pass

* l2geth: add sync range functions

* l2geth: add batch index indexing

* l2geth: update syncservice hot path logging

* l2geth: use indexed batch index

* chore: add changeset

* l2geth: sync spec refactor (#822)

* l2geth: more in depth usage string

* l2geth: add standard client getters for index

* l2geth: refactor sync service into shared codepaths

* l2geth: clean up tests

* l2geth: better logging and error handling

* test: improve test coverage around timestamps

* l2geth: improve docstring

* l2geth: rename variable

* sync-service: better logline

* l2geth: better logline

* l2geth: test apply indexed transaction

* l2geth: better logline

* linting: fix

* syncservice: fix logline

* l2geth: add error and fix logline

* l2geth: sync service tests

* fix: get last confirmed enqueue (#846)

* l2geth: fix get last confirmed enqueue

* chore: add changeset

* client: return error correctly

* batch-submitter: updated config (#847)

* batch-submitter: backwards compatible configuration

* chore: add changeset

* deps: update

* js: move bcfg interface to core-utils

* batch-submitter: parse USE_SENTRY and add to env example

* chore: add changeset

* batch-submitter: parse as float instead of int

* batch-submitter: better error logging

* l2geth: update rawdb logline
Co-authored-by: default avatarGeorgios Konstantopoulos <me@gakonst.com>

* l2geth: more robust testing
Co-authored-by: default avatarGeorgios Konstantopoulos <me@gakonst.com>

* l2geth: add sanity check for L1ToL2 timestamps

* l2geth: handle error in single place

* l2geth: fix test tx queue origin

* l2geth: add new arg to start.sh

* l2geth: return error in the SyncService.Start()

* chore: go fmt
Co-authored-by: default avatarGeorgios Konstantopoulos <me@gakonst.com>
parent c3d39df8
---
"@eth-optimism/l2geth": patch
---
Refactor the SyncService to more closely implement the specification. This includes using query params to select the backend from the DTL, trailing syncing of batches for the sequencer, syncing by batches as the verifier as well as unified code paths for transaction ingestion to prevent double ingestion or missed ingestion
...@@ -165,6 +165,7 @@ var ( ...@@ -165,6 +165,7 @@ var (
utils.RollupMaxCalldataSizeFlag, utils.RollupMaxCalldataSizeFlag,
utils.RollupDataPriceFlag, utils.RollupDataPriceFlag,
utils.RollupExecutionPriceFlag, utils.RollupExecutionPriceFlag,
utils.RollupBackendFlag,
utils.RollupEnableL2GasPollingFlag, utils.RollupEnableL2GasPollingFlag,
utils.RollupGasPriceOracleAddressFlag, utils.RollupGasPriceOracleAddressFlag,
utils.RollupEnforceFeesFlag, utils.RollupEnforceFeesFlag,
......
...@@ -80,6 +80,7 @@ var AppHelpFlagGroups = []flagGroup{ ...@@ -80,6 +80,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.RollupMaxCalldataSizeFlag, utils.RollupMaxCalldataSizeFlag,
utils.RollupDataPriceFlag, utils.RollupDataPriceFlag,
utils.RollupExecutionPriceFlag, utils.RollupExecutionPriceFlag,
utils.RollupBackendFlag,
utils.RollupEnableL2GasPollingFlag, utils.RollupEnableL2GasPollingFlag,
utils.RollupGasPriceOracleAddressFlag, utils.RollupGasPriceOracleAddressFlag,
utils.RollupEnforceFeesFlag, utils.RollupEnforceFeesFlag,
......
...@@ -851,6 +851,12 @@ var ( ...@@ -851,6 +851,12 @@ var (
Value: time.Minute * 3, Value: time.Minute * 3,
EnvVar: "ROLLUP_TIMESTAMP_REFRESH", EnvVar: "ROLLUP_TIMESTAMP_REFRESH",
} }
RollupBackendFlag = cli.StringFlag{
Name: "rollup.backend",
Usage: "Sync backend for verifiers (\"l1\" or \"l2\"), defaults to l1",
Value: "l1",
EnvVar: "ROLLUP_BACKEND",
}
// Flag to enable verifier mode // Flag to enable verifier mode
RollupEnableVerifierFlag = cli.BoolFlag{ RollupEnableVerifierFlag = cli.BoolFlag{
Name: "rollup.verifier", Name: "rollup.verifier",
...@@ -1188,6 +1194,15 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) { ...@@ -1188,6 +1194,15 @@ func setRollup(ctx *cli.Context, cfg *rollup.Config) {
if ctx.GlobalIsSet(RollupExecutionPriceFlag.Name) { if ctx.GlobalIsSet(RollupExecutionPriceFlag.Name) {
cfg.ExecutionPrice = GlobalBig(ctx, RollupExecutionPriceFlag.Name) cfg.ExecutionPrice = GlobalBig(ctx, RollupExecutionPriceFlag.Name)
} }
if ctx.GlobalIsSet(RollupBackendFlag.Name) {
val := ctx.GlobalString(RollupBackendFlag.Name)
backend, err := rollup.NewBackend(val)
if err != nil {
log.Error("Configured with unknown sync backend, defaulting to l1", "backend", val)
backend, _ = rollup.NewBackend("l1")
}
cfg.Backend = backend
}
if ctx.GlobalIsSet(RollupGasPriceOracleAddressFlag.Name) { if ctx.GlobalIsSet(RollupGasPriceOracleAddressFlag.Name) {
addr := ctx.GlobalString(RollupGasPriceOracleAddressFlag.Name) addr := ctx.GlobalString(RollupGasPriceOracleAddressFlag.Name)
cfg.GasPriceOracleAddress = common.HexToAddress(addr) cfg.GasPriceOracleAddress = common.HexToAddress(addr)
......
...@@ -69,3 +69,24 @@ func WriteHeadVerifiedIndex(db ethdb.KeyValueWriter, index uint64) { ...@@ -69,3 +69,24 @@ func WriteHeadVerifiedIndex(db ethdb.KeyValueWriter, index uint64) {
log.Crit("Failed to store verifier index", "err", err) log.Crit("Failed to store verifier index", "err", err)
} }
} }
// ReadHeadBatchIndex will read the known tip of the processed batches
func ReadHeadBatchIndex(db ethdb.KeyValueReader) *uint64 {
data, _ := db.Get(headBatchKey)
if len(data) == 0 {
return nil
}
ret := new(big.Int).SetBytes(data).Uint64()
return &ret
}
// WriteHeadBatchIndex will write the known tip of the processed batches
func WriteHeadBatchIndex(db ethdb.KeyValueWriter, index uint64) {
value := new(big.Int).SetUint64(index).Bytes()
if index == 0 {
value = []byte{0}
}
if err := db.Put(headBatchKey, value); err != nil {
log.Crit("Failed to store head batch index", "err", err)
}
}
...@@ -62,6 +62,8 @@ var ( ...@@ -62,6 +62,8 @@ var (
headQueueIndexKey = []byte("LastQueueIndex") headQueueIndexKey = []byte("LastQueueIndex")
// headVerifiedIndexKey tracks the latest verified index // headVerifiedIndexKey tracks the latest verified index
headVerifiedIndexKey = []byte("LastVerifiedIndex") headVerifiedIndexKey = []byte("LastVerifiedIndex")
// headBatchKey tracks the latest processed batch
headBatchKey = []byte("LastBatch")
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
configPrefix = []byte("ethereum-config-") // config prefix for the db configPrefix = []byte("ethereum-config-") // config prefix for the db
......
...@@ -330,7 +330,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) ...@@ -330,7 +330,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
} }
} }
} }
return b.eth.syncService.ApplyTransaction(signedTx) return b.eth.syncService.ValidateAndApplySequencerTransaction(signedTx)
} }
// OVM Disabled // OVM Disabled
return b.eth.txPool.AddLocal(signedTx) return b.eth.txPool.AddLocal(signedTx)
......
...@@ -116,14 +116,17 @@ type decoded struct { ...@@ -116,14 +116,17 @@ type decoded struct {
type RollupClient interface { type RollupClient interface {
GetEnqueue(index uint64) (*types.Transaction, error) GetEnqueue(index uint64) (*types.Transaction, error)
GetLatestEnqueue() (*types.Transaction, error) GetLatestEnqueue() (*types.Transaction, error)
GetTransaction(uint64) (*types.Transaction, error) GetLatestEnqueueIndex() (*uint64, error)
GetLatestTransaction() (*types.Transaction, error) GetTransaction(uint64, Backend) (*types.Transaction, error)
GetLatestTransaction(Backend) (*types.Transaction, error)
GetLatestTransactionIndex(Backend) (*uint64, error)
GetEthContext(uint64) (*EthContext, error) GetEthContext(uint64) (*EthContext, error)
GetLatestEthContext() (*EthContext, error) GetLatestEthContext() (*EthContext, error)
GetLastConfirmedEnqueue() (*types.Transaction, error) GetLastConfirmedEnqueue() (*types.Transaction, error)
GetLatestTransactionBatch() (*Batch, []*types.Transaction, error) GetLatestTransactionBatch() (*Batch, []*types.Transaction, error)
GetLatestTransactionBatchIndex() (*uint64, error)
GetTransactionBatch(uint64) (*Batch, []*types.Transaction, error) GetTransactionBatch(uint64) (*Batch, []*types.Transaction, error)
SyncStatus() (*SyncStatus, error) SyncStatus(Backend) (*SyncStatus, error)
GetL1GasPrice() (*big.Int, error) GetL1GasPrice() (*big.Int, error)
} }
...@@ -270,6 +273,43 @@ func (c *Client) GetLatestEnqueue() (*types.Transaction, error) { ...@@ -270,6 +273,43 @@ func (c *Client) GetLatestEnqueue() (*types.Transaction, error) {
return tx, nil return tx, nil
} }
// GetLatestEnqueueIndex returns the latest `enqueue()` index
func (c *Client) GetLatestEnqueueIndex() (*uint64, error) {
tx, err := c.GetLatestEnqueue()
if err != nil {
return nil, err
}
index := tx.GetMeta().QueueIndex
if index == nil {
return nil, errors.New("Latest queue index is nil")
}
return index, nil
}
// GetLatestTransactionIndex returns the latest CTC index that has been batch
// submitted or not, depending on the backend
func (c *Client) GetLatestTransactionIndex(backend Backend) (*uint64, error) {
tx, err := c.GetLatestTransaction(backend)
if err != nil {
return nil, err
}
index := tx.GetMeta().Index
if index == nil {
return nil, errors.New("Latest index is nil")
}
return index, nil
}
// GetLatestTransactionBatchIndex returns the latest transaction batch index
func (c *Client) GetLatestTransactionBatchIndex() (*uint64, error) {
batch, _, err := c.GetLatestTransactionBatch()
if err != nil {
return nil, err
}
index := batch.Index
return &index, nil
}
// batchedTransactionToTransaction converts a transaction into a // batchedTransactionToTransaction converts a transaction into a
// types.Transaction that can be consumed by the SyncService // types.Transaction that can be consumed by the SyncService
func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signer) (*types.Transaction, error) { func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signer) (*types.Transaction, error) {
...@@ -364,12 +404,15 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe ...@@ -364,12 +404,15 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe
} }
// GetTransaction will get a transaction by Canonical Transaction Chain index // GetTransaction will get a transaction by Canonical Transaction Chain index
func (c *Client) GetTransaction(index uint64) (*types.Transaction, error) { func (c *Client) GetTransaction(index uint64, backend Backend) (*types.Transaction, error) {
str := strconv.FormatUint(index, 10) str := strconv.FormatUint(index, 10)
response, err := c.client.R(). response, err := c.client.R().
SetPathParams(map[string]string{ SetPathParams(map[string]string{
"index": str, "index": str,
}). }).
SetQueryParams(map[string]string{
"backend": backend.String(),
}).
SetResult(&TransactionResponse{}). SetResult(&TransactionResponse{}).
Get("/transaction/index/{index}") Get("/transaction/index/{index}")
...@@ -385,9 +428,12 @@ func (c *Client) GetTransaction(index uint64) (*types.Transaction, error) { ...@@ -385,9 +428,12 @@ func (c *Client) GetTransaction(index uint64) (*types.Transaction, error) {
// GetLatestTransaction will get the latest transaction, meaning the transaction // GetLatestTransaction will get the latest transaction, meaning the transaction
// with the greatest Canonical Transaction Chain index // with the greatest Canonical Transaction Chain index
func (c *Client) GetLatestTransaction() (*types.Transaction, error) { func (c *Client) GetLatestTransaction(backend Backend) (*types.Transaction, error) {
response, err := c.client.R(). response, err := c.client.R().
SetResult(&TransactionResponse{}). SetResult(&TransactionResponse{}).
SetQueryParams(map[string]string{
"backend": backend.String(),
}).
Get("/transaction/latest") Get("/transaction/latest")
if err != nil { if err != nil {
...@@ -477,9 +523,12 @@ func (c *Client) GetLastConfirmedEnqueue() (*types.Transaction, error) { ...@@ -477,9 +523,12 @@ func (c *Client) GetLastConfirmedEnqueue() (*types.Transaction, error) {
} }
// SyncStatus will query the remote server to determine if it is still syncing // SyncStatus will query the remote server to determine if it is still syncing
func (c *Client) SyncStatus() (*SyncStatus, error) { func (c *Client) SyncStatus(backend Backend) (*SyncStatus, error) {
response, err := c.client.R(). response, err := c.client.R().
SetResult(&SyncStatus{}). SetResult(&SyncStatus{}).
SetQueryParams(map[string]string{
"backend": backend.String(),
}).
Get("/eth/syncing") Get("/eth/syncing")
if err != nil { if err != nil {
...@@ -533,8 +582,8 @@ func (c *Client) GetTransactionBatch(index uint64) (*Batch, []*types.Transaction ...@@ -533,8 +582,8 @@ func (c *Client) GetTransactionBatch(index uint64) (*Batch, []*types.Transaction
// parseTransactionBatchResponse will turn a TransactionBatchResponse into a // parseTransactionBatchResponse will turn a TransactionBatchResponse into a
// Batch and its corresponding types.Transactions // Batch and its corresponding types.Transactions
func parseTransactionBatchResponse(txBatch *TransactionBatchResponse, signer *types.EIP155Signer) (*Batch, []*types.Transaction, error) { func parseTransactionBatchResponse(txBatch *TransactionBatchResponse, signer *types.EIP155Signer) (*Batch, []*types.Transaction, error) {
if txBatch == nil { if txBatch == nil || txBatch.Batch == nil {
return nil, nil, nil return nil, nil, errElementNotFound
} }
batch := txBatch.Batch batch := txBatch.Batch
txs := make([]*types.Transaction, len(txBatch.Transactions)) txs := make([]*types.Transaction, len(txBatch.Transactions))
......
...@@ -40,6 +40,8 @@ type Config struct { ...@@ -40,6 +40,8 @@ type Config struct {
DataPrice *big.Int DataPrice *big.Int
// The gas price to use for L2 congestion costs // The gas price to use for L2 congestion costs
ExecutionPrice *big.Int ExecutionPrice *big.Int
// Represents the source of the transactions that is being synced
Backend Backend
// Only accept transactions with fees // Only accept transactions with fees
EnforceFees bool EnforceFees bool
} }
This diff is collapsed.
This diff is collapsed.
...@@ -2,11 +2,60 @@ package rollup ...@@ -2,11 +2,60 @@ package rollup
import ( import (
"bytes" "bytes"
"fmt"
"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"
) )
// OVMContext represents the blocknumber and timestamp
// that exist during L2 execution
type OVMContext struct {
blockNumber uint64
timestamp uint64
}
// Backend represents the type of transactions that are being synced.
// The different types have different security models.
type Backend uint
// String implements the Stringer interface
func (s Backend) String() string {
switch s {
case BackendL1:
return "l1"
case BackendL2:
return "l2"
default:
return ""
}
}
// NewBackend creates a Backend from a human readable string
func NewBackend(typ string) (Backend, error) {
switch typ {
case "l1":
return BackendL1, nil
case "l2":
return BackendL2, nil
default:
return 0, fmt.Errorf("Unknown Backend: %s", typ)
}
}
const (
// BackendL1 Backend involves syncing transactions that have been batched to
// Layer One. Once the transactions have been batched to L1, they cannot be
// removed assuming that they are not reorganized out of the chain.
BackendL1 Backend = iota
// BackendL2 Backend involves syncing transactions from the sequencer,
// meaning that the transactions may have not been batched to Layer One yet.
// This gives higher latency access to the sequencer data but no guarantees
// around the transactions as they have not been submitted via a batch to
// L1.
BackendL2
)
func isCtcTxEqual(a, b *types.Transaction) bool { func isCtcTxEqual(a, b *types.Transaction) bool {
if a.To() == nil && b.To() != nil { if a.To() == nil && b.To() != nil {
if !bytes.Equal(b.To().Bytes(), common.Address{}.Bytes()) { if !bytes.Equal(b.To().Bytes(), common.Address{}.Bytes()) {
......
...@@ -20,6 +20,7 @@ CACHE=1024 ...@@ -20,6 +20,7 @@ CACHE=1024
RPC_PORT=8545 RPC_PORT=8545
WS_PORT=8546 WS_PORT=8546
VERBOSITY=3 VERBOSITY=3
ROLLUP_BACKEND=l1
USAGE=" USAGE="
Start the Sequencer or Verifier with most configuration pre-set. Start the Sequencer or Verifier with most configuration pre-set.
...@@ -189,6 +190,15 @@ while (( "$#" )); do ...@@ -189,6 +190,15 @@ while (( "$#" )); do
exit 1 exit 1
fi fi
;; ;;
--rollup.backend)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ROLLUP_BACKEND="$2"
shift 2
else
echo "Error: Argument for $1 is missing" >&2
exit 1
fi
;;
--cache) --cache)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
CACHE="$2" CACHE="$2"
...@@ -227,6 +237,7 @@ cmd="$cmd --eth1.l1ethgatewayaddress $ETH1_L1_GATEWAY_ADDRESS" ...@@ -227,6 +237,7 @@ cmd="$cmd --eth1.l1ethgatewayaddress $ETH1_L1_GATEWAY_ADDRESS"
cmd="$cmd --rollup.clienthttp $ROLLUP_CLIENT_HTTP" cmd="$cmd --rollup.clienthttp $ROLLUP_CLIENT_HTTP"
cmd="$cmd --rollup.pollinterval $ROLLUP_POLL_INTERVAL" cmd="$cmd --rollup.pollinterval $ROLLUP_POLL_INTERVAL"
cmd="$cmd --rollup.timestamprefresh $ROLLUP_TIMESTAMP_REFRESH" cmd="$cmd --rollup.timestamprefresh $ROLLUP_TIMESTAMP_REFRESH"
cmd="$cmd --rollup.backend $ROLLUP_BACKEND"
cmd="$cmd --cache $CACHE" cmd="$cmd --cache $CACHE"
cmd="$cmd --rpc" cmd="$cmd --rpc"
cmd="$cmd --dev" cmd="$cmd --dev"
......
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