ethergo/submitter/util.go
package submitter
import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/synapsecns/sanguine/ethergo/util"
"go.opentelemetry.io/otel/attribute"
"math/big"
"sort"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/ethergo/chain/gas"
"github.com/synapsecns/sanguine/ethergo/submitter/db"
)
// copyTransactOpts creates a deep copy of the given TransactOpts struct
// with big ints wrapped in core.CopyBigInt().
func copyTransactOpts(opts *bind.TransactOpts) *bind.TransactOpts {
copyOpts := &bind.TransactOpts{
From: opts.From,
Nonce: core.CopyBigInt(opts.Nonce),
Signer: opts.Signer,
Value: core.CopyBigInt(opts.Value),
GasPrice: core.CopyBigInt(opts.GasPrice),
GasFeeCap: core.CopyBigInt(opts.GasFeeCap),
GasTipCap: core.CopyBigInt(opts.GasTipCap),
GasLimit: opts.GasLimit,
Context: opts.Context,
NoSend: opts.NoSend,
}
return copyOpts
}
func txToAttributes(transaction *types.Transaction, uuid string) (attributes []attribute.KeyValue) {
attributes = util.TxToAttributes(transaction)
attributes = append(attributes, attribute.String(uuidAttr, uuid))
return attributes
}
const uuidAttr = "tx.UUID"
// sortTxesByChainID sorts a slice of transactions by nonce.
func sortTxesByChainID(txs []db.TX, maxPerChain int) map[uint64][]db.TX {
txesByChainID := make(map[uint64][]db.TX)
// put the transactions in a map by chain id
for _, t := range txs {
txesByChainID[t.ChainId().Uint64()] = append(txesByChainID[t.ChainId().Uint64()], t)
}
for key := range txesByChainID {
key := key // capture range variable
// sort the transactions by nonce
sort.Slice(txesByChainID[key], func(i, j int) bool {
iNonce := txesByChainID[key][i].Nonce()
jNonce := txesByChainID[key][j].Nonce()
if iNonce == jNonce {
gasCmp := gas.CompareGas(txesByChainID[key][i].Transaction, txesByChainID[key][j].Transaction, nil)
if gasCmp == 0 || gasCmp == 1 {
return false
}
return true
}
return iNonce < jNonce
})
}
// cap the number of txes per chain
for chainID, txes := range txesByChainID {
if len(txes) > maxPerChain {
txesByChainID[chainID] = txes[:maxPerChain]
}
}
return txesByChainID
}
// groupTxesByNonce groups a slice of transactions by nonce.
// this will not differentiate between transactions with different chain ids.
func groupTxesByNonce(txs []db.TX) map[uint64][]db.TX {
txesByNonce := make(map[uint64][]db.TX)
for _, t := range txs {
txesByNonce[t.Nonce()] = append(txesByNonce[t.Nonce()], t)
}
return txesByNonce
}
// Function to check if a slice contains a given big integer.
func contains(slice []*big.Int, elem *big.Int) bool {
for _, v := range slice {
if v.Cmp(elem) == 0 {
return true
}
}
return false
}
// Function to get the outersection of two slices of big.Int.
func outersection(set, superset []*big.Int) []*big.Int {
var result []*big.Int
for _, elem := range superset {
if !contains(set, elem) {
result = append(result, elem)
}
}
return result
}
// Generic function to convert a map[uint64]T to []*big.Int.
func mapToBigIntSlice[T any](m map[uint64]T) []*big.Int {
var result []*big.Int
for k := range m {
bigIntKey := new(big.Int).SetUint64(k)
result = append(result, bigIntKey)
}
return result
}