Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(devnet): better support of multiple preconfs in blocks #162

Merged
merged 19 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -102,23 +102,25 @@ dora:
fi

# manually send a preconfirmation to the bolt devnet
send-preconf:
send-preconf count='1':
cd bolt-spammer && RUST_LOG=info cargo run -- \
--provider-url $(kurtosis port print bolt-devnet el-1-geth-lighthouse rpc) \
--beacon-client-url $(kurtosis port print bolt-devnet cl-1-lighthouse-geth http) \
--bolt-sidecar-url http://$(kurtosis port print bolt-devnet mev-sidecar-api api) \
--private-key 53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710 \
--slot head
--slot head \
--count {{count}}
merklefruit marked this conversation as resolved.
Show resolved Hide resolved

# manually send a blob preconfirmation to the bolt devnet
send-blob-preconf:
send-blob-preconf count='1':
cd bolt-spammer && RUST_LOG=info cargo run -- \
--provider-url $(kurtosis port print bolt-devnet el-1-geth-lighthouse rpc) \
--beacon-client-url $(kurtosis port print bolt-devnet cl-1-lighthouse-geth http) \
--bolt-sidecar-url http://$(kurtosis port print bolt-devnet mev-sidecar-api api) \
--private-key 53321db7c1e331d93a11a41d16f004d7ff63972ec8ec7c25db329728ceeb1710 \
--slot head \
--blob
--blob \
--count {{count}} \

# build all the docker images locally
build-images:
Expand Down
2 changes: 1 addition & 1 deletion bolt-sidecar/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ pub struct Limits {
impl Default for Limits {
fn default() -> Self {
Self {
max_commitments_per_slot: NonZero::new(6).expect("Valid non-zero"),
max_commitments_per_slot: NonZero::new(128).expect("Valid non-zero"),
max_committed_gas_per_slot: NonZero::new(10_000_000).expect("Valid non-zero"),
}
}
Expand Down
82 changes: 43 additions & 39 deletions bolt-spammer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ struct Opts {
blob: bool,
#[clap(short = 's', long, default_value = "head")]
slot: String,
#[clap(short = 'C', long, default_value_t = 1)]
count: u64,
}

#[tokio::main]
Expand All @@ -53,45 +55,47 @@ async fn main() -> Result<()> {
let current_slot = current_slot(&beacon_api_client).await?;
let target_slot = if opts.slot == "head" { current_slot + 2 } else { opts.slot.parse()? };

let mut tx = if opts.blob { generate_random_blob_tx() } else { generate_random_tx() };
tx.set_from(sender);
tx.set_nonce(provider.get_transaction_count(sender).await?);

let tx_signed = tx.build(&transaction_signer).await?;
let tx_hash = tx_signed.tx_hash().to_string();
let tx_rlp = hex::encode(tx_signed.encoded_2718());

let message_digest = {
let mut data = Vec::new();
data.extend_from_slice(&target_slot.to_le_bytes());
data.extend_from_slice(hex::decode(tx_hash.trim_start_matches("0x"))?.as_slice());
keccak256(data)
};

let signature = wallet.sign_hash(&message_digest).await?;
let signature = hex::encode(signature.as_bytes());

let request = prepare_rpc_request(
"bolt_inclusionPreconfirmation",
vec![serde_json::json!({
"slot": target_slot,
"tx": tx_rlp,
"signature": signature,
})],
);

info!("Transaction hash: {}", tx_hash);
info!("body: {}", serde_json::to_string(&request)?);

let client = reqwest::Client::new();
let response = client
.post(&opts.bolt_sidecar_url)
.header("content-type", "application/json")
.body(serde_json::to_string(&request)?)
.send()
.await?;

info!("Response: {:?}", response.text().await?);
for i in 0..opts.count {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no delay between spamming? should we do something like 100 ms? just an idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the devnet I think there is no reason to add a delay, but yeah I should bring these changes for helder testnet and it might be worth to add configurable delay between preconfs, with a 100ms default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, should I do that for Helder or wait for #163 to be done?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waiting is fine, it's not a priority

let mut tx = if opts.blob { generate_random_blob_tx() } else { generate_random_tx() };
tx.set_from(sender);
tx.set_nonce(provider.get_transaction_count(sender).await? + i);

let tx_signed = tx.build(&transaction_signer).await?;
let tx_hash = tx_signed.tx_hash().to_string();
let tx_rlp = hex::encode(tx_signed.encoded_2718());

let message_digest = {
let mut data = Vec::new();
data.extend_from_slice(&target_slot.to_le_bytes());
data.extend_from_slice(hex::decode(tx_hash.trim_start_matches("0x"))?.as_slice());
keccak256(data)
};

let signature = wallet.sign_hash(&message_digest).await?;
let signature = hex::encode(signature.as_bytes());

let request = prepare_rpc_request(
"bolt_inclusionPreconfirmation",
vec![serde_json::json!({
"slot": target_slot,
"tx": tx_rlp,
"signature": signature,
})],
);

info!("Transaction hash: {}", tx_hash);
info!("body: {}", serde_json::to_string(&request)?);

let client = reqwest::Client::new();
let response = client
.post(&opts.bolt_sidecar_url)
.header("content-type", "application/json")
.body(serde_json::to_string(&request)?)
.send()
.await?;

info!("Response: {:?}", response.text().await?);
}

Ok(())
}
4 changes: 2 additions & 2 deletions bolt-spammer/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub fn generate_random_tx() -> TransactionRequest {
.with_to(Address::from_str(DEAD_ADDRESS).unwrap())
.with_chain_id(KURTOSIS_CHAIN_ID)
.with_value(U256::from(thread_rng().gen_range(1..100)))
.with_gas_limit(1_000_000u128)
.with_gas_limit(21_000u128)
.with_gas_price(NOICE_GAS_PRICE)
}

Expand All @@ -38,7 +38,7 @@ pub fn generate_random_blob_tx() -> TransactionRequest {
.with_max_fee_per_blob_gas(100u128)
.max_fee_per_gas(NOICE_GAS_PRICE)
.max_priority_fee_per_gas(NOICE_GAS_PRICE / 10)
.with_gas_limit(1_000_000u128)
.with_gas_limit(42_000u128)
.with_blob_sidecar(sidecar)
.with_input(random_bytes)
}
Expand Down
2 changes: 1 addition & 1 deletion builder/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ARG VERSION=""
ARG BUILDNUM=""

# Build Geth in a stock Go builder container
FROM golang:1.21-alpine AS builder
FROM golang:1.22-alpine AS builder

RUN apk add --no-cache gcc musl-dev linux-headers git

Expand Down
2 changes: 1 addition & 1 deletion builder/Dockerfile.alltools
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ ARG VERSION=""
ARG BUILDNUM=""

# Build Geth in a stock Go builder container
FROM golang:1.21-alpine AS builder
FROM golang:1.22-alpine AS builder

RUN apk add --no-cache gcc musl-dev linux-headers git

Expand Down
16 changes: 9 additions & 7 deletions builder/builder/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,11 @@ func EmitBoltDemoEvent(message string) {

func CalculateMerkleMultiProofs(
payloadTransactions types.Transactions,
constraints types.HashToConstraintDecoded,
HashToConstraintDecoded types.HashToConstraintDecoded,
mempirate marked this conversation as resolved.
Show resolved Hide resolved
) (inclusionProof *common.InclusionProof, rootNode *ssz.Node, err error) {
constraintsOrderedByIndex, constraintsWithoutIndex, _, _ := types.ParseConstraintsDecoded(HashToConstraintDecoded)
constraints := slices.Concat(constraintsOrderedByIndex, constraintsWithoutIndex)

// BOLT: generate merkle tree from payload transactions (we need raw RLP bytes for this)
rawTxs := make([]bellatrix.Transaction, len(payloadTransactions))
for i, tx := range payloadTransactions {
Expand Down Expand Up @@ -185,21 +188,20 @@ func CalculateMerkleMultiProofs(
baseGeneralizedIndex := int(math.Pow(float64(2), float64(21)))
generalizedIndexes := make([]int, len(constraints))
transactionHashes := make([]common.Hash, len(constraints))
i := 0

for hash := range constraints {
for i, constraint := range constraints {
tx := constraint.Tx
// get the index of the preconfirmed transaction in the block
preconfIndex := slices.IndexFunc(payloadTransactions, func(tx *types.Transaction) bool { return tx.Hash() == hash })
preconfIndex := slices.IndexFunc(payloadTransactions, func(payloadTx *types.Transaction) bool { return payloadTx.Hash() == tx.Hash() })
if preconfIndex == -1 {
log.Error(fmt.Sprintf("Preconfirmed transaction %s not found in block", hash))
log.Error(fmt.Sprintf("Preconfirmed transaction %s not found in block", tx.Hash()))
log.Error(fmt.Sprintf("block has %v transactions", len(payloadTransactions)))
continue
}

generalizedIndex := baseGeneralizedIndex + preconfIndex
generalizedIndexes[i] = generalizedIndex
transactionHashes[i] = hash
i++
transactionHashes[i] = tx.Hash()
thedevbirb marked this conversation as resolved.
Show resolved Hide resolved
}

log.Info(fmt.Sprintf("[BOLT]: Calculating merkle multiproof for %d preconfirmed transaction",
Expand Down
49 changes: 48 additions & 1 deletion builder/core/types/constraints.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package types

import "github.com/ethereum/go-ethereum/common"
import (
"sort"

"github.com/ethereum/go-ethereum/common"
)

// NOTE: not the greatest place for this type but given that it uses
// `common.Hash`, `Transaction` and it's used in both the builder
Expand All @@ -13,3 +17,46 @@ type (
Tx *Transaction
}
)

// ParseConstraintsDecoded receives a map of constraints and returns
// - a slice of constraints sorted by index
// - a slice of constraints without index sorted by nonce and hash
// - the total gas required by the constraints
// - the total blob gas required by the constraints
func ParseConstraintsDecoded(constraints HashToConstraintDecoded) ([]*ConstraintDecoded, []*ConstraintDecoded, uint64, uint64) {
// Here we initialize and track the constraints left to be executed along
// with their gas requirements
constraintsOrderedByIndex := make([]*ConstraintDecoded, 0, len(constraints))
constraintsWithoutIndex := make([]*ConstraintDecoded, 0, len(constraints))
constraintsTotalGasLeft := uint64(0)
constraintsTotalBlobGasLeft := uint64(0)

for _, constraint := range constraints {
if constraint.Index == nil {
constraintsWithoutIndex = append(constraintsWithoutIndex, constraint)
} else {
constraintsOrderedByIndex = append(constraintsOrderedByIndex, constraint)
}
constraintsTotalGasLeft += constraint.Tx.Gas()
constraintsTotalBlobGasLeft += constraint.Tx.BlobGas()
}

// Sorts the constraints by index ascending
sort.Slice(constraintsOrderedByIndex, func(i, j int) bool {
// By assumption, all constraints here have a non-nil index
return *constraintsOrderedByIndex[i].Index < *constraintsOrderedByIndex[j].Index
})

// Sorts the unindexed constraints by nonce ascending and by hash
sort.Slice(constraintsWithoutIndex, func(i, j int) bool {
iNonce := constraintsWithoutIndex[i].Tx.Nonce()
jNonce := constraintsWithoutIndex[j].Tx.Nonce()
// Sort by hash
if iNonce == jNonce {
return constraintsWithoutIndex[i].Tx.Hash().Cmp(constraintsWithoutIndex[j].Tx.Hash()) < 0
}
return iNonce < jNonce
})

return constraintsOrderedByIndex, constraintsWithoutIndex, constraintsTotalGasLeft, constraintsTotalBlobGasLeft
}
5 changes: 3 additions & 2 deletions builder/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/ethereum/go-ethereum

go 1.20
go 1.22

require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
Expand All @@ -26,7 +26,7 @@ require (
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
github.com/ethereum/c-kzg-4844 v0.4.0
github.com/fatih/color v1.15.0
github.com/ferranbt/fastssz v0.1.3
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2
github.com/flashbots/go-boost-utils v1.8.0
Expand Down Expand Up @@ -86,6 +86,7 @@ require (
)

require (
github.com/emicklei/dot v1.6.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/goccy/go-yaml v1.11.2 // indirect
Expand Down
6 changes: 4 additions & 2 deletions builder/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
Expand All @@ -150,8 +152,8 @@ github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBD
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688 h1:k70X5h1haHaSbpD/9fcjtvAUEVlRlOKtdpvN7Mzhcv4=
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
Expand Down
26 changes: 5 additions & 21 deletions builder/miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1033,26 +1033,10 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac

// Here we initialize and track the constraints left to be executed along
// with their gas requirements
constraintsOrderedByIndex := make([]*types.ConstraintDecoded, 0, len(constraints))
constraintsWithoutIndex := make([]*types.ConstraintDecoded, 0, len(constraints))
constraintsTotalGasLeft := uint64(0)
constraintsTotalBlobGasLeft := uint64(0)

for _, constraint := range constraints {
if constraint.Index == nil {
constraintsWithoutIndex = append(constraintsWithoutIndex, constraint)
} else {
constraintsOrderedByIndex = append(constraintsOrderedByIndex, constraint)
}
constraintsTotalGasLeft += constraint.Tx.Gas()
constraintsTotalBlobGasLeft += constraint.Tx.BlobGas()
}

// Sorts the constraints by index ascending
sort.Slice(constraintsOrderedByIndex, func(i, j int) bool {
// By assumption, all constraints here have a non-nil index
return *constraintsOrderedByIndex[i].Index < *constraintsOrderedByIndex[j].Index
})
constraintsOrderedByIndex,
constraintsWithoutIndex,
constraintsTotalGasLeft,
constraintsTotalBlobGasLeft := types.ParseConstraintsDecoded(constraints)

for {
// `env.tcount` starts from 0 so it's correct to use it as the current index
Expand Down Expand Up @@ -1177,7 +1161,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac
// As such, we can safely exist
break
}
candidate = candidateTx{tx: common.Pop(&constraintsWithoutIndex).Tx, isConstraint: true}
candidate = candidateTx{tx: common.Shift(&constraintsWithoutIndex).Tx, isConstraint: true}
}
}

Expand Down
3 changes: 2 additions & 1 deletion mev-boost-relay/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
Expand Down Expand Up @@ -91,7 +92,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/ferranbt/fastssz v0.1.3
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
Expand Down
4 changes: 4 additions & 0 deletions mev-boost-relay/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
Expand All @@ -131,6 +133,8 @@ github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4Nij
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688 h1:k70X5h1haHaSbpD/9fcjtvAUEVlRlOKtdpvN7Mzhcv4=
github.com/ferranbt/fastssz v0.1.4-0.20240724090034-31cd371f8688/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
github.com/flashbots/go-boost-utils v1.8.0 h1:z3K1hw+Fbl9AGMNQKnK7Bvf0M/rKgjfruAEvra+Z8Mg=
github.com/flashbots/go-boost-utils v1.8.0/go.mod h1:Ry1Rw8Lx5v1rpAR0+IvR4sV10jYAeQaGVM3vRD8mYdM=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down
Loading
Loading