Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
feat(all): use an unified transaction sender implementation (#560)
Browse files Browse the repository at this point in the history
Co-authored-by: David <[email protected]>
  • Loading branch information
mask-pp and davidtaikocha committed Feb 25, 2024
1 parent e70b7a0 commit 1bd56c0
Show file tree
Hide file tree
Showing 13 changed files with 859 additions and 194 deletions.
22 changes: 16 additions & 6 deletions driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,10 @@ func (s *DriverTestSuite) TestProcessL1Blocks() {
}

func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() {
var testnetL1SnapshotID = s.SetL1Snapshot()

var (
testnetL1SnapshotID = s.SetL1Snapshot()
sender = s.p.GetSender()
)
l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil)
s.Nil(err)
l2Head1, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
Expand Down Expand Up @@ -164,6 +166,8 @@ func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() {
s.Equal(l1Head3.Number.Uint64(), l1Head1.Number.Uint64())
s.Equal(l1Head3.Hash(), l1Head1.Hash())

// Because of evm_revert operation, the nonce of the proposer need to be adjusted.
sender.AdjustNonce(nil)
// Propose ten blocks on another fork
for i := 0; i < 10; i++ {
s.ProposeInvalidTxListBytes(s.p)
Expand All @@ -188,8 +192,10 @@ func (s *DriverTestSuite) TestCheckL1ReorgToHigherFork() {
}

func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() {
var testnetL1SnapshotID = s.SetL1Snapshot()

var (
testnetL1SnapshotID = s.SetL1Snapshot()
sender = s.p.GetSender()
)
l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil)
s.Nil(err)
l2Head1, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
Expand Down Expand Up @@ -223,6 +229,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() {
s.Equal(l1Head3.Number.Uint64(), l1Head1.Number.Uint64())
s.Equal(l1Head3.Hash(), l1Head1.Hash())

sender.AdjustNonce(nil)
// Propose one blocks on another fork
s.ProposeInvalidTxListBytes(s.p)

Expand All @@ -244,8 +251,10 @@ func (s *DriverTestSuite) TestCheckL1ReorgToLowerFork() {
}

func (s *DriverTestSuite) TestCheckL1ReorgToSameHeightFork() {
var testnetL1SnapshotID = s.SetL1Snapshot()

var (
testnetL1SnapshotID = s.SetL1Snapshot()
sender = s.p.GetSender()
)
l1Head1, err := s.d.rpc.L1.HeaderByNumber(context.Background(), nil)
s.Nil(err)
l2Head1, err := s.d.rpc.L2.HeaderByNumber(context.Background(), nil)
Expand Down Expand Up @@ -279,6 +288,7 @@ func (s *DriverTestSuite) TestCheckL1ReorgToSameHeightFork() {
s.Equal(l1Head3.Number.Uint64(), l1Head1.Number.Uint64())
s.Equal(l1Head3.Hash(), l1Head1.Hash())

sender.AdjustNonce(nil)
// Propose two blocks on another fork
s.ProposeInvalidTxListBytes(s.p)
time.Sleep(3 * time.Second)
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ require (
github.com/joho/godotenv v1.5.1
github.com/labstack/echo/v4 v4.11.1
github.com/modern-go/reflect2 v1.0.2
github.com/orcaman/concurrent-map/v2 v2.0.1
github.com/pborman/uuid v1.2.1
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/prysmaticlabs/prysm/v4 v4.2.0
github.com/stretchr/testify v1.8.4
github.com/swaggo/swag v1.16.2
github.com/urfave/cli/v2 v2.25.7
golang.org/x/sync v0.5.0
modernc.org/mathutil v1.6.0
)

require (
Expand Down Expand Up @@ -79,7 +82,7 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
Expand Down Expand Up @@ -164,6 +167,7 @@ require (
github.com/quic-go/quic-go v0.39.3 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/cors v1.7.0 // indirect
Expand Down
12 changes: 10 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -442,8 +442,8 @@ github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
Expand Down Expand Up @@ -797,13 +797,17 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
Expand Down Expand Up @@ -887,6 +891,8 @@ github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtB
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
Expand Down Expand Up @@ -1648,6 +1654,8 @@ k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
Expand Down
202 changes: 202 additions & 0 deletions internal/sender/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package sender

import (
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/holiman/uint256"
"github.com/pborman/uuid"
"modernc.org/mathutil"

"github.com/taikoxyz/taiko-client/pkg/rpc"
)

// adjustGas adjusts the gas fee cap and gas tip cap of the given transaction with the configured
// growth rate.
func (s *Sender) adjustGas(txData types.TxData) {
rate := s.GasGrowthRate + 100
switch baseTx := txData.(type) {
case *types.DynamicFeeTx:
gasFeeCap := baseTx.GasFeeCap.Int64()
gasFeeCap = gasFeeCap / 100 * int64(rate)
gasFeeCap = mathutil.MinInt64(gasFeeCap, int64(s.MaxGasFee))
baseTx.GasFeeCap = big.NewInt(gasFeeCap)

gasTipCap := baseTx.GasTipCap.Int64()
gasTipCap = gasTipCap / 100 * int64(rate)
gasTipCap = mathutil.MinInt64(gasFeeCap, mathutil.MinInt64(gasTipCap, int64(s.MaxGasFee)))
baseTx.GasTipCap = big.NewInt(gasTipCap)
case *types.BlobTx:
gasFeeCap := baseTx.GasFeeCap.Uint64()
gasFeeCap = gasFeeCap / 100 * rate
gasFeeCap = mathutil.MinUint64(gasFeeCap, s.MaxGasFee)
baseTx.GasFeeCap = uint256.NewInt(gasFeeCap)

gasTipCap := baseTx.GasTipCap.Uint64()
gasTipCap = gasTipCap / 100 * rate
gasTipCap = mathutil.MinUint64(gasFeeCap, mathutil.MinUint64(gasTipCap, s.MaxGasFee))
baseTx.GasTipCap = uint256.NewInt(gasTipCap)

blobFeeCap := baseTx.BlobFeeCap.Uint64()
blobFeeCap = blobFeeCap / 100 * rate
blobFeeCap = mathutil.MinUint64(blobFeeCap, s.MaxBlobFee)
baseTx.BlobFeeCap = uint256.NewInt(blobFeeCap)
}
}

// AdjustNonce adjusts the nonce of the given transaction with the current nonce of the sender.
func (s *Sender) AdjustNonce(txData types.TxData) {
nonce, err := s.client.NonceAt(s.ctx, s.Opts.From, nil)
if err != nil {
log.Warn("Failed to get the nonce", "from", s.Opts.From, "err", err)
return
}
s.Opts.Nonce = new(big.Int).SetUint64(nonce)

switch tx := txData.(type) {
case *types.DynamicFeeTx:
tx.Nonce = nonce
case *types.BlobTx:
tx.Nonce = nonce
default:
log.Warn("Unsupported transaction type", "from", s.Opts.From)
}
}

// updateGasTipGasFee updates the gas tip cap and gas fee cap of the sender with the given chain head info.
func (s *Sender) updateGasTipGasFee(head *types.Header) error {
// Get the gas tip cap
gasTipCap, err := s.client.SuggestGasTipCap(s.ctx)
if err != nil {
return err
}

// Get the gas fee cap
gasFeeCap := new(big.Int).Add(gasTipCap, new(big.Int).Mul(head.BaseFee, big.NewInt(2)))
// Check if the gas fee cap is less than the gas tip cap
if gasFeeCap.Cmp(gasTipCap) < 0 {
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", gasFeeCap, gasTipCap)
}
maxGasFee := new(big.Int).SetUint64(s.MaxGasFee)
if gasFeeCap.Cmp(maxGasFee) > 0 {
gasFeeCap = new(big.Int).Set(maxGasFee)
gasTipCap = new(big.Int).Set(maxGasFee)
}

s.Opts.GasTipCap = gasTipCap
s.Opts.GasFeeCap = gasFeeCap

return nil
}

// buildTxData assembles the transaction data from the given transaction.
func (s *Sender) buildTxData(tx *types.Transaction) (types.TxData, error) {
switch tx.Type() {
case types.DynamicFeeTxType:
return &types.DynamicFeeTx{
ChainID: s.client.ChainID,
To: tx.To(),
Nonce: tx.Nonce(),
GasFeeCap: s.Opts.GasFeeCap,
GasTipCap: s.Opts.GasTipCap,
Gas: tx.Gas(),
Value: tx.Value(),
Data: tx.Data(),
AccessList: tx.AccessList(),
}, nil
case types.BlobTxType:
var to common.Address
if tx.To() != nil {
to = *tx.To()
}
return &types.BlobTx{
ChainID: uint256.MustFromBig(s.client.ChainID),
To: to,
Nonce: tx.Nonce(),
GasFeeCap: uint256.MustFromBig(s.Opts.GasFeeCap),
GasTipCap: uint256.MustFromBig(s.Opts.GasTipCap),
Gas: tx.Gas(),
Value: uint256.MustFromBig(tx.Value()),
Data: tx.Data(),
AccessList: tx.AccessList(),
BlobFeeCap: uint256.MustFromBig(tx.BlobGasFeeCap()),
BlobHashes: tx.BlobHashes(),
Sidecar: tx.BlobTxSidecar(),
}, nil
default:
return nil, fmt.Errorf("unsupported transaction type: %v", tx.Type())
}
}

// handleReorgTransactions handles the transactions which are backed to the mempool due to reorg.
func (s *Sender) handleReorgTransactions() { // nolint: unused
content, err := rpc.Content(s.ctx, s.client)
if err != nil {
log.Warn("failed to get the unconfirmed transactions", "address", s.Opts.From.String(), "err", err)
return
}
if len(content) == 0 {
return
}

txs := map[common.Hash]*types.Transaction{}
for _, txMapStatus := range content {
for key, txMapNonce := range txMapStatus {
addr := common.HexToAddress(key)
if addr != s.Opts.From {
continue
}
for _, tx := range txMapNonce {
txs[tx.Hash()] = tx
}
}
}
// Remove the already handled transactions.
for _, confirm := range s.unconfirmedTxs.Items() {
delete(txs, confirm.CurrentTx.Hash())
}
for _, tx := range txs {
baseTx, err := s.buildTxData(tx)
if err != nil {
log.Warn("failed to make the transaction data when handle reorg txs", "tx_hash", tx.Hash().String(), "err", err)
return
}
txID := uuid.New()
confirm := &TxToConfirm{
ID: txID,
CurrentTx: tx,
originalTx: baseTx,
}
s.unconfirmedTxs.Set(txID, confirm)
s.txToConfirmCh.Set(txID, make(chan *TxToConfirm, 1))
log.Info("handle reorg tx", "tx_hash", tx.Hash().String(), "tx_id", txID)
}
}

// setDefault sets the default value if the given value is 0.
func setDefault[T uint64 | time.Duration](src, dest T) T {
if src == 0 {
return dest
}
return src
}

// setConfigWithDefaultValues sets the config with default values if the given config is nil.
func setConfigWithDefaultValues(config *Config) *Config {
if config == nil {
return DefaultConfig
}
return &Config{
ConfirmationDepth: setDefault(config.ConfirmationDepth, DefaultConfig.ConfirmationDepth),
MaxRetrys: setDefault(config.MaxRetrys, DefaultConfig.MaxRetrys),
MaxWaitingTime: setDefault(config.MaxWaitingTime, DefaultConfig.MaxWaitingTime),
GasLimit: setDefault(config.GasLimit, DefaultConfig.GasLimit),
GasGrowthRate: setDefault(config.GasGrowthRate, DefaultConfig.GasGrowthRate),
MaxGasFee: setDefault(config.MaxGasFee, DefaultConfig.MaxGasFee),
MaxBlobFee: setDefault(config.MaxBlobFee, DefaultConfig.MaxBlobFee),
}
}
Loading

0 comments on commit 1bd56c0

Please sign in to comment.