-
Notifications
You must be signed in to change notification settings - Fork 29
/
util.go
143 lines (125 loc) · 4.42 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package submitter
import (
"fmt"
"math/big"
"sort"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/ethergo/chain/gas"
"github.com/synapsecns/sanguine/ethergo/submitter/db"
"github.com/synapsecns/sanguine/ethergo/util"
"go.opentelemetry.io/otel/attribute"
)
// 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
}
const (
uuidAttr = "tx.UUID"
hashAttr = "tx.Hash"
fromAttr = "tx.From"
toAttr = "tx.To"
dataAttr = "tx.Data"
valueAttr = "tx.Value"
nonceAttr = "tx.Nonce"
gasLimitAttr = "tx.GasLimit"
chainIDAttr = "tx.ChainID"
gasPriceAttr = "tx.GasPrice"
gasFeeCapAttr = "tx.GasFeeCap"
gasTipCapAttr = "tx.GasTipCap"
)
// txToAttributes converts a transaction to a slice of attribute.KeyValue.
func txToAttributes(transaction *types.Transaction, uuid string) []attribute.KeyValue {
var from string
call, err := util.TxToCall(transaction)
if err != nil {
from = fmt.Sprintf("could not be detected: %v", err)
} else {
from = call.From.Hex()
}
var attributes = []attribute.KeyValue{
attribute.String(uuidAttr, uuid),
attribute.String(hashAttr, transaction.Hash().Hex()),
attribute.String(fromAttr, from),
attribute.String(toAttr, addressPtrToString(transaction.To())),
attribute.String(dataAttr, fmt.Sprintf("%x", transaction.Data())),
attribute.String(valueAttr, bigPtrToString(transaction.Value())),
// TODO: this could be downcast to int64, but it's unclear how we should handle overflows.
// since this is only for tracing, we can probably ignore it for now.
attribute.Int64(nonceAttr, int64(transaction.Nonce())),
attribute.Int64(gasLimitAttr, int64(transaction.Gas())),
attribute.String(chainIDAttr, bigPtrToString(transaction.ChainId())),
}
if transaction.Type() == types.LegacyTxType && transaction.GasPrice() != nil {
attributes = append(attributes, attribute.String(gasPriceAttr, bigPtrToString(transaction.GasPrice())))
}
if transaction.Type() == types.DynamicFeeTxType && transaction.GasFeeCap() != nil {
attributes = append(attributes, attribute.String(gasFeeCapAttr, bigPtrToString(transaction.GasFeeCap())))
}
if transaction.Type() == types.DynamicFeeTxType && transaction.GasTipCap() != nil {
attributes = append(attributes, attribute.String(gasTipCapAttr, bigPtrToString(transaction.GasTipCap())))
}
return attributes
}
const nullFieldAttribute = "null"
func addressPtrToString(address *common.Address) string {
if address == nil {
return nullFieldAttribute
}
return address.Hex()
}
func bigPtrToString(num *big.Int) string {
if num == nil {
return nullFieldAttribute
}
return num.String()
}
// sortTxesByChainID sorts a slice of transactions by nonce.
func sortTxesByChainID(txs []db.TX) 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
})
}
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
}