synapsecns/sanguine

View on GitHub
ethergo/submitter/util.go

Summary

Maintainability
A
0 mins
Test Coverage
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
}