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
8ade648e
Commit
8ade648e
authored
Mar 24, 2023
by
Joshua Gutow
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
op-proposer: Use new API
This also adds a test for the proposer tx data creation.
parent
971387d1
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
205 additions
and
101 deletions
+205
-101
l2_proposer.go
op-e2e/actions/l2_proposer.go
+59
-14
random.go
op-node/testutils/random.go
+20
-0
abi_test.go
op-proposer/proposer/abi_test.go
+75
-0
l2_output_submitter.go
op-proposer/proposer/l2_output_submitter.go
+51
-87
No files found.
op-e2e/actions/l2_proposer.go
View file @
8ade648e
...
@@ -6,11 +6,13 @@ import (
...
@@ -6,11 +6,13 @@ import (
"math/big"
"math/big"
"time"
"time"
"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/crypto"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-node/sources"
"github.com/ethereum-optimism/optimism/op-node/sources"
...
@@ -27,11 +29,14 @@ type ProposerCfg struct {
...
@@ -27,11 +29,14 @@ type ProposerCfg struct {
}
}
type
L2Proposer
struct
{
type
L2Proposer
struct
{
log
log
.
Logger
log
log
.
Logger
l1
*
ethclient
.
Client
l1
*
ethclient
.
Client
driver
*
proposer
.
L2OutputSubmitter
driver
*
proposer
.
L2OutputSubmitter
address
common
.
Address
address
common
.
Address
lastTx
common
.
Hash
privKey
*
ecdsa
.
PrivateKey
signer
opcrypto
.
SignerFn
contractAddr
common
.
Address
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
{
...
@@ -66,13 +71,56 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
...
@@ -66,13 +71,56 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
return
&
L2Proposer
{
return
&
L2Proposer
{
log
:
log
,
log
:
log
,
l1
:
l1
,
l1
:
l1
,
driver
:
dr
,
driver
:
dr
,
address
:
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
),
address
:
crypto
.
PubkeyToAddress
(
cfg
.
ProposerKey
.
PublicKey
),
privKey
:
cfg
.
ProposerKey
,
signer
:
proposerCfg
.
TxManagerConfig
.
Signer
,
contractAddr
:
cfg
.
OutputOracleAddr
,
}
}
}
}
// sendTx reimplements creating & sending transactions because we need to do the final send as async in
// the action tests while we do it synchronously in the real system.
func
(
p
*
L2Proposer
)
sendTx
(
t
Testing
,
data
[]
byte
)
{
gasTipCap
:=
big
.
NewInt
(
2
*
params
.
GWei
)
pendingHeader
,
err
:=
p
.
l1
.
HeaderByNumber
(
t
.
Ctx
(),
big
.
NewInt
(
-
1
))
require
.
NoError
(
t
,
err
,
"need l1 pending header for gas price estimation"
)
gasFeeCap
:=
new
(
big
.
Int
)
.
Add
(
gasTipCap
,
new
(
big
.
Int
)
.
Mul
(
pendingHeader
.
BaseFee
,
big
.
NewInt
(
2
)))
chainID
,
err
:=
p
.
l1
.
ChainID
(
t
.
Ctx
())
require
.
NoError
(
t
,
err
)
nonce
,
err
:=
p
.
l1
.
NonceAt
(
t
.
Ctx
(),
p
.
address
,
nil
)
require
.
NoError
(
t
,
err
)
gasLimit
,
err
:=
p
.
l1
.
EstimateGas
(
t
.
Ctx
(),
ethereum
.
CallMsg
{
From
:
p
.
address
,
To
:
&
p
.
contractAddr
,
GasFeeCap
:
gasFeeCap
,
GasTipCap
:
gasTipCap
,
Data
:
data
,
})
require
.
NoError
(
t
,
err
)
rawTx
:=
&
types
.
DynamicFeeTx
{
Nonce
:
nonce
,
To
:
&
p
.
contractAddr
,
Data
:
data
,
GasFeeCap
:
gasFeeCap
,
GasTipCap
:
gasTipCap
,
Gas
:
gasLimit
,
ChainID
:
chainID
,
}
tx
,
err
:=
types
.
SignNewTx
(
p
.
privKey
,
types
.
LatestSignerForChainID
(
chainID
),
rawTx
)
require
.
NoError
(
t
,
err
,
"need to sign tx"
)
err
=
p
.
l1
.
SendTransaction
(
t
.
Ctx
(),
tx
)
require
.
NoError
(
t
,
err
,
"need to send tx"
)
p
.
lastTx
=
tx
.
Hash
()
}
func
(
p
*
L2Proposer
)
CanPropose
(
t
Testing
)
bool
{
func
(
p
*
L2Proposer
)
CanPropose
(
t
Testing
)
bool
{
_
,
shouldPropose
,
err
:=
p
.
driver
.
FetchNextOutputInfo
(
t
.
Ctx
())
_
,
shouldPropose
,
err
:=
p
.
driver
.
FetchNextOutputInfo
(
t
.
Ctx
())
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
...
@@ -86,15 +134,12 @@ func (p *L2Proposer) ActMakeProposalTx(t Testing) {
...
@@ -86,15 +134,12 @@ func (p *L2Proposer) ActMakeProposalTx(t Testing) {
}
}
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
tx
,
err
:=
p
.
driver
.
CreateProposalTx
(
t
.
Ctx
(),
output
)
tx
Data
,
err
:=
p
.
driver
.
ProposeL2OutputTxData
(
output
)
require
.
NoError
(
t
,
err
)
require
.
NoError
(
t
,
err
)
// Note: Use L1 instead of the output submitter's transaction manager because
// Note: Use L1 instead of the output submitter's transaction manager because
// this is non-blocking while the txmgr is blocking & deadlocks the tests
// this is non-blocking while the txmgr is blocking & deadlocks the tests
err
=
p
.
l1
.
SendTransaction
(
t
.
Ctx
(),
tx
)
p
.
sendTx
(
t
,
txData
)
require
.
NoError
(
t
,
err
)
p
.
lastTx
=
tx
.
Hash
()
}
}
func
(
p
*
L2Proposer
)
LastProposalTx
()
common
.
Hash
{
func
(
p
*
L2Proposer
)
LastProposalTx
()
common
.
Hash
{
...
...
op-node/testutils/random.go
View file @
8ade648e
...
@@ -245,3 +245,23 @@ func RandomBlockPrependTxs(rng *rand.Rand, txCount int, ptxs ...*types.Transacti
...
@@ -245,3 +245,23 @@ func RandomBlockPrependTxs(rng *rand.Rand, txCount int, ptxs ...*types.Transacti
}
}
return
block
,
receipts
return
block
,
receipts
}
}
func
RandomOutputResponse
(
rng
*
rand
.
Rand
)
*
eth
.
OutputResponse
{
return
&
eth
.
OutputResponse
{
Version
:
eth
.
Bytes32
(
RandomHash
(
rng
)),
OutputRoot
:
eth
.
Bytes32
(
RandomHash
(
rng
)),
BlockRef
:
RandomL2BlockRef
(
rng
),
WithdrawalStorageRoot
:
RandomHash
(
rng
),
StateRoot
:
RandomHash
(
rng
),
Status
:
&
eth
.
SyncStatus
{
CurrentL1
:
RandomBlockRef
(
rng
),
CurrentL1Finalized
:
RandomBlockRef
(
rng
),
HeadL1
:
RandomBlockRef
(
rng
),
SafeL1
:
RandomBlockRef
(
rng
),
FinalizedL1
:
RandomBlockRef
(
rng
),
UnsafeL2
:
RandomL2BlockRef
(
rng
),
SafeL2
:
RandomL2BlockRef
(
rng
),
FinalizedL2
:
RandomL2BlockRef
(
rng
),
},
}
}
op-proposer/proposer/abi_test.go
0 → 100644
View file @
8ade648e
package
proposer
import
(
"math/big"
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-node/testutils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
// setupL2OutputOracle deploys the L2 Output Oracle contract to a simulated backend
func
setupL2OutputOracle
()
(
common
.
Address
,
*
bind
.
TransactOpts
,
*
backends
.
SimulatedBackend
,
*
bindings
.
L2OutputOracle
,
error
)
{
privateKey
,
err
:=
crypto
.
GenerateKey
()
from
:=
crypto
.
PubkeyToAddress
(
privateKey
.
PublicKey
)
if
err
!=
nil
{
return
common
.
Address
{},
nil
,
nil
,
nil
,
err
}
opts
,
err
:=
bind
.
NewKeyedTransactorWithChainID
(
privateKey
,
big
.
NewInt
(
1337
))
if
err
!=
nil
{
return
common
.
Address
{},
nil
,
nil
,
nil
,
err
}
backend
:=
backends
.
NewSimulatedBackend
(
core
.
GenesisAlloc
{
from
:
{
Balance
:
big
.
NewInt
(
params
.
Ether
)}},
50
_000_000
)
_
,
_
,
contract
,
err
:=
bindings
.
DeployL2OutputOracle
(
opts
,
backend
,
big
.
NewInt
(
10
),
big
.
NewInt
(
2
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
from
,
common
.
Address
{
0xdd
},
big
.
NewInt
(
100
))
if
err
!=
nil
{
return
common
.
Address
{},
nil
,
nil
,
nil
,
err
}
return
from
,
opts
,
backend
,
contract
,
nil
}
// TestManualABIPacking ensure that the manual ABI packing is the same as going through the bound contract.
// We don't use the contract to transact because it does not fit our transaction management scheme, but
// we want to make sure that we don't incorrectly create the transaction data.
func
TestManualABIPacking
(
t
*
testing
.
T
)
{
_
,
opts
,
_
,
contract
,
err
:=
setupL2OutputOracle
()
require
.
NoError
(
t
,
err
)
rng
:=
rand
.
New
(
rand
.
NewSource
(
1234
))
abi
,
err
:=
bindings
.
L2OutputOracleMetaData
.
GetAbi
()
require
.
NoError
(
t
,
err
)
output
:=
testutils
.
RandomOutputResponse
(
rng
)
txData
,
err
:=
proposeL2OutputTxData
(
abi
,
output
)
require
.
NoError
(
t
,
err
)
// set a gas limit to disable gas estimation. The invariantes that the L2OO tries to uphold
// are not maintained in this test.
opts
.
GasLimit
=
100
_000
tx
,
err
:=
contract
.
ProposeL2Output
(
opts
,
output
.
OutputRoot
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
BlockRef
.
Number
),
output
.
Status
.
CurrentL1
.
Hash
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
Status
.
CurrentL1
.
Number
))
require
.
NoError
(
t
,
err
)
require
.
Equal
(
t
,
txData
,
tx
.
Data
())
}
op-proposer/proposer/l2_output_submitter.go
View file @
8ade648e
...
@@ -8,7 +8,6 @@ import (
...
@@ -8,7 +8,6 @@ import (
_
"net/http/pprof"
_
"net/http/pprof"
"os"
"os"
"os/signal"
"os/signal"
"strings"
"sync"
"sync"
"syscall"
"syscall"
"time"
"time"
...
@@ -16,7 +15,6 @@ import (
...
@@ -16,7 +15,6 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi"
"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/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/urfave/cli"
"github.com/urfave/cli"
...
@@ -124,13 +122,14 @@ type L2OutputSubmitter struct {
...
@@ -124,13 +122,14 @@ type L2OutputSubmitter struct {
ctx
context
.
Context
ctx
context
.
Context
cancel
context
.
CancelFunc
cancel
context
.
CancelFunc
//
L1Client is used to submit transactions to
//
l1Client is retained to make it easier to start the metrics balance check
l1Client
*
ethclient
.
Client
l1Client
*
ethclient
.
Client
// RollupClient is used to retrieve output roots from
// RollupClient is used to retrieve output roots from
rollupClient
*
sources
.
RollupClient
rollupClient
*
sources
.
RollupClient
l2ooContract
*
bindings
.
L2OutputOracle
l2ooContract
*
bindings
.
L2OutputOracleCaller
rawL2ooContract
*
bind
.
BoundContract
l2ooContractAddr
common
.
Address
l2ooABI
*
abi
.
ABI
// AllowNonFinalized enables the proposal of safe, but non-finalized L2 blocks.
// 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
// The L1 block-hash embedded in the proposal TX is checked and should ensure the proposal
...
@@ -139,8 +138,6 @@ type L2OutputSubmitter struct {
...
@@ -139,8 +138,6 @@ type L2OutputSubmitter struct {
allowNonFinalized
bool
allowNonFinalized
bool
// From is the address to send transactions from
// From is the address to send transactions from
from
common
.
Address
from
common
.
Address
// SignerFn is the function used to sign transactions
signerFn
opcrypto
.
SignerFn
// How frequently to poll L2 for new finalized outputs
// How frequently to poll L2 for new finalized outputs
pollInterval
time
.
Duration
pollInterval
time
.
Duration
}
}
...
@@ -211,25 +208,26 @@ func NewL2OutputSubmitter(cfg Config, l log.Logger, m metrics.Metricer) (*L2Outp
...
@@ -211,25 +208,26 @@ func NewL2OutputSubmitter(cfg Config, l log.Logger, m metrics.Metricer) (*L2Outp
signer
:=
cfg
.
SignerFnFactory
(
chainID
)
signer
:=
cfg
.
SignerFnFactory
(
chainID
)
cfg
.
TxManagerConfig
.
Signer
=
signer
cfg
.
TxManagerConfig
.
Signer
=
signer
l2ooContract
,
err
:=
bindings
.
NewL2OutputOracle
(
cfg
.
L2OutputOracleAddr
,
cfg
.
L1Client
)
l2ooContract
,
err
:=
bindings
.
NewL2OutputOracle
Caller
(
cfg
.
L2OutputOracleAddr
,
cfg
.
L1Client
)
if
err
!=
nil
{
if
err
!=
nil
{
cancel
()
cancel
()
return
nil
,
err
return
nil
,
err
}
}
version
,
err
:=
l2ooContract
.
Version
(
&
bind
.
CallOpts
{})
cCtx
,
cCancel
=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cCancel
()
version
,
err
:=
l2ooContract
.
Version
(
&
bind
.
CallOpts
{
Context
:
cCtx
})
if
err
!=
nil
{
if
err
!=
nil
{
cancel
()
cancel
()
return
nil
,
err
return
nil
,
err
}
}
log
.
Info
(
"Connected to L2OutputOracle"
,
"address"
,
cfg
.
L2OutputOracleAddr
,
"version"
,
version
)
log
.
Info
(
"Connected to L2OutputOracle"
,
"address"
,
cfg
.
L2OutputOracleAddr
,
"version"
,
version
)
parsed
,
err
:=
abi
.
JSON
(
strings
.
NewReader
(
bindings
.
L2OutputOracleMetaData
.
ABI
)
)
parsed
,
err
:=
bindings
.
L2OutputOracleMetaData
.
GetAbi
(
)
if
err
!=
nil
{
if
err
!=
nil
{
cancel
()
cancel
()
return
nil
,
err
return
nil
,
err
}
}
rawL2ooContract
:=
bind
.
NewBoundContract
(
cfg
.
L2OutputOracleAddr
,
parsed
,
cfg
.
L1Client
,
cfg
.
L1Client
,
cfg
.
L1Client
)
return
&
L2OutputSubmitter
{
return
&
L2OutputSubmitter
{
txMgr
:
txmgr
.
NewSimpleTxManager
(
"proposer"
,
l
,
cfg
.
TxManagerConfig
,
cfg
.
L1Client
),
txMgr
:
txmgr
.
NewSimpleTxManager
(
"proposer"
,
l
,
cfg
.
TxManagerConfig
,
cfg
.
L1Client
),
...
@@ -242,12 +240,12 @@ func NewL2OutputSubmitter(cfg Config, l log.Logger, m metrics.Metricer) (*L2Outp
...
@@ -242,12 +240,12 @@ func NewL2OutputSubmitter(cfg Config, l log.Logger, m metrics.Metricer) (*L2Outp
l1Client
:
cfg
.
L1Client
,
l1Client
:
cfg
.
L1Client
,
rollupClient
:
cfg
.
RollupClient
,
rollupClient
:
cfg
.
RollupClient
,
l2ooContract
:
l2ooContract
,
l2ooContract
:
l2ooContract
,
rawL2ooContract
:
rawL2ooContract
,
l2ooContractAddr
:
cfg
.
L2OutputOracleAddr
,
l2ooABI
:
parsed
,
allowNonFinalized
:
cfg
.
AllowNonFinalized
,
allowNonFinalized
:
cfg
.
AllowNonFinalized
,
from
:
cfg
.
From
,
from
:
cfg
.
From
,
signerFn
:
signer
,
pollInterval
:
cfg
.
PollInterval
,
pollInterval
:
cfg
.
PollInterval
,
},
nil
},
nil
}
}
...
@@ -264,29 +262,14 @@ func (l *L2OutputSubmitter) Stop() {
...
@@ -264,29 +262,14 @@ func (l *L2OutputSubmitter) Stop() {
l
.
wg
.
Wait
()
l
.
wg
.
Wait
()
}
}
// 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
(
l
*
L2OutputSubmitter
)
UpdateGasPrice
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
opts
:=
&
bind
.
TransactOpts
{
From
:
l
.
from
,
Signer
:
func
(
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
l
.
signerFn
(
ctx
,
addr
,
tx
)
},
Context
:
ctx
,
Nonce
:
new
(
big
.
Int
)
.
SetUint64
(
tx
.
Nonce
()),
NoSend
:
true
,
}
return
l
.
rawL2ooContract
.
RawTransact
(
opts
,
tx
.
Data
())
}
// FetchNextOutputInfo gets the block number of the next proposal.
// FetchNextOutputInfo gets the block number of the next proposal.
// It returns: the next block number, if the proposal should be made, error
// It returns: the next block number, if the proposal should be made, error
func
(
l
*
L2OutputSubmitter
)
FetchNextOutputInfo
(
ctx
context
.
Context
)
(
*
eth
.
OutputResponse
,
bool
,
error
)
{
func
(
l
*
L2OutputSubmitter
)
FetchNextOutputInfo
(
ctx
context
.
Context
)
(
*
eth
.
OutputResponse
,
bool
,
error
)
{
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cancel
()
callOpts
:=
&
bind
.
CallOpts
{
callOpts
:=
&
bind
.
CallOpts
{
From
:
l
.
from
,
From
:
l
.
from
,
Context
:
ctx
,
Context
:
c
C
tx
,
}
}
nextCheckpointBlock
,
err
:=
l
.
l2ooContract
.
NextBlockNumber
(
callOpts
)
nextCheckpointBlock
,
err
:=
l
.
l2ooContract
.
NextBlockNumber
(
callOpts
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -294,7 +277,9 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
...
@@ -294,7 +277,9 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
return
nil
,
false
,
err
return
nil
,
false
,
err
}
}
// Fetch the current L2 heads
// Fetch the current L2 heads
status
,
err
:=
l
.
rollupClient
.
SyncStatus
(
ctx
)
cCtx
,
cancel
=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cancel
()
status
,
err
:=
l
.
rollupClient
.
SyncStatus
(
cCtx
)
if
err
!=
nil
{
if
err
!=
nil
{
l
.
log
.
Error
(
"proposer unable to get sync status"
,
"err"
,
err
)
l
.
log
.
Error
(
"proposer unable to get sync status"
,
"err"
,
err
)
return
nil
,
false
,
err
return
nil
,
false
,
err
...
@@ -312,17 +297,23 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
...
@@ -312,17 +297,23 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
return
nil
,
false
,
nil
return
nil
,
false
,
nil
}
}
output
,
err
:=
l
.
rollupClient
.
OutputAtBlock
(
ctx
,
nextCheckpointBlock
.
Uint64
())
return
l
.
fetchOuput
(
ctx
,
nextCheckpointBlock
)
}
func
(
l
*
L2OutputSubmitter
)
fetchOuput
(
ctx
context
.
Context
,
block
*
big
.
Int
)
(
*
eth
.
OutputResponse
,
bool
,
error
)
{
ctx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
defaultDialTimeout
)
defer
cancel
()
output
,
err
:=
l
.
rollupClient
.
OutputAtBlock
(
ctx
,
block
.
Uint64
())
if
err
!=
nil
{
if
err
!=
nil
{
l
.
log
.
Error
(
"failed to fetch output at block %d: %w"
,
nextCheckpointB
lock
,
err
)
l
.
log
.
Error
(
"failed to fetch output at block %d: %w"
,
b
lock
,
err
)
return
nil
,
false
,
err
return
nil
,
false
,
err
}
}
if
output
.
Version
!=
supportedL2OutputVersion
{
if
output
.
Version
!=
supportedL2OutputVersion
{
l
.
log
.
Error
(
"unsupported l2 output version: %s"
,
output
.
Version
)
l
.
log
.
Error
(
"unsupported l2 output version: %s"
,
output
.
Version
)
return
nil
,
false
,
errors
.
New
(
"unsupported l2 output version"
)
return
nil
,
false
,
errors
.
New
(
"unsupported l2 output version"
)
}
}
if
output
.
BlockRef
.
Number
!=
nextCheckpointB
lock
.
Uint64
()
{
// sanity check, e.g. in case of bad RPC caching
if
output
.
BlockRef
.
Number
!=
b
lock
.
Uint64
()
{
// sanity check, e.g. in case of bad RPC caching
l
.
log
.
Error
(
"invalid blockNumber: next blockNumber is %v, blockNumber of block is %v"
,
nextCheckpointB
lock
,
output
.
BlockRef
.
Number
)
l
.
log
.
Error
(
"invalid blockNumber: next blockNumber is %v, blockNumber of block is %v"
,
b
lock
,
output
.
BlockRef
.
Number
)
return
nil
,
false
,
errors
.
New
(
"invalid blockNumber"
)
return
nil
,
false
,
errors
.
New
(
"invalid blockNumber"
)
}
}
...
@@ -338,54 +329,36 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
...
@@ -338,54 +329,36 @@ func (l *L2OutputSubmitter) FetchNextOutputInfo(ctx context.Context) (*eth.Outpu
return
output
,
true
,
nil
return
output
,
true
,
nil
}
}
// CreateProposalTx transforms an output response into a signed output transaction.
// ProposeL2OutputTxData creates the transaction data for the ProposeL2Output function
// It does not send the transaction to the transaction pool.
func
(
l
*
L2OutputSubmitter
)
ProposeL2OutputTxData
(
output
*
eth
.
OutputResponse
)
([]
byte
,
error
)
{
func
(
l
*
L2OutputSubmitter
)
CreateProposalTx
(
ctx
context
.
Context
,
output
*
eth
.
OutputResponse
)
(
*
types
.
Transaction
,
error
)
{
return
proposeL2OutputTxData
(
l
.
l2ooABI
,
output
)
nonce
,
err
:=
l
.
l1Client
.
NonceAt
(
ctx
,
l
.
from
,
nil
)
}
if
err
!=
nil
{
l
.
log
.
Error
(
"Failed to get nonce"
,
"err"
,
err
,
"from"
,
l
.
from
)
return
nil
,
err
}
opts
:=
&
bind
.
TransactOpts
{
From
:
l
.
from
,
Signer
:
func
(
addr
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
l
.
signerFn
(
ctx
,
addr
,
tx
)
},
Context
:
ctx
,
Nonce
:
new
(
big
.
Int
)
.
SetUint64
(
nonce
),
NoSend
:
true
,
}
tx
,
err
:=
l
.
l2ooContract
.
ProposeL2Output
(
// proposeL2OutputTxData creates the transaction data for the ProposeL2Output function
opts
,
func
proposeL2OutputTxData
(
abi
*
abi
.
ABI
,
output
*
eth
.
OutputResponse
)
([]
byte
,
error
)
{
return
abi
.
Pack
(
"proposeL2Output"
,
output
.
OutputRoot
,
output
.
OutputRoot
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
BlockRef
.
Number
),
new
(
big
.
Int
)
.
SetUint64
(
output
.
BlockRef
.
Number
),
output
.
Status
.
CurrentL1
.
Hash
,
output
.
Status
.
CurrentL1
.
Hash
,
new
(
big
.
Int
)
.
SetUint64
(
output
.
Status
.
CurrentL1
.
Number
))
new
(
big
.
Int
)
.
SetUint64
(
output
.
Status
.
CurrentL1
.
Number
))
if
err
!=
nil
{
l
.
log
.
Error
(
"failed to create the ProposeL2Output transaction"
,
"err"
,
err
)
return
nil
,
err
}
return
tx
,
nil
}
}
// SendTransaction sends a transaction through the transaction manager which handles automatic
// sendTransaction creates & sends transactions through the underlying transaction manager.
// price bumping.
func
(
l
*
L2OutputSubmitter
)
sendTransaction
(
ctx
context
.
Context
,
output
*
eth
.
OutputResponse
)
error
{
// It also hardcodes a timeout of 100s.
data
,
err
:=
l
.
ProposeL2OutputTxData
(
output
)
func
(
l
*
L2OutputSubmitter
)
SendTransaction
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
if
err
!=
nil
{
// Wait until one of our submitted transactions confirms. If no
return
err
// receipt is received it's likely our gas price was too low.
}
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
100
*
time
.
Second
)
receipt
,
err
:=
l
.
txMgr
.
Send
(
ctx
,
txmgr
.
TxCandidate
{
defer
cancel
()
TxData
:
data
,
l
.
log
.
Info
(
"Sending transaction"
,
"tx_hash"
,
tx
.
Hash
())
To
:
l
.
l2ooContractAddr
,
receipt
,
err
:=
l
.
txMgr
.
Send
(
cCtx
,
tx
)
GasLimit
:
0
,
From
:
l
.
from
,
})
if
err
!=
nil
{
if
err
!=
nil
{
l
.
log
.
Error
(
"proposer unable to publish tx"
,
"err"
,
err
)
return
err
return
err
}
}
// The transaction was successfully submitted
l
.
log
.
Info
(
"proposer tx successfully published"
,
"tx_hash"
,
receipt
.
TxHash
)
l
.
log
.
Info
(
"proposer tx successfully published"
,
"tx_hash"
,
receipt
.
TxHash
)
return
nil
return
nil
}
}
...
@@ -401,9 +374,7 @@ func (l *L2OutputSubmitter) loop() {
...
@@ -401,9 +374,7 @@ func (l *L2OutputSubmitter) loop() {
for
{
for
{
select
{
select
{
case
<-
ticker
.
C
:
case
<-
ticker
.
C
:
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
30
*
time
.
Second
)
output
,
shouldPropose
,
err
:=
l
.
FetchNextOutputInfo
(
ctx
)
output
,
shouldPropose
,
err
:=
l
.
FetchNextOutputInfo
(
cCtx
)
cancel
()
if
err
!=
nil
{
if
err
!=
nil
{
break
break
}
}
...
@@ -411,15 +382,8 @@ func (l *L2OutputSubmitter) loop() {
...
@@ -411,15 +382,8 @@ func (l *L2OutputSubmitter) loop() {
break
break
}
}
cCtx
,
cancel
=
context
.
WithTimeout
(
ctx
,
30
*
time
.
Second
)
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
10
*
time
.
Minute
)
tx
,
err
:=
l
.
CreateProposalTx
(
cCtx
,
output
)
if
err
:=
l
.
sendTransaction
(
cCtx
,
output
);
err
!=
nil
{
cancel
()
if
err
!=
nil
{
l
.
log
.
Error
(
"Failed to create proposal transaction"
,
"err"
,
err
)
break
}
cCtx
,
cancel
=
context
.
WithTimeout
(
ctx
,
10
*
time
.
Minute
)
if
err
:=
l
.
SendTransaction
(
cCtx
,
tx
);
err
!=
nil
{
l
.
log
.
Error
(
"Failed to send proposal transaction"
,
"err"
,
err
)
l
.
log
.
Error
(
"Failed to send proposal transaction"
,
"err"
,
err
)
cancel
()
cancel
()
break
break
...
...
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