Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
bbb46f4c
Unverified
Commit
bbb46f4c
authored
Jan 21, 2023
by
mergify[bot]
Committed by
GitHub
Jan 21, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4684 from ethereum-optimism/jg/cleanup_proposer
op-proposer: Cleanup
parents
6e1f4db2
03c618cf
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
392 additions
and
745 deletions
+392
-745
l2_proposer.go
op-e2e/actions/l2_proposer.go
+35
-21
migration_test.go
op-e2e/migration_test.go
+2
-2
setup.go
op-e2e/setup.go
+2
-2
l1client.go
op-proposer/mock/l1client.go
+0
-164
config.go
op-proposer/proposer/config.go
+30
-9
driver.go
op-proposer/proposer/driver.go
+0
-247
interface.go
op-proposer/proposer/interface.go
+0
-36
l2_output_submitter.go
op-proposer/proposer/l2_output_submitter.go
+276
-90
service.go
op-proposer/proposer/service.go
+0
-174
utils.go
op-proposer/proposer/utils.go
+47
-0
No files found.
op-e2e/actions/l2_proposer.go
View file @
bbb46f4c
...
@@ -4,6 +4,7 @@ import (
...
@@ -4,6 +4,7 @@ import (
"context"
"context"
"crypto/ecdsa"
"crypto/ecdsa"
"math/big"
"math/big"
"time"
"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"
...
@@ -14,6 +15,7 @@ import (
...
@@ -14,6 +15,7 @@ import (
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-proposer/proposer"
"github.com/ethereum-optimism/optimism/op-proposer/proposer"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
opcrypto
"github.com/ethereum-optimism/optimism/op-service/crypto"
opcrypto
"github.com/ethereum-optimism/optimism/op-service/crypto"
)
)
...
@@ -26,28 +28,41 @@ type ProposerCfg struct {
...
@@ -26,28 +28,41 @@ type ProposerCfg struct {
type
L2Proposer
struct
{
type
L2Proposer
struct
{
log
log
.
Logger
log
log
.
Logger
l1
*
ethclient
.
Client
l1
*
ethclient
.
Client
driver
*
proposer
.
Driv
er
driver
*
proposer
.
L2OutputSubmitt
er
address
common
.
Address
address
common
.
Address
lastTx
common
.
Hash
lastTx
common
.
Hash
}
}
func
NewL2Proposer
(
t
Testing
,
log
log
.
Logger
,
cfg
*
ProposerCfg
,
l1
*
ethclient
.
Client
,
rollupCl
*
sources
.
RollupClient
)
*
L2Proposer
{
func
NewL2Proposer
(
t
Testing
,
log
log
.
Logger
,
cfg
*
ProposerCfg
,
l1
*
ethclient
.
Client
,
rollupCl
*
sources
.
RollupClient
)
*
L2Proposer
{
chainID
,
err
:=
l1
.
ChainID
(
t
.
Ctx
())
signer
:=
func
(
chainID
*
big
.
Int
)
proposer
.
SignerFn
{
require
.
NoError
(
t
,
err
)
s
:=
opcrypto
.
PrivateKeySignerFn
(
cfg
.
ProposerKey
,
chainID
)
signer
:=
opcrypto
.
PrivateKeySignerFn
(
cfg
.
ProposerKey
,
chainID
)
return
func
(
_
context
.
Context
,
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
dr
,
err
:=
proposer
.
NewDriver
(
proposer
.
DriverConfig
{
return
s
(
addr
,
tx
)
Log
:
log
,
}
Name
:
"proposer"
,
}
from
:=
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
)
proposerCfg
:=
proposer
.
Config
{
L2OutputOracleAddr
:
cfg
.
OutputOracleAddr
,
PollInterval
:
time
.
Second
,
TxManagerConfig
:
txmgr
.
Config
{
Log
:
log
,
Name
:
"action-proposer"
,
ResubmissionTimeout
:
5
*
time
.
Second
,
ReceiptQueryInterval
:
time
.
Second
,
NumConfirmations
:
1
,
SafeAbortNonceTooLowCount
:
4
,
},
L1Client
:
l1
,
L1Client
:
l1
,
RollupClient
:
rollupCl
,
RollupClient
:
rollupCl
,
AllowNonFinalized
:
cfg
.
AllowNonFinalized
,
AllowNonFinalized
:
cfg
.
AllowNonFinalized
,
L2OOAddr
:
cfg
.
OutputOracleAddr
,
From
:
from
,
From
:
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
),
SignerFnFactory
:
signer
,
SignerFn
:
func
(
_
context
.
Context
,
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
}
return
signer
(
addr
,
tx
)
},
dr
,
err
:=
proposer
.
NewL2OutputSubmitterWithSigner
(
proposerCfg
,
log
)
})
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
return
&
L2Proposer
{
return
&
L2Proposer
{
log
:
log
,
log
:
log
,
l1
:
l1
,
l1
:
l1
,
...
@@ -57,25 +72,24 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
...
@@ -57,25 +72,24 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
}
}
func
(
p
*
L2Proposer
)
CanPropose
(
t
Testing
)
bool
{
func
(
p
*
L2Proposer
)
CanPropose
(
t
Testing
)
bool
{
start
,
end
,
err
:=
p
.
driver
.
GetBlockRange
(
t
.
Ctx
())
_
,
shouldPropose
,
err
:=
p
.
driver
.
FetchNextOutputInfo
(
t
.
Ctx
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
return
s
tart
.
Cmp
(
end
)
<
0
return
s
houldPropose
}
}
func
(
p
*
L2Proposer
)
ActMakeProposalTx
(
t
Testing
)
{
func
(
p
*
L2Proposer
)
ActMakeProposalTx
(
t
Testing
)
{
start
,
end
,
err
:=
p
.
driver
.
GetBlockRange
(
t
.
Ctx
())
output
,
shouldPropose
,
err
:=
p
.
driver
.
FetchNextOutputInfo
(
t
.
Ctx
())
require
.
NoError
(
t
,
err
)
if
!
shouldPropose
{
if
start
.
Cmp
(
end
)
==
0
{
return
t
.
InvalidAction
(
"nothing to propose, block range starts and ends at %s"
,
start
.
String
())
}
}
nonce
,
err
:=
p
.
l1
.
PendingNonceAt
(
t
.
Ctx
(),
p
.
address
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
tx
,
err
:=
p
.
driver
.
Cr
aftTx
(
t
.
Ctx
(),
start
,
end
,
new
(
big
.
Int
)
.
SetUint64
(
nonce
)
)
tx
,
err
:=
p
.
driver
.
Cr
eateProposalTx
(
t
.
Ctx
(),
output
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
err
=
p
.
driver
.
SendTransaction
(
t
.
Ctx
(),
tx
)
err
=
p
.
driver
.
SendTransaction
(
t
.
Ctx
(),
tx
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
p
.
lastTx
=
tx
.
Hash
()
p
.
lastTx
=
tx
.
Hash
()
}
}
...
...
op-e2e/migration_test.go
View file @
bbb46f4c
...
@@ -342,7 +342,7 @@ func TestMigration(t *testing.T) {
...
@@ -342,7 +342,7 @@ func TestMigration(t *testing.T) {
batcher
.
Stop
()
batcher
.
Stop
()
})
})
proposer
,
err
:=
l2os
.
NewL2OutputSubmitter
(
l2os
.
Config
{
proposer
,
err
:=
l2os
.
NewL2OutputSubmitter
(
l2os
.
C
LIC
onfig
{
L1EthRpc
:
forkedL1URL
,
L1EthRpc
:
forkedL1URL
,
RollupRpc
:
rollupNode
.
HTTPEndpoint
(),
RollupRpc
:
rollupNode
.
HTTPEndpoint
(),
L2OOAddress
:
l2OS
.
Address
.
String
(),
L2OOAddress
:
l2OS
.
Address
.
String
(),
...
@@ -356,7 +356,7 @@ func TestMigration(t *testing.T) {
...
@@ -356,7 +356,7 @@ func TestMigration(t *testing.T) {
Format
:
"text"
,
Format
:
"text"
,
},
},
PrivateKey
:
hexPriv
(
secrets
.
Proposer
),
PrivateKey
:
hexPriv
(
secrets
.
Proposer
),
},
""
,
lgr
.
New
(
"module"
,
"proposer"
))
},
lgr
.
New
(
"module"
,
"proposer"
))
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
t
.
Cleanup
(
func
()
{
t
.
Cleanup
(
func
()
{
proposer
.
Stop
()
proposer
.
Stop
()
...
...
op-e2e/setup.go
View file @
bbb46f4c
...
@@ -498,7 +498,7 @@ func (cfg SystemConfig) Start() (*System, error) {
...
@@ -498,7 +498,7 @@ func (cfg SystemConfig) Start() (*System, error) {
}
}
// L2Output Submitter
// L2Output Submitter
sys
.
L2OutputSubmitter
,
err
=
l2os
.
NewL2OutputSubmitter
(
l2os
.
Config
{
sys
.
L2OutputSubmitter
,
err
=
l2os
.
NewL2OutputSubmitter
(
l2os
.
C
LIC
onfig
{
L1EthRpc
:
sys
.
Nodes
[
"l1"
]
.
WSEndpoint
(),
L1EthRpc
:
sys
.
Nodes
[
"l1"
]
.
WSEndpoint
(),
RollupRpc
:
sys
.
RollupNodes
[
"sequencer"
]
.
HTTPEndpoint
(),
RollupRpc
:
sys
.
RollupNodes
[
"sequencer"
]
.
HTTPEndpoint
(),
L2OOAddress
:
predeploys
.
DevL2OutputOracleAddr
.
String
(),
L2OOAddress
:
predeploys
.
DevL2OutputOracleAddr
.
String
(),
...
@@ -512,7 +512,7 @@ func (cfg SystemConfig) Start() (*System, error) {
...
@@ -512,7 +512,7 @@ func (cfg SystemConfig) Start() (*System, error) {
Format
:
"text"
,
Format
:
"text"
,
},
},
PrivateKey
:
hexPriv
(
cfg
.
Secrets
.
Proposer
),
PrivateKey
:
hexPriv
(
cfg
.
Secrets
.
Proposer
),
},
""
,
sys
.
cfg
.
Loggers
[
"proposer"
])
},
sys
.
cfg
.
Loggers
[
"proposer"
])
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"unable to setup l2 output submitter: %w"
,
err
)
return
nil
,
fmt
.
Errorf
(
"unable to setup l2 output submitter: %w"
,
err
)
}
}
...
...
op-proposer/mock/l1client.go
deleted
100644 → 0
View file @
6e1f4db2
package
mock
import
(
"context"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// L1ClientConfig houses the internal methods that are executed by the mock
// L1Client. Any members left as nil will panic on execution.
type
L1ClientConfig
struct
{
// BlockNumber returns the most recent block number.
BlockNumber
func
(
context
.
Context
)
(
uint64
,
error
)
// HeaderByNumber returns a block header from the current canonical chain.
// If number is nil, the latest known header is returned.
HeaderByNumber
func
(
context
.
Context
,
*
big
.
Int
)
(
*
types
.
Header
,
error
)
// NonceAt returns the account nonce of the given account. The block number
// can be nil, in which case the nonce is taken from the latest known block.
NonceAt
func
(
context
.
Context
,
common
.
Address
,
*
big
.
Int
)
(
uint64
,
error
)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
//
// If the transaction was a contract creation use the TransactionReceipt
// method to get the contract address after the transaction has been mined.
SendTransaction
func
(
context
.
Context
,
*
types
.
Transaction
)
error
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559
// to allow a timely execution of a transaction.
SuggestGasTipCap
func
(
context
.
Context
)
(
*
big
.
Int
,
error
)
// TransactionReceipt returns the receipt of a transaction by transaction
// hash. Note that the receipt is not available for pending transactions.
TransactionReceipt
func
(
context
.
Context
,
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
}
// L1Client represents a mock L1Client.
type
L1Client
struct
{
cfg
L1ClientConfig
mu
sync
.
RWMutex
}
// NewL1Client returns a new L1Client using the mocked methods in the
// L1ClientConfig.
func
NewL1Client
(
cfg
L1ClientConfig
)
*
L1Client
{
return
&
L1Client
{
cfg
:
cfg
,
}
}
// BlockNumber returns the most recent block number.
func
(
c
*
L1Client
)
BlockNumber
(
ctx
context
.
Context
)
(
uint64
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
BlockNumber
(
ctx
)
}
// HeaderByNumber returns a block header from the current canonical chain. If
// number is nil, the latest known header is returned.
func
(
c
*
L1Client
)
HeaderByNumber
(
ctx
context
.
Context
,
blockNumber
*
big
.
Int
)
(
*
types
.
Header
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
HeaderByNumber
(
ctx
,
blockNumber
)
}
// NonceAt executes the mock NonceAt method.
func
(
c
*
L1Client
)
NonceAt
(
ctx
context
.
Context
,
addr
common
.
Address
,
blockNumber
*
big
.
Int
)
(
uint64
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
NonceAt
(
ctx
,
addr
,
blockNumber
)
}
// SendTransaction executes the mock SendTransaction method.
func
(
c
*
L1Client
)
SendTransaction
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
SendTransaction
(
ctx
,
tx
)
}
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to
// allow a timely execution of a transaction.
func
(
c
*
L1Client
)
SuggestGasTipCap
(
ctx
context
.
Context
)
(
*
big
.
Int
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
SuggestGasTipCap
(
ctx
)
}
// TransactionReceipt executes the mock TransactionReceipt method.
func
(
c
*
L1Client
)
TransactionReceipt
(
ctx
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
TransactionReceipt
(
ctx
,
txHash
)
}
// SetBlockNumberFunc overwrites the mock BlockNumber method.
func
(
c
*
L1Client
)
SetBlockNumberFunc
(
f
func
(
context
.
Context
)
(
uint64
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
BlockNumber
=
f
}
// SetHeaderByNumberFunc overwrites the mock HeaderByNumber method.
func
(
c
*
L1Client
)
SetHeaderByNumberFunc
(
f
func
(
ctx
context
.
Context
,
blockNumber
*
big
.
Int
)
(
*
types
.
Header
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
HeaderByNumber
=
f
}
// SetNonceAtFunc overwrites the mock NonceAt method.
func
(
c
*
L1Client
)
SetNonceAtFunc
(
f
func
(
context
.
Context
,
common
.
Address
,
*
big
.
Int
)
(
uint64
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
NonceAt
=
f
}
// SetSendTransactionFunc overwrites the mock SendTransaction method.
func
(
c
*
L1Client
)
SetSendTransactionFunc
(
f
func
(
context
.
Context
,
*
types
.
Transaction
)
error
)
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
SendTransaction
=
f
}
// SetSuggestGasTipCapFunc overwrites themock SuggestGasTipCap method.
func
(
c
*
L1Client
)
SetSuggestGasTipCapFunc
(
f
func
(
context
.
Context
)
(
*
big
.
Int
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
SuggestGasTipCap
=
f
}
// SetTransactionReceiptFunc overwrites the mock TransactionReceipt method.
func
(
c
*
L1Client
)
SetTransactionReceiptFunc
(
f
func
(
context
.
Context
,
common
.
Hash
)
(
*
types
.
Receipt
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
TransactionReceipt
=
f
}
op-proposer/proposer/config.go
View file @
bbb46f4c
...
@@ -3,16 +3,36 @@ package proposer
...
@@ -3,16 +3,36 @@ package proposer
import
(
import
(
"time"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/urfave/cli"
"github.com/urfave/cli"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-proposer/flags"
"github.com/ethereum-optimism/optimism/op-proposer/flags"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
oplog
"github.com/ethereum-optimism/optimism/op-service/log"
oplog
"github.com/ethereum-optimism/optimism/op-service/log"
opmetrics
"github.com/ethereum-optimism/optimism/op-service/metrics"
opmetrics
"github.com/ethereum-optimism/optimism/op-service/metrics"
oppprof
"github.com/ethereum-optimism/optimism/op-service/pprof"
oppprof
"github.com/ethereum-optimism/optimism/op-service/pprof"
oprpc
"github.com/ethereum-optimism/optimism/op-service/rpc"
oprpc
"github.com/ethereum-optimism/optimism/op-service/rpc"
)
)
// Config contains the well typed fields that are used to initialize the output submitter.
// It is intended for programmatic use.
type
Config
struct
{
type
Config
struct
{
L2OutputOracleAddr
common
.
Address
PollInterval
time
.
Duration
TxManagerConfig
txmgr
.
Config
L1Client
*
ethclient
.
Client
RollupClient
*
sources
.
RollupClient
AllowNonFinalized
bool
From
common
.
Address
SignerFnFactory
SignerFactory
}
// CLIConfig is a well typed config that is parsed from the CLI params.
// This also contains config options for auxiliary services.
// It is transformed into a `Config` before the L2 output submitter is started.
type
CLIConfig
struct
{
/* Required Params */
/* Required Params */
// L1EthRpc is the HTTP provider URL for L1.
// L1EthRpc is the HTTP provider URL for L1.
...
@@ -68,7 +88,7 @@ type Config struct {
...
@@ -68,7 +88,7 @@ type Config struct {
PprofConfig
oppprof
.
CLIConfig
PprofConfig
oppprof
.
CLIConfig
}
}
func
(
c
Config
)
Check
()
error
{
func
(
c
C
LIC
onfig
)
Check
()
error
{
if
err
:=
c
.
RPCConfig
.
Check
();
err
!=
nil
{
if
err
:=
c
.
RPCConfig
.
Check
();
err
!=
nil
{
return
err
return
err
}
}
...
@@ -85,9 +105,9 @@ func (c Config) Check() error {
...
@@ -85,9 +105,9 @@ func (c Config) Check() error {
}
}
// NewConfig parses the Config from the provided flags or environment variables.
// NewConfig parses the Config from the provided flags or environment variables.
func
NewConfig
(
ctx
*
cli
.
Context
)
Config
{
func
NewConfig
(
ctx
*
cli
.
Context
)
C
LIC
onfig
{
return
Config
{
return
C
LIC
onfig
{
/
* Required Flags */
/
/ Required Flags
L1EthRpc
:
ctx
.
GlobalString
(
flags
.
L1EthRpcFlag
.
Name
),
L1EthRpc
:
ctx
.
GlobalString
(
flags
.
L1EthRpcFlag
.
Name
),
RollupRpc
:
ctx
.
GlobalString
(
flags
.
RollupRpcFlag
.
Name
),
RollupRpc
:
ctx
.
GlobalString
(
flags
.
RollupRpcFlag
.
Name
),
L2OOAddress
:
ctx
.
GlobalString
(
flags
.
L2OOAddressFlag
.
Name
),
L2OOAddress
:
ctx
.
GlobalString
(
flags
.
L2OOAddressFlag
.
Name
),
...
@@ -98,10 +118,11 @@ func NewConfig(ctx *cli.Context) Config {
...
@@ -98,10 +118,11 @@ func NewConfig(ctx *cli.Context) Config {
Mnemonic
:
ctx
.
GlobalString
(
flags
.
MnemonicFlag
.
Name
),
Mnemonic
:
ctx
.
GlobalString
(
flags
.
MnemonicFlag
.
Name
),
L2OutputHDPath
:
ctx
.
GlobalString
(
flags
.
L2OutputHDPathFlag
.
Name
),
L2OutputHDPath
:
ctx
.
GlobalString
(
flags
.
L2OutputHDPathFlag
.
Name
),
PrivateKey
:
ctx
.
GlobalString
(
flags
.
PrivateKeyFlag
.
Name
),
PrivateKey
:
ctx
.
GlobalString
(
flags
.
PrivateKeyFlag
.
Name
),
AllowNonFinalized
:
ctx
.
GlobalBool
(
flags
.
AllowNonFinalizedFlag
.
Name
),
// Optional Flags
RPCConfig
:
oprpc
.
ReadCLIConfig
(
ctx
),
AllowNonFinalized
:
ctx
.
GlobalBool
(
flags
.
AllowNonFinalizedFlag
.
Name
),
LogConfig
:
oplog
.
ReadCLIConfig
(
ctx
),
RPCConfig
:
oprpc
.
ReadCLIConfig
(
ctx
),
MetricsConfig
:
opmetrics
.
ReadCLIConfig
(
ctx
),
LogConfig
:
oplog
.
ReadCLIConfig
(
ctx
),
PprofConfig
:
oppprof
.
ReadCLIConfig
(
ctx
),
MetricsConfig
:
opmetrics
.
ReadCLIConfig
(
ctx
),
PprofConfig
:
oppprof
.
ReadCLIConfig
(
ctx
),
}
}
}
}
op-proposer/proposer/driver.go
deleted
100644 → 0
View file @
6e1f4db2
package
proposer
import
(
"context"
"fmt"
"math/big"
"strings"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/eth"
)
var
bigOne
=
big
.
NewInt
(
1
)
var
supportedL2OutputVersion
=
eth
.
Bytes32
{}
type
SignerFn
func
(
context
.
Context
,
common
.
Address
,
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
type
DriverConfig
struct
{
Log
log
.
Logger
Name
string
// L1Client is used to submit transactions to
L1Client
*
ethclient
.
Client
// RollupClient is used to retrieve output roots from
RollupClient
*
sources
.
RollupClient
// AllowNonFinalized enables the proposal of safe, but non-finalized L2 blocks.
// The L1 block-hash embedded in the proposal TX is checked and should ensure the proposal
// is never valid on an alternative L1 chain that would produce different L2 data.
// This option is not necessary when higher proposal latency is acceptable and L1 is healthy.
AllowNonFinalized
bool
// L2OOAddr is the L1 contract address of the L2 Output Oracle.
L2OOAddr
common
.
Address
// From is the address to send transactions from
From
common
.
Address
// SignerFn is the function used to sign transactions
SignerFn
SignerFn
}
type
Driver
struct
{
cfg
DriverConfig
l2ooContract
*
bindings
.
L2OutputOracle
rawL2ooContract
*
bind
.
BoundContract
walletAddr
common
.
Address
l
log
.
Logger
}
func
NewDriver
(
cfg
DriverConfig
)
(
*
Driver
,
error
)
{
l2ooContract
,
err
:=
bindings
.
NewL2OutputOracle
(
cfg
.
L2OOAddr
,
cfg
.
L1Client
)
if
err
!=
nil
{
return
nil
,
err
}
parsed
,
err
:=
abi
.
JSON
(
strings
.
NewReader
(
bindings
.
L2OutputOracleMetaData
.
ABI
,
))
if
err
!=
nil
{
return
nil
,
err
}
rawL2ooContract
:=
bind
.
NewBoundContract
(
cfg
.
L2OOAddr
,
parsed
,
cfg
.
L1Client
,
cfg
.
L1Client
,
cfg
.
L1Client
,
)
cfg
.
Log
.
Info
(
"Configured driver"
,
"wallet"
,
cfg
.
From
,
"l2-output-contract"
,
cfg
.
L2OOAddr
)
return
&
Driver
{
cfg
:
cfg
,
l2ooContract
:
l2ooContract
,
rawL2ooContract
:
rawL2ooContract
,
walletAddr
:
cfg
.
From
,
l
:
cfg
.
Log
,
},
nil
}
// Name is an identifier used to prefix logs for a particular service.
func
(
d
*
Driver
)
Name
()
string
{
return
d
.
cfg
.
Name
}
// WalletAddr is the wallet address used to pay for transaction fees.
func
(
d
*
Driver
)
WalletAddr
()
common
.
Address
{
return
d
.
walletAddr
}
// GetBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed.
func
(
d
*
Driver
)
GetBlockRange
(
ctx
context
.
Context
)
(
*
big
.
Int
,
*
big
.
Int
,
error
)
{
name
:=
d
.
cfg
.
Name
callOpts
:=
&
bind
.
CallOpts
{
Pending
:
false
,
Context
:
ctx
,
}
// Determine the last committed L2 Block Number
start
,
err
:=
d
.
l2ooContract
.
LatestBlockNumber
(
callOpts
)
if
err
!=
nil
{
d
.
l
.
Error
(
name
+
" unable to get latest block number"
,
"err"
,
err
)
return
nil
,
nil
,
err
}
start
.
Add
(
start
,
bigOne
)
// Next determine the L2 block that we need to commit
nextBlockNumber
,
err
:=
d
.
l2ooContract
.
NextBlockNumber
(
callOpts
)
if
err
!=
nil
{
d
.
l
.
Error
(
name
+
" unable to get next block number"
,
"err"
,
err
)
return
nil
,
nil
,
err
}
status
,
err
:=
d
.
cfg
.
RollupClient
.
SyncStatus
(
ctx
)
if
err
!=
nil
{
d
.
l
.
Error
(
name
+
" unable to get sync status"
,
"err"
,
err
)
return
nil
,
nil
,
err
}
var
currentBlockNumber
*
big
.
Int
if
d
.
cfg
.
AllowNonFinalized
{
currentBlockNumber
=
new
(
big
.
Int
)
.
SetUint64
(
status
.
SafeL2
.
Number
)
}
else
{
currentBlockNumber
=
new
(
big
.
Int
)
.
SetUint64
(
status
.
FinalizedL2
.
Number
)
}
// If we do not have the new L2 Block number
if
currentBlockNumber
.
Cmp
(
nextBlockNumber
)
<
0
{
d
.
l
.
Info
(
name
+
" submission interval has not elapsed"
,
"currentBlockNumber"
,
currentBlockNumber
,
"nextBlockNumber"
,
nextBlockNumber
)
return
start
,
start
,
nil
}
d
.
l
.
Info
(
name
+
" submission interval has elapsed"
,
"currentBlockNumber"
,
currentBlockNumber
,
"nextBlockNumber"
,
nextBlockNumber
)
// Otherwise the submission interval has elapsed. Transform the next
// expected timestamp into its L2 block number, and add one since end is
// exclusive.
end
:=
new
(
big
.
Int
)
.
Add
(
nextBlockNumber
,
bigOne
)
return
start
,
end
,
nil
}
// CraftTx transforms the L2 blocks between start and end into a transaction
// using the given nonce.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
func
(
d
*
Driver
)
CraftTx
(
ctx
context
.
Context
,
start
,
end
,
nonce
*
big
.
Int
)
(
*
types
.
Transaction
,
error
)
{
name
:=
d
.
cfg
.
Name
d
.
l
.
Info
(
name
+
" crafting checkpoint tx"
,
"start"
,
start
,
"end"
,
end
,
"nonce"
,
nonce
)
// Fetch the final block in the range, as this is the only L2 output we need to submit.
nextCheckpointBlock
:=
new
(
big
.
Int
)
.
Sub
(
end
,
bigOne
)
.
Uint64
()
output
,
err
:=
d
.
cfg
.
RollupClient
.
OutputAtBlock
(
ctx
,
nextCheckpointBlock
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to fetch output at block %d: %w"
,
nextCheckpointBlock
,
err
)
}
if
output
.
Version
!=
supportedL2OutputVersion
{
return
nil
,
fmt
.
Errorf
(
"unsupported l2 output version: %s"
,
output
.
Version
)
}
if
output
.
BlockRef
.
Number
!=
nextCheckpointBlock
{
// sanity check, e.g. in case of bad RPC caching
return
nil
,
fmt
.
Errorf
(
"invalid blockNumber: next blockNumber is %v, blockNumber of block is %v"
,
nextCheckpointBlock
,
output
.
BlockRef
.
Number
)
}
// Always propose if it's part of the Finalized L2 chain. Or if allowed, if it's part of the safe L2 chain.
if
!
(
output
.
BlockRef
.
Number
<=
output
.
Status
.
FinalizedL2
.
Number
||
(
d
.
cfg
.
AllowNonFinalized
&&
output
.
BlockRef
.
Number
<=
output
.
Status
.
SafeL2
.
Number
))
{
d
.
l
.
Debug
(
"not proposing yet, L2 block is not ready for proposal"
,
"l2_proposal"
,
output
.
BlockRef
,
"l2_safe"
,
output
.
Status
.
SafeL2
,
"l2_finalized"
,
output
.
Status
.
FinalizedL2
,
"allow_non_finalized"
,
d
.
cfg
.
AllowNonFinalized
)
return
nil
,
fmt
.
Errorf
(
"output for L2 block %s is still unsafe"
,
output
.
BlockRef
)
}
opts
:=
&
bind
.
TransactOpts
{
From
:
d
.
cfg
.
From
,
Signer
:
func
(
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
d
.
cfg
.
SignerFn
(
ctx
,
addr
,
tx
)
},
Context
:
ctx
,
Nonce
:
nonce
,
NoSend
:
true
,
}
// Note: the CurrentL1 is up to (and incl.) what the safe chain and finalized chain have been derived from,
// and should be a quite recent L1 block (depends on L1 conf distance applied to rollup node).
tx
,
err
:=
d
.
l2ooContract
.
ProposeL2Output
(
opts
,
output
.
OutputRoot
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
BlockRef
.
Number
),
output
.
Status
.
CurrentL1
.
Hash
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
Status
.
CurrentL1
.
Number
))
if
err
!=
nil
{
return
nil
,
err
}
numElements
:=
new
(
big
.
Int
)
.
Sub
(
start
,
end
)
.
Uint64
()
d
.
l
.
Info
(
name
+
" proposal constructed"
,
"start"
,
start
,
"end"
,
end
,
"nonce"
,
nonce
,
"blocks_committed"
,
numElements
,
"tx_hash"
,
tx
.
Hash
(),
"output_version"
,
output
.
Version
,
"output_root"
,
output
.
OutputRoot
,
"output_block"
,
output
.
BlockRef
,
"output_withdrawals_root"
,
output
.
WithdrawalStorageRoot
,
"output_state_root"
,
output
.
StateRoot
,
"current_l1"
,
output
.
Status
.
CurrentL1
,
"safe_l2"
,
output
.
Status
.
SafeL2
,
"finalized_l2"
,
output
.
Status
.
FinalizedL2
,
)
return
tx
,
nil
}
// UpdateGasPrice signs an otherwise identical txn to the one provided but with
// updated gas prices sampled from the existing network conditions.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
func
(
d
*
Driver
)
UpdateGasPrice
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
opts
:=
&
bind
.
TransactOpts
{
From
:
d
.
cfg
.
From
,
Signer
:
func
(
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
d
.
cfg
.
SignerFn
(
ctx
,
addr
,
tx
)
},
Context
:
ctx
,
Nonce
:
new
(
big
.
Int
)
.
SetUint64
(
tx
.
Nonce
()),
NoSend
:
true
,
}
return
d
.
rawL2ooContract
.
RawTransact
(
opts
,
tx
.
Data
())
}
// SendTransaction injects a signed transaction into the pending pool for execution.
func
(
d
*
Driver
)
SendTransaction
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
d
.
l
.
Info
(
d
.
cfg
.
Name
+
" sending transaction"
,
"tx"
,
tx
.
Hash
())
return
d
.
cfg
.
L1Client
.
SendTransaction
(
ctx
,
tx
)
}
op-proposer/proposer/interface.go
deleted
100644 → 0
View file @
6e1f4db2
package
proposer
import
(
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// L1Client is an abstraction over an L1 Ethereum client functionality required
// by the batch submitter.
type
L1Client
interface
{
// HeaderByNumber returns a block header from the current canonical chain.
// If number is nil, the latest known header is returned.
HeaderByNumber
(
context
.
Context
,
*
big
.
Int
)
(
*
types
.
Header
,
error
)
// NonceAt returns the account nonce of the given account. The block number
// can be nil, in which case the nonce is taken from the latest known block.
NonceAt
(
context
.
Context
,
common
.
Address
,
*
big
.
Int
)
(
uint64
,
error
)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
//
// If the transaction was a contract creation use the TransactionReceipt
// method to get the contract address after the transaction has been mined.
SendTransaction
(
context
.
Context
,
*
types
.
Transaction
)
error
// SuggestGasTipCap retrieves the currently suggested gas tip cap after 1559
// to allow a timely execution of a transaction.
SuggestGasTipCap
(
context
.
Context
)
(
*
big
.
Int
,
error
)
// TransactionReceipt returns the receipt of a transaction by transaction
// hash. Note that the receipt is not available for pending transactions.
TransactionReceipt
(
context
.
Context
,
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
}
op-proposer/proposer/l2_output_submitter.go
View file @
bbb46f4c
This diff is collapsed.
Click to expand it.
op-proposer/proposer/service.go
deleted
100644 → 0
View file @
6e1f4db2
package
proposer
import
(
"context"
"math/big"
"sync"
"time"
"github.com/ethereum-optimism/optimism/op-proposer/txmgr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
// DriverInterface is an interface for creating and submitting transactions for a
// specific contract.
type
DriverInterface
interface
{
// Name is an identifier used to prefix logs for a particular service.
Name
()
string
// WalletAddr is the wallet address used to pay for transaction fees.
WalletAddr
()
common
.
Address
// GetBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the
// returned values are identical nothing needs to be processed.
GetBlockRange
(
ctx
context
.
Context
)
(
*
big
.
Int
,
*
big
.
Int
,
error
)
// CraftTx transforms the L2 blocks between start and end into a transaction
// using the given nonce.
//
// NOTE: This method SHOULD NOT publish the resulting transaction.
CraftTx
(
ctx
context
.
Context
,
start
,
end
,
nonce
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
// UpdateGasPrice signs an otherwise identical txn to the one provided but
// with updated gas prices sampled from the existing network conditions.
//
// NOTE: Thie method SHOULD NOT publish the resulting transaction.
UpdateGasPrice
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
,
)
(
*
types
.
Transaction
,
error
)
// SendTransaction injects a signed transaction into the pending pool for
// execution.
SendTransaction
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
}
type
ServiceConfig
struct
{
Log
log
.
Logger
Context
context
.
Context
Driver
DriverInterface
PollInterval
time
.
Duration
L1Client
*
ethclient
.
Client
TxManagerConfig
txmgr
.
Config
}
type
Service
struct
{
cfg
ServiceConfig
txMgr
txmgr
.
TxManager
l
log
.
Logger
ctx
context
.
Context
cancel
func
()
wg
sync
.
WaitGroup
}
func
NewService
(
cfg
ServiceConfig
)
*
Service
{
txMgr
:=
txmgr
.
NewSimpleTxManager
(
cfg
.
Driver
.
Name
(),
cfg
.
TxManagerConfig
,
cfg
.
L1Client
,
)
ctx
,
cancel
:=
context
.
WithCancel
(
cfg
.
Context
)
return
&
Service
{
cfg
:
cfg
,
txMgr
:
txMgr
,
l
:
cfg
.
Log
,
ctx
:
ctx
,
cancel
:
cancel
,
}
}
func
(
s
*
Service
)
Start
()
error
{
s
.
wg
.
Add
(
1
)
go
s
.
eventLoop
()
return
nil
}
func
(
s
*
Service
)
Stop
()
error
{
s
.
cancel
()
s
.
wg
.
Wait
()
return
nil
}
func
(
s
*
Service
)
eventLoop
()
{
defer
s
.
wg
.
Done
()
name
:=
s
.
cfg
.
Driver
.
Name
()
ticker
:=
time
.
NewTicker
(
s
.
cfg
.
PollInterval
)
defer
ticker
.
Stop
()
for
{
select
{
case
<-
ticker
.
C
:
// Determine the range of L2 blocks that the submitter has not
// processed, and needs to take action on.
s
.
l
.
Info
(
name
+
" fetching current block range"
)
start
,
end
,
err
:=
s
.
cfg
.
Driver
.
GetBlockRange
(
s
.
ctx
)
if
err
!=
nil
{
s
.
l
.
Error
(
name
+
" unable to get block range"
,
"err"
,
err
)
continue
}
// No new updates.
if
start
.
Cmp
(
end
)
==
0
{
s
.
l
.
Info
(
name
+
" no updates"
,
"start"
,
start
,
"end"
,
end
)
continue
}
s
.
l
.
Info
(
name
+
" block range"
,
"start"
,
start
,
"end"
,
end
)
// Query for the submitter's current nonce.
nonce64
,
err
:=
s
.
cfg
.
L1Client
.
NonceAt
(
s
.
ctx
,
s
.
cfg
.
Driver
.
WalletAddr
(),
nil
,
)
if
err
!=
nil
{
s
.
l
.
Error
(
name
+
" unable to get current nonce"
,
"err"
,
err
)
continue
}
nonce
:=
new
(
big
.
Int
)
.
SetUint64
(
nonce64
)
tx
,
err
:=
s
.
cfg
.
Driver
.
CraftTx
(
s
.
ctx
,
start
,
end
,
nonce
,
)
if
err
!=
nil
{
s
.
l
.
Error
(
name
+
" unable to craft tx"
,
"err"
,
err
)
continue
}
// Construct the a closure that will update the txn with the current
// gas prices.
updateGasPrice
:=
func
(
ctx
context
.
Context
)
(
*
types
.
Transaction
,
error
)
{
s
.
l
.
Info
(
name
+
" updating batch tx gas price"
,
"start"
,
start
,
"end"
,
end
,
"nonce"
,
nonce
)
return
s
.
cfg
.
Driver
.
UpdateGasPrice
(
ctx
,
tx
)
}
// Wait until one of our submitted transactions confirms. If no
// receipt is received it's likely our gas price was too low.
receipt
,
err
:=
s
.
txMgr
.
Send
(
s
.
ctx
,
updateGasPrice
,
s
.
cfg
.
Driver
.
SendTransaction
,
)
if
err
!=
nil
{
s
.
l
.
Error
(
name
+
" unable to publish tx"
,
"err"
,
err
)
continue
}
// The transaction was successfully submitted.
s
.
l
.
Info
(
name
+
" tx successfully published"
,
"tx_hash"
,
receipt
.
TxHash
)
case
<-
s
.
ctx
.
Done
()
:
s
.
l
.
Info
(
name
+
" service shutting down"
)
return
}
}
}
op-proposer/proposer/utils.go
0 → 100644
View file @
bbb46f4c
package
proposer
import
(
"context"
"fmt"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
)
// dialEthClientWithTimeout attempts to dial the L1 provider using the provided
// URL. If the dial doesn't complete within defaultDialTimeout seconds, this
// method will return an error.
func
dialEthClientWithTimeout
(
ctx
context
.
Context
,
url
string
)
(
*
ethclient
.
Client
,
error
)
{
ctxt
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cancel
()
return
ethclient
.
DialContext
(
ctxt
,
url
)
}
// dialRollupClientWithTimeout attempts to dial the RPC provider using the provided
// URL. If the dial doesn't complete within defaultDialTimeout seconds, this
// method will return an error.
func
dialRollupClientWithTimeout
(
ctx
context
.
Context
,
url
string
)
(
*
sources
.
RollupClient
,
error
)
{
ctxt
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cancel
()
rpcCl
,
err
:=
rpc
.
DialContext
(
ctxt
,
url
)
if
err
!=
nil
{
return
nil
,
err
}
return
sources
.
NewRollupClient
(
client
.
NewBaseRPCClient
(
rpcCl
)),
nil
}
// parseAddress parses an ETH address from a hex string. This method will fail if
// the address is not a valid hexadecimal address.
func
parseAddress
(
address
string
)
(
common
.
Address
,
error
)
{
if
common
.
IsHexAddress
(
address
)
{
return
common
.
HexToAddress
(
address
),
nil
}
return
common
.
Address
{},
fmt
.
Errorf
(
"invalid address: %v"
,
address
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment