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
4bc2c019
Unverified
Commit
4bc2c019
authored
Mar 17, 2022
by
Matthew Slipper
Committed by
GitHub
Mar 17, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2338 from cfromknecht/bss-core-txmgr-error-revert
feat: txmgr return ErrReverted if confirmed tx reverts
parents
e8aa162c
6856b215
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
87 additions
and
5 deletions
+87
-5
lucky-cameras-grin.md
.changeset/lucky-cameras-grin.md
+6
-0
clear_pending_tx_test.go
go/bss-core/drivers/clear_pending_tx_test.go
+2
-0
service.go
go/bss-core/service.go
+12
-4
txmgr.go
go/bss-core/txmgr/txmgr.go
+11
-1
txmgr_test.go
go/bss-core/txmgr/txmgr_test.go
+56
-0
No files found.
.changeset/lucky-cameras-grin.md
0 → 100644
View file @
4bc2c019
---
'
@eth-optimism/batch-submitter-service'
:
patch
'
@eth-optimism/teleportr'
:
patch
---
Count reverted transactions in failed_submissions
go/bss-core/drivers/clear_pending_tx_test.go
View file @
4bc2c019
...
@@ -231,6 +231,7 @@ func TestClearPendingTxClearingTxConfirms(t *testing.T) {
...
@@ -231,6 +231,7 @@ func TestClearPendingTxClearingTxConfirms(t *testing.T) {
return
&
types
.
Receipt
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
TxHash
:
txHash
,
BlockNumber
:
big
.
NewInt
(
int64
(
testBlockNumber
)),
BlockNumber
:
big
.
NewInt
(
int64
(
testBlockNumber
)),
Status
:
types
.
ReceiptStatusSuccessful
,
},
nil
},
nil
},
},
})
})
...
@@ -296,6 +297,7 @@ func TestClearPendingTxMultipleConfs(t *testing.T) {
...
@@ -296,6 +297,7 @@ func TestClearPendingTxMultipleConfs(t *testing.T) {
return
&
types
.
Receipt
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
TxHash
:
txHash
,
BlockNumber
:
big
.
NewInt
(
int64
(
testBlockNumber
)),
BlockNumber
:
big
.
NewInt
(
int64
(
testBlockNumber
)),
Status
:
types
.
ReceiptStatusSuccessful
,
},
nil
},
nil
},
},
},
numConfs
)
},
numConfs
)
...
...
go/bss-core/service.go
View file @
4bc2c019
...
@@ -215,6 +215,18 @@ func (s *Service) eventLoop() {
...
@@ -215,6 +215,18 @@ func (s *Service) eventLoop() {
receipt
,
err
:=
s
.
txMgr
.
Send
(
receipt
,
err
:=
s
.
txMgr
.
Send
(
s
.
ctx
,
updateGasPrice
,
s
.
cfg
.
Driver
.
SendTransaction
,
s
.
ctx
,
updateGasPrice
,
s
.
cfg
.
Driver
.
SendTransaction
,
)
)
// Record the confirmation time and gas used if we receive a
// receipt, as this indicates the transaction confirmed. We record
// these metrics here as the transaction may have reverted, and will
// abort below.
if
receipt
!=
nil
{
batchConfirmationTime
:=
time
.
Since
(
batchConfirmationStart
)
/
time
.
Millisecond
s
.
metrics
.
BatchConfirmationTimeMs
()
.
Set
(
float64
(
batchConfirmationTime
))
s
.
metrics
.
SubmissionGasUsedWei
()
.
Set
(
float64
(
receipt
.
GasUsed
))
}
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
name
+
" unable to publish batch tx"
,
log
.
Error
(
name
+
" unable to publish batch tx"
,
"err"
,
err
)
"err"
,
err
)
...
@@ -225,11 +237,7 @@ func (s *Service) eventLoop() {
...
@@ -225,11 +237,7 @@ func (s *Service) eventLoop() {
// The transaction was successfully submitted.
// The transaction was successfully submitted.
log
.
Info
(
name
+
" batch tx successfully published"
,
log
.
Info
(
name
+
" batch tx successfully published"
,
"tx_hash"
,
receipt
.
TxHash
)
"tx_hash"
,
receipt
.
TxHash
)
batchConfirmationTime
:=
time
.
Since
(
batchConfirmationStart
)
/
time
.
Millisecond
s
.
metrics
.
BatchConfirmationTimeMs
()
.
Set
(
float64
(
batchConfirmationTime
))
s
.
metrics
.
BatchesSubmitted
()
.
Inc
()
s
.
metrics
.
BatchesSubmitted
()
.
Inc
()
s
.
metrics
.
SubmissionGasUsedWei
()
.
Set
(
float64
(
receipt
.
GasUsed
))
s
.
metrics
.
SubmissionTimestamp
()
.
Set
(
float64
(
time
.
Now
()
.
UnixNano
()
/
1e6
))
s
.
metrics
.
SubmissionTimestamp
()
.
Set
(
float64
(
time
.
Now
()
.
UnixNano
()
/
1e6
))
case
err
:=
<-
s
.
ctx
.
Done
()
:
case
err
:=
<-
s
.
ctx
.
Done
()
:
...
...
go/bss-core/txmgr/txmgr.go
View file @
4bc2c019
...
@@ -2,6 +2,7 @@ package txmgr
...
@@ -2,6 +2,7 @@ package txmgr
import
(
import
(
"context"
"context"
"errors"
"math/big"
"math/big"
"strings"
"strings"
"sync"
"sync"
...
@@ -12,6 +13,9 @@ import (
...
@@ -12,6 +13,9 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
)
)
// ErrReverted signals that a mined transaction reverted.
var
ErrReverted
=
errors
.
New
(
"transaction reverted"
)
// UpdateGasPriceSendTxFunc defines a function signature for publishing a
// UpdateGasPriceSendTxFunc defines a function signature for publishing a
// desired tx with a specific gas price. Implementations of this signature
// desired tx with a specific gas price. Implementations of this signature
// should also return promptly when the context is canceled.
// should also return promptly when the context is canceled.
...
@@ -225,6 +229,9 @@ func (m *SimpleTxManager) Send(
...
@@ -225,6 +229,9 @@ func (m *SimpleTxManager) Send(
// The transaction has confirmed.
// The transaction has confirmed.
case
receipt
:=
<-
receiptChan
:
case
receipt
:=
<-
receiptChan
:
if
receipt
.
Status
==
types
.
ReceiptStatusFailed
{
return
receipt
,
ErrReverted
}
return
receipt
,
nil
return
receipt
,
nil
}
}
}
}
...
@@ -288,7 +295,10 @@ func waitMined(
...
@@ -288,7 +295,10 @@ func waitMined(
// tipHeight. The equation is rewritten in this form to avoid
// tipHeight. The equation is rewritten in this form to avoid
// underflows.
// underflows.
if
txHeight
+
numConfirmations
<=
tipHeight
+
1
{
if
txHeight
+
numConfirmations
<=
tipHeight
+
1
{
log
.
Info
(
"Transaction confirmed"
,
"txHash"
,
txHash
)
reverted
:=
receipt
.
Status
==
types
.
ReceiptStatusFailed
log
.
Info
(
"Transaction confirmed"
,
"txHash"
,
txHash
,
"reverted"
,
reverted
)
return
receipt
,
nil
return
receipt
,
nil
}
}
...
...
go/bss-core/txmgr/txmgr_test.go
View file @
4bc2c019
...
@@ -98,6 +98,7 @@ func (g *gasPricer) sample() (*big.Int, *big.Int) {
...
@@ -98,6 +98,7 @@ func (g *gasPricer) sample() (*big.Int, *big.Int) {
type
minedTxInfo
struct
{
type
minedTxInfo
struct
{
gasFeeCap
*
big
.
Int
gasFeeCap
*
big
.
Int
blockNumber
uint64
blockNumber
uint64
reverted
bool
}
}
// mockBackend implements txmgr.ReceiptSource that tracks mined transactions
// mockBackend implements txmgr.ReceiptSource that tracks mined transactions
...
@@ -123,6 +124,20 @@ func newMockBackend() *mockBackend {
...
@@ -123,6 +124,20 @@ func newMockBackend() *mockBackend {
// TransactionReceipt with a matching txHash will result in a non-nil receipt.
// TransactionReceipt with a matching txHash will result in a non-nil receipt.
// If a nil txHash is supplied this has the effect of mining an empty block.
// If a nil txHash is supplied this has the effect of mining an empty block.
func
(
b
*
mockBackend
)
mine
(
txHash
*
common
.
Hash
,
gasFeeCap
*
big
.
Int
)
{
func
(
b
*
mockBackend
)
mine
(
txHash
*
common
.
Hash
,
gasFeeCap
*
big
.
Int
)
{
b
.
mineWithStatus
(
txHash
,
gasFeeCap
,
false
)
}
// mineWithStatus records a (txHash, gasFeeCap) pair as confirmed, but also
// includes the option to specify whether or not the transaction reverted.
// Subsequent calls to TransactionReceipt with a matching txHash will result in
// a non-nil receipt. If a nil txHash is supplied this has the effect of mining
// an empty block.
func
(
b
*
mockBackend
)
mineWithStatus
(
txHash
*
common
.
Hash
,
gasFeeCap
*
big
.
Int
,
revert
bool
,
)
{
b
.
mu
.
Lock
()
b
.
mu
.
Lock
()
defer
b
.
mu
.
Unlock
()
defer
b
.
mu
.
Unlock
()
...
@@ -131,6 +146,7 @@ func (b *mockBackend) mine(txHash *common.Hash, gasFeeCap *big.Int) {
...
@@ -131,6 +146,7 @@ func (b *mockBackend) mine(txHash *common.Hash, gasFeeCap *big.Int) {
b
.
minedTxs
[
*
txHash
]
=
minedTxInfo
{
b
.
minedTxs
[
*
txHash
]
=
minedTxInfo
{
gasFeeCap
:
gasFeeCap
,
gasFeeCap
:
gasFeeCap
,
blockNumber
:
b
.
blockHeight
,
blockNumber
:
b
.
blockHeight
,
reverted
:
revert
,
}
}
}
}
}
}
...
@@ -160,12 +176,18 @@ func (b *mockBackend) TransactionReceipt(
...
@@ -160,12 +176,18 @@ func (b *mockBackend) TransactionReceipt(
return
nil
,
nil
return
nil
,
nil
}
}
var
status
=
types
.
ReceiptStatusSuccessful
if
txInfo
.
reverted
{
status
=
types
.
ReceiptStatusFailed
}
// Return the gas fee cap for the transaction in the GasUsed field so that
// Return the gas fee cap for the transaction in the GasUsed field so that
// we can assert the proper tx confirmed in our tests.
// we can assert the proper tx confirmed in our tests.
return
&
types
.
Receipt
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
TxHash
:
txHash
,
GasUsed
:
txInfo
.
gasFeeCap
.
Uint64
(),
GasUsed
:
txInfo
.
gasFeeCap
.
Uint64
(),
BlockNumber
:
big
.
NewInt
(
int64
(
txInfo
.
blockNumber
)),
BlockNumber
:
big
.
NewInt
(
int64
(
txInfo
.
blockNumber
)),
Status
:
status
,
},
nil
},
nil
}
}
...
@@ -201,6 +223,39 @@ func TestTxMgrConfirmAtMinGasPrice(t *testing.T) {
...
@@ -201,6 +223,39 @@ func TestTxMgrConfirmAtMinGasPrice(t *testing.T) {
require
.
Equal
(
t
,
gasPricer
.
expGasFeeCap
()
.
Uint64
(),
receipt
.
GasUsed
)
require
.
Equal
(
t
,
gasPricer
.
expGasFeeCap
()
.
Uint64
(),
receipt
.
GasUsed
)
}
}
// TestTxMgrFailsForRevertedTxn asserts that Send returns ErrReverted if the
// confirmed transaction reverts during execution, and returns the resulting
// receipt.
func
TestTxMgrFailsForRevertedTxn
(
t
*
testing
.
T
)
{
t
.
Parallel
()
h
:=
newTestHarness
()
gasPricer
:=
newGasPricer
(
1
)
updateGasPrice
:=
func
(
ctx
context
.
Context
)
(
*
types
.
Transaction
,
error
)
{
gasTipCap
,
gasFeeCap
:=
gasPricer
.
sample
()
return
types
.
NewTx
(
&
types
.
DynamicFeeTx
{
GasTipCap
:
gasTipCap
,
GasFeeCap
:
gasFeeCap
,
}),
nil
}
sendTx
:=
func
(
ctx
context
.
Context
,
tx
*
types
.
Transaction
)
error
{
if
gasPricer
.
shouldMine
(
tx
.
GasFeeCap
())
{
txHash
:=
tx
.
Hash
()
h
.
backend
.
mineWithStatus
(
&
txHash
,
tx
.
GasFeeCap
(),
true
)
}
return
nil
}
ctx
:=
context
.
Background
()
receipt
,
err
:=
h
.
mgr
.
Send
(
ctx
,
updateGasPrice
,
sendTx
)
require
.
Equal
(
t
,
txmgr
.
ErrReverted
,
err
)
require
.
NotNil
(
t
,
receipt
)
require
.
Equal
(
t
,
gasPricer
.
expGasFeeCap
()
.
Uint64
(),
receipt
.
GasUsed
)
}
// TestTxMgrNeverConfirmCancel asserts that a Send can be canceled even if no
// TestTxMgrNeverConfirmCancel asserts that a Send can be canceled even if no
// transaction is mined. This is done to ensure the the tx mgr can properly
// transaction is mined. This is done to ensure the the tx mgr can properly
// abort on shutdown, even if a txn is in the process of being published.
// abort on shutdown, even if a txn is in the process of being published.
...
@@ -519,6 +574,7 @@ func (b *failingBackend) TransactionReceipt(
...
@@ -519,6 +574,7 @@ func (b *failingBackend) TransactionReceipt(
return
&
types
.
Receipt
{
return
&
types
.
Receipt
{
TxHash
:
txHash
,
TxHash
:
txHash
,
BlockNumber
:
big
.
NewInt
(
1
),
BlockNumber
:
big
.
NewInt
(
1
),
Status
:
types
.
ReceiptStatusSuccessful
,
},
nil
},
nil
}
}
...
...
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