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
753c36ca
Unverified
Commit
753c36ca
authored
Sep 29, 2023
by
Michael de Hoog
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
txmgr: don't wait the resubmission timeout for gas increases for underpriced errors
parent
cf7b329a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
123 additions
and
70 deletions
+123
-70
setup.go
op-e2e/setup.go
+1
-0
cli.go
op-service/txmgr/cli.go
+23
-0
send_state.go
op-service/txmgr/send_state.go
+3
-0
txmgr.go
op-service/txmgr/txmgr.go
+82
-56
txmgr_test.go
op-service/txmgr/txmgr_test.go
+14
-14
No files found.
op-e2e/setup.go
View file @
753c36ca
...
@@ -71,6 +71,7 @@ func newTxMgrConfig(l1Addr string, privKey *ecdsa.PrivateKey) txmgr.CLIConfig {
...
@@ -71,6 +71,7 @@ func newTxMgrConfig(l1Addr string, privKey *ecdsa.PrivateKey) txmgr.CLIConfig {
PrivateKey
:
hexPriv
(
privKey
),
PrivateKey
:
hexPriv
(
privKey
),
NumConfirmations
:
1
,
NumConfirmations
:
1
,
SafeAbortNonceTooLowCount
:
3
,
SafeAbortNonceTooLowCount
:
3
,
FeeLimitMultiplier
:
5
,
ResubmissionTimeout
:
3
*
time
.
Second
,
ResubmissionTimeout
:
3
*
time
.
Second
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
NetworkTimeout
:
2
*
time
.
Second
,
NetworkTimeout
:
2
*
time
.
Second
,
...
...
op-service/txmgr/cli.go
View file @
753c36ca
...
@@ -26,6 +26,7 @@ const (
...
@@ -26,6 +26,7 @@ const (
// TxMgr Flags (new + legacy + some shared flags)
// TxMgr Flags (new + legacy + some shared flags)
NumConfirmationsFlagName
=
"num-confirmations"
NumConfirmationsFlagName
=
"num-confirmations"
SafeAbortNonceTooLowCountFlagName
=
"safe-abort-nonce-too-low-count"
SafeAbortNonceTooLowCountFlagName
=
"safe-abort-nonce-too-low-count"
FeeLimitMultiplierFlagName
=
"fee-limit-multiplier"
ResubmissionTimeoutFlagName
=
"resubmission-timeout"
ResubmissionTimeoutFlagName
=
"resubmission-timeout"
NetworkTimeoutFlagName
=
"network-timeout"
NetworkTimeoutFlagName
=
"network-timeout"
TxSendTimeoutFlagName
=
"txmgr.send-timeout"
TxSendTimeoutFlagName
=
"txmgr.send-timeout"
...
@@ -51,6 +52,7 @@ var (
...
@@ -51,6 +52,7 @@ var (
type
DefaultFlagValues
struct
{
type
DefaultFlagValues
struct
{
NumConfirmations
uint64
NumConfirmations
uint64
SafeAbortNonceTooLowCount
uint64
SafeAbortNonceTooLowCount
uint64
FeeLimitMultiplier
uint64
ResubmissionTimeout
time
.
Duration
ResubmissionTimeout
time
.
Duration
NetworkTimeout
time
.
Duration
NetworkTimeout
time
.
Duration
TxSendTimeout
time
.
Duration
TxSendTimeout
time
.
Duration
...
@@ -62,6 +64,7 @@ var (
...
@@ -62,6 +64,7 @@ var (
DefaultBatcherFlagValues
=
DefaultFlagValues
{
DefaultBatcherFlagValues
=
DefaultFlagValues
{
NumConfirmations
:
uint64
(
10
),
NumConfirmations
:
uint64
(
10
),
SafeAbortNonceTooLowCount
:
uint64
(
3
),
SafeAbortNonceTooLowCount
:
uint64
(
3
),
FeeLimitMultiplier
:
uint64
(
5
),
ResubmissionTimeout
:
48
*
time
.
Second
,
ResubmissionTimeout
:
48
*
time
.
Second
,
NetworkTimeout
:
10
*
time
.
Second
,
NetworkTimeout
:
10
*
time
.
Second
,
TxSendTimeout
:
0
*
time
.
Second
,
TxSendTimeout
:
0
*
time
.
Second
,
...
@@ -71,6 +74,7 @@ var (
...
@@ -71,6 +74,7 @@ var (
DefaultChallengerFlagValues
=
DefaultFlagValues
{
DefaultChallengerFlagValues
=
DefaultFlagValues
{
NumConfirmations
:
uint64
(
3
),
NumConfirmations
:
uint64
(
3
),
SafeAbortNonceTooLowCount
:
uint64
(
3
),
SafeAbortNonceTooLowCount
:
uint64
(
3
),
FeeLimitMultiplier
:
uint64
(
5
),
ResubmissionTimeout
:
24
*
time
.
Second
,
ResubmissionTimeout
:
24
*
time
.
Second
,
NetworkTimeout
:
10
*
time
.
Second
,
NetworkTimeout
:
10
*
time
.
Second
,
TxSendTimeout
:
2
*
time
.
Minute
,
TxSendTimeout
:
2
*
time
.
Minute
,
...
@@ -115,6 +119,12 @@ func CLIFlagsWithDefaults(envPrefix string, defaults DefaultFlagValues) []cli.Fl
...
@@ -115,6 +119,12 @@ func CLIFlagsWithDefaults(envPrefix string, defaults DefaultFlagValues) []cli.Fl
Value
:
defaults
.
SafeAbortNonceTooLowCount
,
Value
:
defaults
.
SafeAbortNonceTooLowCount
,
EnvVars
:
prefixEnvVars
(
"SAFE_ABORT_NONCE_TOO_LOW_COUNT"
),
EnvVars
:
prefixEnvVars
(
"SAFE_ABORT_NONCE_TOO_LOW_COUNT"
),
},
},
&
cli
.
Uint64Flag
{
Name
:
FeeLimitMultiplierFlagName
,
Usage
:
"The multiplier applied to fee suggestions to put a hard limit on fee increases"
,
Value
:
defaults
.
FeeLimitMultiplier
,
EnvVars
:
prefixEnvVars
(
"FEE_LIMIT_MULTIPLIER"
),
},
&
cli
.
DurationFlag
{
&
cli
.
DurationFlag
{
Name
:
ResubmissionTimeoutFlagName
,
Name
:
ResubmissionTimeoutFlagName
,
Usage
:
"Duration we will wait before resubmitting a transaction to L1"
,
Usage
:
"Duration we will wait before resubmitting a transaction to L1"
,
...
@@ -158,6 +168,7 @@ type CLIConfig struct {
...
@@ -158,6 +168,7 @@ type CLIConfig struct {
SignerCLIConfig
opsigner
.
CLIConfig
SignerCLIConfig
opsigner
.
CLIConfig
NumConfirmations
uint64
NumConfirmations
uint64
SafeAbortNonceTooLowCount
uint64
SafeAbortNonceTooLowCount
uint64
FeeLimitMultiplier
uint64
ResubmissionTimeout
time
.
Duration
ResubmissionTimeout
time
.
Duration
ReceiptQueryInterval
time
.
Duration
ReceiptQueryInterval
time
.
Duration
NetworkTimeout
time
.
Duration
NetworkTimeout
time
.
Duration
...
@@ -170,6 +181,7 @@ func NewCLIConfig(l1RPCURL string, defaults DefaultFlagValues) CLIConfig {
...
@@ -170,6 +181,7 @@ func NewCLIConfig(l1RPCURL string, defaults DefaultFlagValues) CLIConfig {
L1RPCURL
:
l1RPCURL
,
L1RPCURL
:
l1RPCURL
,
NumConfirmations
:
defaults
.
NumConfirmations
,
NumConfirmations
:
defaults
.
NumConfirmations
,
SafeAbortNonceTooLowCount
:
defaults
.
SafeAbortNonceTooLowCount
,
SafeAbortNonceTooLowCount
:
defaults
.
SafeAbortNonceTooLowCount
,
FeeLimitMultiplier
:
defaults
.
FeeLimitMultiplier
,
ResubmissionTimeout
:
defaults
.
ResubmissionTimeout
,
ResubmissionTimeout
:
defaults
.
ResubmissionTimeout
,
NetworkTimeout
:
defaults
.
NetworkTimeout
,
NetworkTimeout
:
defaults
.
NetworkTimeout
,
TxSendTimeout
:
defaults
.
TxSendTimeout
,
TxSendTimeout
:
defaults
.
TxSendTimeout
,
...
@@ -189,6 +201,9 @@ func (m CLIConfig) Check() error {
...
@@ -189,6 +201,9 @@ func (m CLIConfig) Check() error {
if
m
.
NetworkTimeout
==
0
{
if
m
.
NetworkTimeout
==
0
{
return
errors
.
New
(
"must provide NetworkTimeout"
)
return
errors
.
New
(
"must provide NetworkTimeout"
)
}
}
if
m
.
FeeLimitMultiplier
==
0
{
return
errors
.
New
(
"must provide FeeLimitMultiplier"
)
}
if
m
.
ResubmissionTimeout
==
0
{
if
m
.
ResubmissionTimeout
==
0
{
return
errors
.
New
(
"must provide ResubmissionTimeout"
)
return
errors
.
New
(
"must provide ResubmissionTimeout"
)
}
}
...
@@ -218,6 +233,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
...
@@ -218,6 +233,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig {
SignerCLIConfig
:
opsigner
.
ReadCLIConfig
(
ctx
),
SignerCLIConfig
:
opsigner
.
ReadCLIConfig
(
ctx
),
NumConfirmations
:
ctx
.
Uint64
(
NumConfirmationsFlagName
),
NumConfirmations
:
ctx
.
Uint64
(
NumConfirmationsFlagName
),
SafeAbortNonceTooLowCount
:
ctx
.
Uint64
(
SafeAbortNonceTooLowCountFlagName
),
SafeAbortNonceTooLowCount
:
ctx
.
Uint64
(
SafeAbortNonceTooLowCountFlagName
),
FeeLimitMultiplier
:
ctx
.
Uint64
(
FeeLimitMultiplierFlagName
),
ResubmissionTimeout
:
ctx
.
Duration
(
ResubmissionTimeoutFlagName
),
ResubmissionTimeout
:
ctx
.
Duration
(
ResubmissionTimeoutFlagName
),
ReceiptQueryInterval
:
ctx
.
Duration
(
ReceiptQueryIntervalFlagName
),
ReceiptQueryInterval
:
ctx
.
Duration
(
ReceiptQueryIntervalFlagName
),
NetworkTimeout
:
ctx
.
Duration
(
NetworkTimeoutFlagName
),
NetworkTimeout
:
ctx
.
Duration
(
NetworkTimeoutFlagName
),
...
@@ -261,6 +277,7 @@ func NewConfig(cfg CLIConfig, l log.Logger) (Config, error) {
...
@@ -261,6 +277,7 @@ func NewConfig(cfg CLIConfig, l log.Logger) (Config, error) {
return
Config
{
return
Config
{
Backend
:
l1
,
Backend
:
l1
,
ResubmissionTimeout
:
cfg
.
ResubmissionTimeout
,
ResubmissionTimeout
:
cfg
.
ResubmissionTimeout
,
FeeLimitMultiplier
:
cfg
.
FeeLimitMultiplier
,
ChainID
:
chainID
,
ChainID
:
chainID
,
TxSendTimeout
:
cfg
.
TxSendTimeout
,
TxSendTimeout
:
cfg
.
TxSendTimeout
,
TxNotInMempoolTimeout
:
cfg
.
TxNotInMempoolTimeout
,
TxNotInMempoolTimeout
:
cfg
.
TxNotInMempoolTimeout
,
...
@@ -282,6 +299,9 @@ type Config struct {
...
@@ -282,6 +299,9 @@ type Config struct {
// attempted.
// attempted.
ResubmissionTimeout
time
.
Duration
ResubmissionTimeout
time
.
Duration
// The multiplier applied to fee suggestions to put a hard limit on fee increases.
FeeLimitMultiplier
uint64
// ChainID is the chain ID of the L1 chain.
// ChainID is the chain ID of the L1 chain.
ChainID
*
big
.
Int
ChainID
*
big
.
Int
...
@@ -326,6 +346,9 @@ func (m Config) Check() error {
...
@@ -326,6 +346,9 @@ func (m Config) Check() error {
if
m
.
NetworkTimeout
==
0
{
if
m
.
NetworkTimeout
==
0
{
return
errors
.
New
(
"must provide NetworkTimeout"
)
return
errors
.
New
(
"must provide NetworkTimeout"
)
}
}
if
m
.
FeeLimitMultiplier
==
0
{
return
errors
.
New
(
"must provide FeeLimitMultiplier"
)
}
if
m
.
ResubmissionTimeout
==
0
{
if
m
.
ResubmissionTimeout
==
0
{
return
errors
.
New
(
"must provide ResubmissionTimeout"
)
return
errors
.
New
(
"must provide ResubmissionTimeout"
)
}
}
...
...
op-service/txmgr/send_state.go
View file @
753c36ca
...
@@ -26,6 +26,9 @@ type SendState struct {
...
@@ -26,6 +26,9 @@ type SendState struct {
// Counts of the different types of errors
// Counts of the different types of errors
successFullPublishCount
uint64
// nil error => tx made it to the mempool
successFullPublishCount
uint64
// nil error => tx made it to the mempool
safeAbortNonceTooLowCount
uint64
// nonce too low error
safeAbortNonceTooLowCount
uint64
// nonce too low error
// Miscellaneous tracking
bumpCount
int
// number of times we have bumped the gas price
}
}
// NewSendStateWithNow creates a new send state with the provided clock.
// NewSendStateWithNow creates a new send state with the provided clock.
...
...
op-service/txmgr/txmgr.go
View file @
753c36ca
...
@@ -24,9 +24,6 @@ import (
...
@@ -24,9 +24,6 @@ import (
const
(
const
(
// Geth requires a minimum fee bump of 10% for tx resubmission
// Geth requires a minimum fee bump of 10% for tx resubmission
priceBump
int64
=
10
priceBump
int64
=
10
// The multiplier applied to fee suggestions to put a hard limit on fee increases
feeLimitMultiplier
=
5
)
)
// new = old * (100 + priceBump) / 100
// new = old * (100 + priceBump) / 100
...
@@ -297,19 +294,17 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
...
@@ -297,19 +294,17 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
sendState
:=
NewSendState
(
m
.
cfg
.
SafeAbortNonceTooLowCount
,
m
.
cfg
.
TxNotInMempoolTimeout
)
sendState
:=
NewSendState
(
m
.
cfg
.
SafeAbortNonceTooLowCount
,
m
.
cfg
.
TxNotInMempoolTimeout
)
receiptChan
:=
make
(
chan
*
types
.
Receipt
,
1
)
receiptChan
:=
make
(
chan
*
types
.
Receipt
,
1
)
sendTxAsync
:=
func
(
tx
*
types
.
Transaction
)
{
sendTx
:=
func
(
tx
*
types
.
Transaction
,
bumpFees
bool
)
*
types
.
Transaction
{
defer
wg
.
Done
()
return
m
.
publishAndWaitForTx
(
ctx
,
tx
,
sendState
,
receiptChan
,
bumpFees
,
wg
.
Done
)
m
.
publishAndWaitForTx
(
ctx
,
tx
,
sendState
,
receiptChan
)
}
}
// Immediately publish a transaction before starting the resumbission loop
// Immediately publish a transaction before starting the resumbission loop
wg
.
Add
(
1
)
wg
.
Add
(
1
)
go
sendTxAsync
(
tx
)
tx
=
sendTx
(
tx
,
false
)
ticker
:=
time
.
NewTicker
(
m
.
cfg
.
ResubmissionTimeout
)
ticker
:=
time
.
NewTicker
(
m
.
cfg
.
ResubmissionTimeout
)
defer
ticker
.
Stop
()
defer
ticker
.
Stop
()
bumpCounter
:=
0
for
{
for
{
select
{
select
{
case
<-
ticker
.
C
:
case
<-
ticker
.
C
:
...
@@ -322,25 +317,14 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
...
@@ -322,25 +317,14 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
m
.
l
.
Warn
(
"Aborting transaction submission"
)
m
.
l
.
Warn
(
"Aborting transaction submission"
)
return
nil
,
errors
.
New
(
"aborted transaction sending"
)
return
nil
,
errors
.
New
(
"aborted transaction sending"
)
}
}
// Increase the gas price & submit the new transaction
newTx
,
err
:=
m
.
increaseGasPrice
(
ctx
,
tx
)
if
err
!=
nil
||
sendState
.
IsWaitingForConfirmation
()
{
// there is a chance the previous tx goes into "waiting for confirmation" state
// during the increaseGasPrice call. In some (but not all) cases increaseGasPrice
// will error out during gas estimation. In either case we should continue waiting
// rather than resubmit the tx.
continue
}
tx
=
newTx
wg
.
Add
(
1
)
wg
.
Add
(
1
)
bumpCounter
+=
1
tx
=
sendTx
(
tx
,
true
)
go
sendTxAsync
(
tx
)
case
<-
ctx
.
Done
()
:
case
<-
ctx
.
Done
()
:
return
nil
,
ctx
.
Err
()
return
nil
,
ctx
.
Err
()
case
receipt
:=
<-
receiptChan
:
case
receipt
:=
<-
receiptChan
:
m
.
metr
.
RecordGasBumpCount
(
bumpCounter
)
m
.
metr
.
RecordGasBumpCount
(
sendState
.
bumpCount
)
m
.
metr
.
TxConfirmed
(
receipt
)
m
.
metr
.
TxConfirmed
(
receipt
)
return
receipt
,
nil
return
receipt
,
nil
}
}
...
@@ -350,57 +334,101 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
...
@@ -350,57 +334,101 @@ func (m *SimpleTxManager) sendTx(ctx context.Context, tx *types.Transaction) (*t
// publishAndWaitForTx publishes the transaction to the transaction pool and then waits for it with [waitMined].
// publishAndWaitForTx publishes the transaction to the transaction pool and then waits for it with [waitMined].
// It should be called in a new go-routine. It will send the receipt to receiptChan in a non-blocking way if a receipt is found
// It should be called in a new go-routine. It will send the receipt to receiptChan in a non-blocking way if a receipt is found
// for the transaction.
// for the transaction.
func
(
m
*
SimpleTxManager
)
publishAndWaitForTx
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
,
sendState
*
SendState
,
receiptChan
chan
*
types
.
Receipt
)
{
func
(
m
*
SimpleTxManager
)
publishAndWaitForTx
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
,
sendState
*
SendState
,
receiptChan
chan
*
types
.
Receipt
,
bumpFees
bool
,
done
func
())
*
types
.
Transaction
{
log
:=
m
.
l
.
New
(
"hash"
,
tx
.
Hash
(),
"nonce"
,
tx
.
Nonce
(),
"gasTipCap"
,
tx
.
GasTipCap
(),
"gasFeeCap"
,
tx
.
GasFeeCap
())
waiting
:=
false
log
.
Info
(
"Publishing transaction"
)
defer
func
()
{
if
!
waiting
{
done
()
}
}()
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
m
.
cfg
.
NetworkTimeout
)
updateLogFields
:=
func
(
tx
*
types
.
Transaction
)
log
.
Logger
{
defer
cancel
()
return
m
.
l
.
New
(
"hash"
,
tx
.
Hash
(),
"nonce"
,
tx
.
Nonce
(),
"gasTipCap"
,
tx
.
GasTipCap
(),
"gasFeeCap"
,
tx
.
GasFeeCap
())
}
l
:=
updateLogFields
(
tx
)
l
.
Info
(
"Publishing transaction"
)
t
:=
time
.
Now
()
t
:=
time
.
Now
()
err
:=
m
.
backend
.
SendTransaction
(
cCtx
,
tx
)
sendState
.
ProcessSendError
(
err
)
// Properly log & exit if there is an error
for
{
if
err
!=
nil
{
if
bumpFees
{
newTx
,
err
:=
m
.
increaseGasPrice
(
ctx
,
tx
)
if
err
!=
nil
{
l
.
Error
(
"unable to increase gas"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"bump_failed"
)
return
tx
}
tx
=
newTx
sendState
.
bumpCount
++
l
=
updateLogFields
(
tx
)
}
bumpFees
=
true
// bump fees next loop
if
sendState
.
IsWaitingForConfirmation
()
{
// there is a chance the previous tx goes into "waiting for confirmation" state
// during the increaseGasPrice call; continue waiting rather than resubmit the tx
return
tx
}
cCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
m
.
cfg
.
NetworkTimeout
)
err
:=
m
.
backend
.
SendTransaction
(
cCtx
,
tx
)
cancel
()
sendState
.
ProcessSendError
(
err
)
if
err
==
nil
{
break
}
switch
{
switch
{
case
errStringMatch
(
err
,
core
.
ErrNonceTooLow
)
:
case
errStringMatch
(
err
,
core
.
ErrNonceTooLow
)
:
l
og
.
Warn
(
"nonce too low"
,
"err"
,
err
)
l
.
Warn
(
"nonce too low"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"nonce_to_low"
)
m
.
metr
.
TxPublished
(
"nonce_to_low"
)
case
errStringMatch
(
err
,
context
.
Canceled
)
:
case
errStringMatch
(
err
,
context
.
Canceled
)
:
m
.
metr
.
RPCError
()
m
.
metr
.
RPCError
()
l
og
.
Warn
(
"transaction send cancelled"
,
"err"
,
err
)
l
.
Warn
(
"transaction send cancelled"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"context_cancelled"
)
m
.
metr
.
TxPublished
(
"context_cancelled"
)
case
errStringMatch
(
err
,
txpool
.
ErrAlreadyKnown
)
:
case
errStringMatch
(
err
,
txpool
.
ErrAlreadyKnown
)
:
l
og
.
Warn
(
"resubmitted already known transaction"
,
"err"
,
err
)
l
.
Warn
(
"resubmitted already known transaction"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"tx_already_known"
)
m
.
metr
.
TxPublished
(
"tx_already_known"
)
case
errStringMatch
(
err
,
txpool
.
ErrReplaceUnderpriced
)
:
case
errStringMatch
(
err
,
txpool
.
ErrReplaceUnderpriced
)
:
l
og
.
Warn
(
"transaction replacement is underpriced"
,
"err"
,
err
)
l
.
Warn
(
"transaction replacement is underpriced"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"tx_replacement_underpriced"
)
m
.
metr
.
TxPublished
(
"tx_replacement_underpriced"
)
continue
// retry with fee bump
case
errStringMatch
(
err
,
txpool
.
ErrUnderpriced
)
:
case
errStringMatch
(
err
,
txpool
.
ErrUnderpriced
)
:
l
og
.
Warn
(
"transaction is underpriced"
,
"err"
,
err
)
l
.
Warn
(
"transaction is underpriced"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"tx_underpriced"
)
m
.
metr
.
TxPublished
(
"tx_underpriced"
)
continue
// retry with fee bump
default
:
default
:
m
.
metr
.
RPCError
()
m
.
metr
.
RPCError
()
l
og
.
Error
(
"unable to publish transaction"
,
"err"
,
err
)
l
.
Error
(
"unable to publish transaction"
,
"err"
,
err
)
m
.
metr
.
TxPublished
(
"unknown_error"
)
m
.
metr
.
TxPublished
(
"unknown_error"
)
}
}
return
// on non-underpriced error return immediately; will retry on next resubmission timeout
return
tx
}
}
m
.
metr
.
TxPublished
(
""
)
m
.
metr
.
TxPublished
(
""
)
log
.
Info
(
"Transaction successfully published"
)
log
.
Info
(
"Transaction successfully published"
)
// Poll for the transaction to be ready & then send the result to receiptChan
receipt
,
err
:=
m
.
waitMined
(
ctx
,
tx
,
sendState
)
waiting
=
true
if
err
!=
nil
{
go
func
()
{
// this will happen if the tx was successfully replaced by a tx with bumped fees
defer
done
()
log
.
Info
(
"Transaction receipt not found"
,
"err"
,
err
)
// Poll for the transaction to be ready & then send the result to receiptChan
return
receipt
,
err
:=
m
.
waitMined
(
ctx
,
tx
,
sendState
)
}
if
err
!=
nil
{
select
{
// this will happen if the tx was successfully replaced by a tx with bumped fees
case
receiptChan
<-
receipt
:
log
.
Info
(
"Transaction receipt not found"
,
"err"
,
err
)
m
.
metr
.
RecordTxConfirmationLatency
(
time
.
Since
(
t
)
.
Milliseconds
())
return
default
:
}
}
select
{
case
receiptChan
<-
receipt
:
m
.
metr
.
RecordTxConfirmationLatency
(
time
.
Since
(
t
)
.
Milliseconds
())
default
:
}
}()
return
tx
}
}
// waitMined waits for the transaction to be mined or for the context to be cancelled.
// waitMined waits for the transaction to be mined or for the context to be cancelled.
...
@@ -485,15 +513,13 @@ func (m *SimpleTxManager) increaseGasPrice(ctx context.Context, tx *types.Transa
...
@@ -485,15 +513,13 @@ func (m *SimpleTxManager) increaseGasPrice(ctx context.Context, tx *types.Transa
bumpedTip
,
bumpedFee
:=
updateFees
(
tx
.
GasTipCap
(),
tx
.
GasFeeCap
(),
tip
,
basefee
,
m
.
l
)
bumpedTip
,
bumpedFee
:=
updateFees
(
tx
.
GasTipCap
(),
tx
.
GasFeeCap
(),
tip
,
basefee
,
m
.
l
)
// Make sure increase is at most 5x the suggested values
// Make sure increase is at most 5x the suggested values
maxTip
:=
new
(
big
.
Int
)
.
Mul
(
tip
,
big
.
NewInt
(
feeLimitMultiplier
))
maxTip
:=
new
(
big
.
Int
)
.
Mul
(
tip
,
big
.
NewInt
(
int64
(
m
.
cfg
.
FeeLimitMultiplier
)
))
if
bumpedTip
.
Cmp
(
maxTip
)
>
0
{
if
bumpedTip
.
Cmp
(
maxTip
)
>
0
{
m
.
l
.
Warn
(
fmt
.
Sprintf
(
"bumped tip getting capped at %dx multiple of the suggested value"
,
feeLimitMultiplier
),
"bumped"
,
bumpedTip
,
"suggestion"
,
tip
)
return
nil
,
fmt
.
Errorf
(
"bumped tip 0x%s is over %dx multiple of the suggested value"
,
bumpedTip
.
Text
(
16
),
m
.
cfg
.
FeeLimitMultiplier
)
bumpedTip
.
Set
(
maxTip
)
}
}
maxFee
:=
calcGasFeeCap
(
new
(
big
.
Int
)
.
Mul
(
basefee
,
big
.
NewInt
(
feeLimitMultiplier
)),
maxTip
)
maxFee
:=
calcGasFeeCap
(
new
(
big
.
Int
)
.
Mul
(
basefee
,
big
.
NewInt
(
int64
(
m
.
cfg
.
FeeLimitMultiplier
)
)),
maxTip
)
if
bumpedFee
.
Cmp
(
maxFee
)
>
0
{
if
bumpedFee
.
Cmp
(
maxFee
)
>
0
{
m
.
l
.
Warn
(
"bumped fee getting capped at multiple of the implied suggested value"
,
"bumped"
,
bumpedFee
,
"suggestion"
,
maxFee
)
return
nil
,
fmt
.
Errorf
(
"bumped fee 0x%s is over %dx multiple of the suggested value"
,
bumpedFee
.
Text
(
16
),
m
.
cfg
.
FeeLimitMultiplier
)
bumpedFee
.
Set
(
maxFee
)
}
}
rawTx
:=
&
types
.
DynamicFeeTx
{
rawTx
:=
&
types
.
DynamicFeeTx
{
ChainID
:
tx
.
ChainId
(),
ChainID
:
tx
.
ChainId
(),
...
...
op-service/txmgr/txmgr_test.go
View file @
753c36ca
...
@@ -80,6 +80,7 @@ func configWithNumConfs(numConfirmations uint64) Config {
...
@@ -80,6 +80,7 @@ func configWithNumConfs(numConfirmations uint64) Config {
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
NumConfirmations
:
numConfirmations
,
NumConfirmations
:
numConfirmations
,
SafeAbortNonceTooLowCount
:
3
,
SafeAbortNonceTooLowCount
:
3
,
FeeLimitMultiplier
:
5
,
TxNotInMempoolTimeout
:
1
*
time
.
Hour
,
TxNotInMempoolTimeout
:
1
*
time
.
Hour
,
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
tx
,
nil
return
tx
,
nil
...
@@ -766,6 +767,7 @@ func doGasPriceIncrease(t *testing.T, txTipCap, txFeeCap, newTip, newBaseFee int
...
@@ -766,6 +767,7 @@ func doGasPriceIncrease(t *testing.T, txTipCap, txFeeCap, newTip, newBaseFee int
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
NumConfirmations
:
1
,
NumConfirmations
:
1
,
SafeAbortNonceTooLowCount
:
3
,
SafeAbortNonceTooLowCount
:
3
,
FeeLimitMultiplier
:
5
,
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
tx
,
nil
return
tx
,
nil
},
},
...
@@ -867,6 +869,7 @@ func TestIncreaseGasPriceNotExponential(t *testing.T) {
...
@@ -867,6 +869,7 @@ func TestIncreaseGasPriceNotExponential(t *testing.T) {
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
ReceiptQueryInterval
:
50
*
time
.
Millisecond
,
NumConfirmations
:
1
,
NumConfirmations
:
1
,
SafeAbortNonceTooLowCount
:
3
,
SafeAbortNonceTooLowCount
:
3
,
FeeLimitMultiplier
:
5
,
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
Signer
:
func
(
ctx
context
.
Context
,
from
common
.
Address
,
tx
*
types
.
Transaction
)
(
*
types
.
Transaction
,
error
)
{
return
tx
,
nil
return
tx
,
nil
},
},
...
@@ -883,23 +886,20 @@ func TestIncreaseGasPriceNotExponential(t *testing.T) {
...
@@ -883,23 +886,20 @@ func TestIncreaseGasPriceNotExponential(t *testing.T) {
})
})
// Run IncreaseGasPrice a bunch of times in a row to simulate a very fast resubmit loop.
// Run IncreaseGasPrice a bunch of times in a row to simulate a very fast resubmit loop.
var
err
error
ctx
:=
context
.
Background
()
for
i
:=
0
;
i
<
30
;
i
++
{
for
{
ctx
:=
context
.
Background
()
newTx
,
err
:=
mgr
.
increaseGasPrice
(
ctx
,
tx
)
tx
,
err
=
mgr
.
increaseGasPrice
(
ctx
,
tx
)
if
err
!=
nil
{
require
.
NoError
(
t
,
err
)
break
}
tx
=
newTx
}
}
lastTip
,
lastFee
:=
tx
.
GasTipCap
(),
tx
.
GasFeeCap
()
lastTip
,
lastFee
:=
tx
.
GasTipCap
(),
tx
.
GasFeeCap
()
require
.
Equal
(
t
,
lastTip
.
Int64
(),
feeLimitMultiplier
*
borkedTip
)
require
.
Equal
(
t
,
lastTip
.
Int64
(),
int64
(
36
)
)
require
.
Equal
(
t
,
lastFee
.
Int64
(),
feeLimitMultiplier
*
(
borkedTip
+
2
*
borkedFee
))
require
.
Equal
(
t
,
lastFee
.
Int64
(),
int64
(
493
))
// Confirm that fees stop rising
// Confirm that fees stop rising
for
i
:=
0
;
i
<
5
;
i
++
{
_
,
err
:=
mgr
.
increaseGasPrice
(
ctx
,
tx
)
ctx
:=
context
.
Background
()
require
.
Error
(
t
,
err
)
tx
,
err
:=
mgr
.
increaseGasPrice
(
ctx
,
tx
)
require
.
NoError
(
t
,
err
)
require
.
True
(
t
,
tx
.
GasTipCap
()
.
Cmp
(
lastTip
)
==
0
,
"suggested tx tip must stop increasing"
)
require
.
True
(
t
,
tx
.
GasFeeCap
()
.
Cmp
(
lastFee
)
==
0
,
"suggested tx fee must stop increasing"
)
}
}
}
func
TestErrStringMatch
(
t
*
testing
.
T
)
{
func
TestErrStringMatch
(
t
*
testing
.
T
)
{
...
...
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