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
5599aed1
Unverified
Commit
5599aed1
authored
Jan 14, 2022
by
Matthew Slipper
Committed by
GitHub
Jan 14, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2003 from cfromknecht/bss-pending-tx
feat: implement clear pending txs for go batch submitter
parents
0f5c810a
15252dd3
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
613 additions
and
8 deletions
+613
-8
batch_submitter.go
go/batch-submitter/batch_submitter.go
+6
-8
clear_pending_tx.go
go/batch-submitter/drivers/clear_pending_tx.go
+173
-0
clear_pending_tx_test.go
go/batch-submitter/drivers/clear_pending_tx_test.go
+192
-0
interface.go
go/batch-submitter/drivers/interface.go
+36
-0
driver.go
go/batch-submitter/drivers/proposer/driver.go
+17
-0
driver.go
go/batch-submitter/drivers/sequencer/driver.go
+17
-0
l1client.go
go/batch-submitter/mock/l1client.go
+123
-0
service.go
go/batch-submitter/service.go
+19
-0
gas_price.go
go/batch-submitter/utils/gas_price.go
+12
-0
gas_price_test.go
go/batch-submitter/utils/gas_price_test.go
+18
-0
No files found.
go/batch-submitter/batch_submitter.go
View file @
5599aed1
...
@@ -4,7 +4,6 @@ import (
...
@@ -4,7 +4,6 @@ import (
"context"
"context"
"crypto/ecdsa"
"crypto/ecdsa"
"fmt"
"fmt"
"math/big"
"net/http"
"net/http"
"os"
"os"
"strconv"
"strconv"
...
@@ -13,6 +12,7 @@ import (
...
@@ -13,6 +12,7 @@ import (
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers/proposer"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers/proposer"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers/sequencer"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers/sequencer"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
"github.com/ethereum-optimism/optimism/go/batch-submitter/utils"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto"
...
@@ -159,9 +159,9 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
...
@@ -159,9 +159,9 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
}
}
txManagerConfig
:=
txmgr
.
Config
{
txManagerConfig
:=
txmgr
.
Config
{
MinGasPrice
:
g
asPriceFromGwei
(
1
),
MinGasPrice
:
utils
.
G
asPriceFromGwei
(
1
),
MaxGasPrice
:
g
asPriceFromGwei
(
cfg
.
MaxGasPriceInGwei
),
MaxGasPrice
:
utils
.
G
asPriceFromGwei
(
cfg
.
MaxGasPriceInGwei
),
GasRetryIncrement
:
g
asPriceFromGwei
(
cfg
.
GasRetryIncrement
),
GasRetryIncrement
:
utils
.
G
asPriceFromGwei
(
cfg
.
GasRetryIncrement
),
ResubmissionTimeout
:
cfg
.
ResubmissionTimeout
,
ResubmissionTimeout
:
cfg
.
ResubmissionTimeout
,
ReceiptQueryInterval
:
time
.
Second
,
ReceiptQueryInterval
:
time
.
Second
,
}
}
...
@@ -186,6 +186,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
...
@@ -186,6 +186,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
Context
:
ctx
,
Context
:
ctx
,
Driver
:
batchTxDriver
,
Driver
:
batchTxDriver
,
PollInterval
:
cfg
.
PollInterval
,
PollInterval
:
cfg
.
PollInterval
,
ClearPendingTx
:
cfg
.
ClearPendingTxs
,
L1Client
:
l1Client
,
L1Client
:
l1Client
,
TxManagerConfig
:
txManagerConfig
,
TxManagerConfig
:
txManagerConfig
,
})
})
...
@@ -212,6 +213,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
...
@@ -212,6 +213,7 @@ func NewBatchSubmitter(cfg Config, gitVersion string) (*BatchSubmitter, error) {
Context
:
ctx
,
Context
:
ctx
,
Driver
:
batchStateDriver
,
Driver
:
batchStateDriver
,
PollInterval
:
cfg
.
PollInterval
,
PollInterval
:
cfg
.
PollInterval
,
ClearPendingTx
:
cfg
.
ClearPendingTxs
,
L1Client
:
l1Client
,
L1Client
:
l1Client
,
TxManagerConfig
:
txManagerConfig
,
TxManagerConfig
:
txManagerConfig
,
})
})
...
@@ -333,7 +335,3 @@ func traceRateToFloat64(rate time.Duration) float64 {
...
@@ -333,7 +335,3 @@ func traceRateToFloat64(rate time.Duration) float64 {
}
}
return
rate64
return
rate64
}
}
func
gasPriceFromGwei
(
gasPriceInGwei
uint64
)
*
big
.
Int
{
return
new
(
big
.
Int
)
.
SetUint64
(
gasPriceInGwei
*
1e9
)
}
go/batch-submitter/drivers/clear_pending_tx.go
0 → 100644
View file @
5599aed1
package
drivers
import
(
"context"
"crypto/ecdsa"
"errors"
"math/big"
"strings"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
)
// ErrClearPendingRetry signals that a transaction from a previous running
// instance confirmed rather than our clearing transaction on startup. In this
// case the caller should retry.
var
ErrClearPendingRetry
=
errors
.
New
(
"retry clear pending txn"
)
// ClearPendingTx publishes a NOOP transaction at the wallet's next unused
// nonce. This is used on restarts in order to clear the mempool of any prior
// publications and ensure the batch submitter starts submitting from a clean
// slate.
func
ClearPendingTx
(
name
string
,
ctx
context
.
Context
,
txMgr
txmgr
.
TxManager
,
l1Client
L1Client
,
walletAddr
common
.
Address
,
privKey
*
ecdsa
.
PrivateKey
,
chainID
*
big
.
Int
,
)
error
{
// Query for the submitter's current nonce.
nonce
,
err
:=
l1Client
.
NonceAt
(
ctx
,
walletAddr
,
nil
)
if
err
!=
nil
{
log
.
Error
(
name
+
" unable to get current nonce"
,
"err"
,
err
)
return
err
}
ctx
,
cancel
:=
context
.
WithCancel
(
ctx
)
defer
cancel
()
// Construct the clearing transaction submission clousure that will attempt
// to send the a clearing transaction transaction at the given nonce and gas
// price.
sendTx
:=
func
(
ctx
context
.
Context
,
gasPrice
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
log
.
Info
(
name
+
" clearing pending tx"
,
"nonce"
,
nonce
,
"gasPrice"
,
gasPrice
)
signedTx
,
err
:=
SignClearingTx
(
ctx
,
walletAddr
,
nonce
,
gasPrice
,
l1Client
,
privKey
,
chainID
,
)
if
err
!=
nil
{
log
.
Error
(
name
+
" unable to sign clearing tx"
,
"nonce"
,
nonce
,
"gasPrice"
,
gasPrice
,
"err"
,
err
)
return
nil
,
err
}
txHash
:=
signedTx
.
Hash
()
err
=
l1Client
.
SendTransaction
(
ctx
,
signedTx
)
switch
{
// Clearing transaction successfully confirmed.
case
err
==
nil
:
log
.
Info
(
name
+
" submitted clearing tx"
,
"nonce"
,
nonce
,
"gasPrice"
,
gasPrice
,
"txHash"
,
txHash
)
return
signedTx
,
nil
// Getting a nonce too low error implies that a previous transaction in
// the mempool has confirmed and we should abort trying to publish at
// this nonce.
case
strings
.
Contains
(
err
.
Error
(),
core
.
ErrNonceTooLow
.
Error
())
:
log
.
Info
(
name
+
" transaction from previous restart confirmed, "
+
"aborting mempool clearing"
)
cancel
()
return
nil
,
context
.
Canceled
// An unexpected error occurred. This also handles the case where the
// clearing transaction has not yet bested the gas price a prior
// transaction in the mempool at this nonce. In such a case we will
// continue until our ratchetting strategy overtakes the old
// transaction, or abort if the old one confirms.
default
:
log
.
Error
(
name
+
" unable to submit clearing tx"
,
"nonce"
,
nonce
,
"gasPrice"
,
gasPrice
,
"txHash"
,
txHash
,
"err"
,
err
)
return
nil
,
err
}
}
receipt
,
err
:=
txMgr
.
Send
(
ctx
,
sendTx
)
switch
{
// If the current context is canceled, a prior transaction in the mempool
// confirmed. The caller should retry, which will use the next nonce, before
// proceeding.
case
err
==
context
.
Canceled
:
log
.
Info
(
name
+
" transaction from previous restart confirmed, "
+
"proceeding to startup"
)
return
ErrClearPendingRetry
// Otherwise we were unable to confirm our transaction, this method should
// be retried by the caller.
case
err
!=
nil
:
log
.
Warn
(
name
+
" unable to send clearing tx"
,
"nonce"
,
nonce
,
"err"
,
err
)
return
err
// We succeeded in confirming a clearing transaction. Proceed to startup as
// normal.
default
:
log
.
Info
(
name
+
" cleared pending tx"
,
"nonce"
,
nonce
,
"txHash"
,
receipt
.
TxHash
)
return
nil
}
}
// SignClearingTx creates a signed clearing tranaction which sends 0 ETH back to
// the sender's address. EstimateGas is used to set an appropriate gas limit.
func
SignClearingTx
(
ctx
context
.
Context
,
walletAddr
common
.
Address
,
nonce
uint64
,
gasPrice
*
big
.
Int
,
l1Client
L1Client
,
privKey
*
ecdsa
.
PrivateKey
,
chainID
*
big
.
Int
,
)
(
*
types
.
Transaction
,
error
)
{
gasLimit
,
err
:=
l1Client
.
EstimateGas
(
ctx
,
ethereum
.
CallMsg
{
To
:
&
walletAddr
,
GasPrice
:
gasPrice
,
Value
:
nil
,
Data
:
nil
,
})
if
err
!=
nil
{
return
nil
,
err
}
tx
:=
CraftClearingTx
(
walletAddr
,
nonce
,
gasPrice
,
gasLimit
)
return
types
.
SignTx
(
tx
,
types
.
LatestSignerForChainID
(
chainID
),
privKey
,
)
}
// CraftClearingTx creates an unsigned clearing transaction which sends 0 ETH
// back to the sender's address.
func
CraftClearingTx
(
walletAddr
common
.
Address
,
nonce
uint64
,
gasPrice
*
big
.
Int
,
gasLimit
uint64
,
)
*
types
.
Transaction
{
return
types
.
NewTx
(
&
types
.
LegacyTx
{
To
:
&
walletAddr
,
Nonce
:
nonce
,
GasPrice
:
gasPrice
,
Gas
:
gasLimit
,
Value
:
nil
,
Data
:
nil
,
})
}
go/batch-submitter/drivers/clear_pending_tx_test.go
0 → 100644
View file @
5599aed1
package
drivers_test
import
(
"context"
"crypto/ecdsa"
"errors"
"math/big"
"testing"
"time"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers"
"github.com/ethereum-optimism/optimism/go/batch-submitter/mock"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
"github.com/ethereum-optimism/optimism/go/batch-submitter/utils"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
func
init
()
{
privKey
,
err
:=
crypto
.
GenerateKey
()
if
err
!=
nil
{
panic
(
err
)
}
testPrivKey
=
privKey
testWalletAddr
=
crypto
.
PubkeyToAddress
(
privKey
.
PublicKey
)
testChainID
=
new
(
big
.
Int
)
.
SetUint64
(
1
)
testGasPrice
=
new
(
big
.
Int
)
.
SetUint64
(
3
)
}
var
(
testPrivKey
*
ecdsa
.
PrivateKey
testWalletAddr
common
.
Address
testChainID
*
big
.
Int
// 1
testNonce
=
uint64
(
2
)
testGasPrice
*
big
.
Int
// 3
testGasLimit
=
uint64
(
4
)
)
// TestCraftClearingTx asserts that CraftClearingTx produces the expected
// unsigned clearing transaction.
func
TestCraftClearingTx
(
t
*
testing
.
T
)
{
tx
:=
drivers
.
CraftClearingTx
(
testWalletAddr
,
testNonce
,
testGasPrice
,
testGasLimit
,
)
require
.
Equal
(
t
,
&
testWalletAddr
,
tx
.
To
())
require
.
Equal
(
t
,
testNonce
,
tx
.
Nonce
())
require
.
Equal
(
t
,
testGasPrice
,
tx
.
GasPrice
())
require
.
Equal
(
t
,
testGasLimit
,
tx
.
Gas
())
require
.
Equal
(
t
,
new
(
big
.
Int
),
tx
.
Value
())
require
.
Nil
(
t
,
tx
.
Data
())
}
// TestSignClearingTxSuccess asserts that we will sign a properly formed
// clearing transaction when the call to EstimateGas succeeds.
func
TestSignClearingTxEstimateGasSuccess
(
t
*
testing
.
T
)
{
l1Client
:=
mock
.
NewL1Client
(
mock
.
L1ClientConfig
{
EstimateGas
:
func
(
_
context
.
Context
,
_
ethereum
.
CallMsg
)
(
uint64
,
error
)
{
return
testGasLimit
,
nil
},
})
tx
,
err
:=
drivers
.
SignClearingTx
(
context
.
Background
(),
testWalletAddr
,
testNonce
,
testGasPrice
,
l1Client
,
testPrivKey
,
testChainID
,
)
require
.
Nil
(
t
,
err
)
require
.
NotNil
(
t
,
tx
)
require
.
Equal
(
t
,
&
testWalletAddr
,
tx
.
To
())
require
.
Equal
(
t
,
testNonce
,
tx
.
Nonce
())
require
.
Equal
(
t
,
testGasPrice
,
tx
.
GasPrice
())
require
.
Equal
(
t
,
testGasLimit
,
tx
.
Gas
())
require
.
Equal
(
t
,
new
(
big
.
Int
),
tx
.
Value
())
require
.
Nil
(
t
,
tx
.
Data
())
// Finally, ensure the sender is correct.
sender
,
err
:=
types
.
Sender
(
types
.
LatestSignerForChainID
(
testChainID
),
tx
)
require
.
Nil
(
t
,
err
)
require
.
Equal
(
t
,
testWalletAddr
,
sender
)
}
// TestSignClearingTxEstimateGasFail asserts that signing a clearing transaction
// will fail if the underlying call to EstimateGas fails.
func
TestSignClearingTxEstimateGasFail
(
t
*
testing
.
T
)
{
errEstimateGas
:=
errors
.
New
(
"estimate gas"
)
l1Client
:=
mock
.
NewL1Client
(
mock
.
L1ClientConfig
{
EstimateGas
:
func
(
_
context
.
Context
,
_
ethereum
.
CallMsg
)
(
uint64
,
error
)
{
return
0
,
errEstimateGas
},
})
tx
,
err
:=
drivers
.
SignClearingTx
(
context
.
Background
(),
testWalletAddr
,
testNonce
,
testGasPrice
,
l1Client
,
testPrivKey
,
testChainID
,
)
require
.
Equal
(
t
,
errEstimateGas
,
err
)
require
.
Nil
(
t
,
tx
)
}
type
clearPendingTxHarness
struct
{
l1Client
drivers
.
L1Client
txMgr
txmgr
.
TxManager
}
func
newClearPendingTxHarness
(
l1ClientConfig
mock
.
L1ClientConfig
)
*
clearPendingTxHarness
{
if
l1ClientConfig
.
NonceAt
==
nil
{
l1ClientConfig
.
NonceAt
=
func
(
_
context
.
Context
,
_
common
.
Address
,
_
*
big
.
Int
)
(
uint64
,
error
)
{
return
testNonce
,
nil
}
}
if
l1ClientConfig
.
EstimateGas
==
nil
{
l1ClientConfig
.
EstimateGas
=
func
(
_
context
.
Context
,
_
ethereum
.
CallMsg
)
(
uint64
,
error
)
{
return
testGasLimit
,
nil
}
}
l1Client
:=
mock
.
NewL1Client
(
l1ClientConfig
)
txMgr
:=
txmgr
.
NewSimpleTxManager
(
"test"
,
txmgr
.
Config
{
MinGasPrice
:
utils
.
GasPriceFromGwei
(
1
),
MaxGasPrice
:
utils
.
GasPriceFromGwei
(
100
),
GasRetryIncrement
:
utils
.
GasPriceFromGwei
(
5
),
ResubmissionTimeout
:
time
.
Second
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
},
l1Client
)
return
&
clearPendingTxHarness
{
l1Client
:
l1Client
,
txMgr
:
txMgr
,
}
}
// TestClearPendingTxClearingTxÇonfirms asserts the happy path where our
// clearing transactions confirms unobstructed.
func
TestClearPendingTxClearingTxConfirms
(
t
*
testing
.
T
)
{
h
:=
newClearPendingTxHarness
(
mock
.
L1ClientConfig
{
SendTransaction
:
func
(
_
context
.
Context
,
_
*
types
.
Transaction
)
error
{
return
nil
},
TransactionReceipt
:
func
(
_
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
},
nil
},
})
err
:=
drivers
.
ClearPendingTx
(
"test"
,
context
.
Background
(),
h
.
txMgr
,
h
.
l1Client
,
testWalletAddr
,
testPrivKey
,
testChainID
,
)
require
.
Nil
(
t
,
err
)
}
// TestClearPendingTx∏reviousTxConfirms asserts that if the mempool starts
// rejecting our transactions because the nonce is too low that ClearPendingTx
// will abort continuing to publish a clearing transaction.
func
TestClearPendingTxPreviousTxConfirms
(
t
*
testing
.
T
)
{
h
:=
newClearPendingTxHarness
(
mock
.
L1ClientConfig
{
SendTransaction
:
func
(
_
context
.
Context
,
_
*
types
.
Transaction
)
error
{
return
core
.
ErrNonceTooLow
},
})
err
:=
drivers
.
ClearPendingTx
(
"test"
,
context
.
Background
(),
h
.
txMgr
,
h
.
l1Client
,
testWalletAddr
,
testPrivKey
,
testChainID
,
)
require
.
Equal
(
t
,
drivers
.
ErrClearPendingRetry
,
err
)
}
// TestClearPendingTxTimeout asserts that ClearPendingTx returns an
// ErrPublishTimeout if the clearing transaction fails to confirm in a timely
// manner and no prior transaction confirms.
func
TestClearPendingTxTimeout
(
t
*
testing
.
T
)
{
h
:=
newClearPendingTxHarness
(
mock
.
L1ClientConfig
{
SendTransaction
:
func
(
_
context
.
Context
,
_
*
types
.
Transaction
)
error
{
return
nil
},
TransactionReceipt
:
func
(
_
context
.
Context
,
txHash
common
.
Hash
)
(
*
types
.
Receipt
,
error
)
{
return
nil
,
nil
},
})
err
:=
drivers
.
ClearPendingTx
(
"test"
,
context
.
Background
(),
h
.
txMgr
,
h
.
l1Client
,
testWalletAddr
,
testPrivKey
,
testChainID
,
)
require
.
Equal
(
t
,
txmgr
.
ErrPublishTimeout
,
err
)
}
go/batch-submitter/drivers/interface.go
0 → 100644
View file @
5599aed1
package
drivers
import
(
"context"
"math/big"
"github.com/ethereum/go-ethereum"
"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
{
// EstimateGas tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as
// other transactions may be added or removed by miners, but it should
// provide a basis for setting a reasonable default.
EstimateGas
(
context
.
Context
,
ethereum
.
CallMsg
)
(
uint64
,
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
// 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
)
}
go/batch-submitter/drivers/proposer/driver.go
View file @
5599aed1
...
@@ -9,7 +9,9 @@ import (
...
@@ -9,7 +9,9 @@ import (
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/scc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/scc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
"github.com/ethereum-optimism/optimism/l2geth/log"
"github.com/ethereum-optimism/optimism/l2geth/log"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
...
@@ -85,6 +87,21 @@ func (d *Driver) Metrics() *metrics.Metrics {
...
@@ -85,6 +87,21 @@ func (d *Driver) Metrics() *metrics.Metrics {
return
d
.
metrics
return
d
.
metrics
}
}
// ClearPendingTx a publishes a transaction at the next available nonce in order
// to clear any transactions in the mempool left over from a prior running
// instance of the batch submitter.
func
(
d
*
Driver
)
ClearPendingTx
(
ctx
context
.
Context
,
txMgr
txmgr
.
TxManager
,
l1Client
*
ethclient
.
Client
,
)
error
{
return
drivers
.
ClearPendingTx
(
d
.
cfg
.
Name
,
ctx
,
txMgr
,
l1Client
,
d
.
walletAddr
,
d
.
cfg
.
PrivKey
,
d
.
cfg
.
ChainID
,
)
}
// GetBatchBlockRange returns the start and end L2 block heights that need to be
// GetBatchBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned
// processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed.
// values are identical nothing needs to be processed.
...
...
go/batch-submitter/drivers/sequencer/driver.go
View file @
5599aed1
...
@@ -9,7 +9,9 @@ import (
...
@@ -9,7 +9,9 @@ import (
"time"
"time"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/bindings/ctc"
"github.com/ethereum-optimism/optimism/go/batch-submitter/drivers"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
"github.com/ethereum-optimism/optimism/go/batch-submitter/metrics"
"github.com/ethereum-optimism/optimism/go/batch-submitter/txmgr"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
l2ethclient
"github.com/ethereum-optimism/optimism/l2geth/ethclient"
"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"
...
@@ -98,6 +100,21 @@ func (d *Driver) Metrics() *metrics.Metrics {
...
@@ -98,6 +100,21 @@ func (d *Driver) Metrics() *metrics.Metrics {
return
d
.
metrics
return
d
.
metrics
}
}
// ClearPendingTx a publishes a transaction at the next available nonce in order
// to clear any transactions in the mempool left over from a prior running
// instance of the batch submitter.
func
(
d
*
Driver
)
ClearPendingTx
(
ctx
context
.
Context
,
txMgr
txmgr
.
TxManager
,
l1Client
*
ethclient
.
Client
,
)
error
{
return
drivers
.
ClearPendingTx
(
d
.
cfg
.
Name
,
ctx
,
txMgr
,
l1Client
,
d
.
walletAddr
,
d
.
cfg
.
PrivKey
,
d
.
cfg
.
ChainID
,
)
}
// GetBatchBlockRange returns the start and end L2 block heights that need to be
// GetBatchBlockRange returns the start and end L2 block heights that need to be
// processed. Note that the end value is *exclusive*, therefore if the returned
// processed. Note that the end value is *exclusive*, therefore if the returned
// values are identical nothing needs to be processed.
// values are identical nothing needs to be processed.
...
...
go/batch-submitter/mock/l1client.go
0 → 100644
View file @
5599aed1
package
mock
import
(
"context"
"math/big"
"sync"
"github.com/ethereum/go-ethereum"
"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
{
// EstimateGas tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as
// other transactions may be added or removed by miners, but it should
// provide a basis for setting a reasonable default.
EstimateGas
func
(
context
.
Context
,
ethereum
.
CallMsg
)
(
uint64
,
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
// 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
,
}
}
// EstimateGas executes the mock EstimateGas method.
func
(
c
*
L1Client
)
EstimateGas
(
ctx
context
.
Context
,
call
ethereum
.
CallMsg
)
(
uint64
,
error
)
{
c
.
mu
.
RLock
()
defer
c
.
mu
.
RUnlock
()
return
c
.
cfg
.
EstimateGas
(
ctx
,
call
)
}
// 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
)
}
// 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
)
}
// SetEstimateGasFunc overrwrites the mock EstimateGas method.
func
(
c
*
L1Client
)
SetEstimateGasFunc
(
f
func
(
context
.
Context
,
ethereum
.
CallMsg
)
(
uint64
,
error
))
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
c
.
cfg
.
EstimateGas
=
f
}
// SetNonceAtFunc overrwrites 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 overrwrites 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
}
// 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
}
go/batch-submitter/service.go
View file @
5599aed1
...
@@ -32,6 +32,11 @@ type Driver interface {
...
@@ -32,6 +32,11 @@ type Driver interface {
// Metrics returns the subservice telemetry object.
// Metrics returns the subservice telemetry object.
Metrics
()
*
metrics
.
Metrics
Metrics
()
*
metrics
.
Metrics
// ClearPendingTx a publishes a transaction at the next available nonce in
// order to clear any transactions in the mempool left over from a prior
// running instance of the batch submitter.
ClearPendingTx
(
context
.
Context
,
txmgr
.
TxManager
,
*
ethclient
.
Client
)
error
// GetBatchBlockRange returns the start and end L2 block heights that
// GetBatchBlockRange returns the start and end L2 block heights that
// need to be processed. Note that the end value is *exclusive*,
// need to be processed. Note that the end value is *exclusive*,
// therefore if the returned values are identical nothing needs to be
// therefore if the returned values are identical nothing needs to be
...
@@ -51,6 +56,7 @@ type ServiceConfig struct {
...
@@ -51,6 +56,7 @@ type ServiceConfig struct {
Context
context
.
Context
Context
context
.
Context
Driver
Driver
Driver
Driver
PollInterval
time
.
Duration
PollInterval
time
.
Duration
ClearPendingTx
bool
L1Client
*
ethclient
.
Client
L1Client
*
ethclient
.
Client
TxManagerConfig
txmgr
.
Config
TxManagerConfig
txmgr
.
Config
}
}
...
@@ -99,6 +105,19 @@ func (s *Service) eventLoop() {
...
@@ -99,6 +105,19 @@ func (s *Service) eventLoop() {
name
:=
s
.
cfg
.
Driver
.
Name
()
name
:=
s
.
cfg
.
Driver
.
Name
()
if
s
.
cfg
.
ClearPendingTx
{
const
maxClearRetries
=
3
for
i
:=
0
;
i
<
maxClearRetries
;
i
++
{
err
:=
s
.
cfg
.
Driver
.
ClearPendingTx
(
s
.
ctx
,
s
.
txMgr
,
s
.
cfg
.
L1Client
)
if
err
==
nil
{
break
}
else
if
i
<
maxClearRetries
-
1
{
continue
}
log
.
Crit
(
"Unable to confirm a clearing transaction"
,
"err"
,
err
)
}
}
for
{
for
{
select
{
select
{
case
<-
time
.
After
(
s
.
cfg
.
PollInterval
)
:
case
<-
time
.
After
(
s
.
cfg
.
PollInterval
)
:
...
...
go/batch-submitter/utils/gas_price.go
0 → 100644
View file @
5599aed1
package
utils
import
(
"math/big"
"github.com/ethereum/go-ethereum/params"
)
// GasPriceFromGwei converts an uint64 gas price in gwei to a big.Int in wei.
func
GasPriceFromGwei
(
gasPriceInGwei
uint64
)
*
big
.
Int
{
return
new
(
big
.
Int
)
.
SetUint64
(
gasPriceInGwei
*
params
.
GWei
)
}
go/batch-submitter/utils/gas_price_test.go
0 → 100644
View file @
5599aed1
package
utils_test
import
(
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/go/batch-submitter/utils"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
// TestGasPriceFromGwei asserts that the integer value is scaled properly by
// 10^9.
func
TestGasPriceFromGwei
(
t
*
testing
.
T
)
{
require
.
Equal
(
t
,
utils
.
GasPriceFromGwei
(
0
),
new
(
big
.
Int
))
require
.
Equal
(
t
,
utils
.
GasPriceFromGwei
(
1
),
big
.
NewInt
(
params
.
GWei
))
require
.
Equal
(
t
,
utils
.
GasPriceFromGwei
(
100
),
big
.
NewInt
(
100
*
params
.
GWei
))
}
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