-
Notifications
You must be signed in to change notification settings - Fork 6
/
transactionSorter.go
106 lines (82 loc) · 3.34 KB
/
transactionSorter.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
package transaction
import (
"bytes"
"sort"
"github.com/ElrondNetwork/elrond-go-core/data"
"github.com/ElrondNetwork/elrond-go-core/hashing"
)
// SortTransactionsBySenderAndNonceWithFrontRunningProtection - sorts the transactions by address and randomness source to protect from front running
func SortTransactionsBySenderAndNonceWithFrontRunningProtection(transactions []data.TransactionHandler, hasher hashing.Hasher, randomness []byte) {
// make sure randomness is 32bytes and uniform
randSeed := hasher.Compute(string(randomness))
xoredAddresses := make(map[string][]byte)
for _, tx := range transactions {
xoredBytes := xorBytes(tx.GetSndAddr(), randSeed)
xoredAddresses[string(tx.GetSndAddr())] = hasher.Compute(string(xoredBytes))
}
sorter := func(i, j int) bool {
txI := transactions[i]
txJ := transactions[j]
delta := bytes.Compare(xoredAddresses[string(txI.GetSndAddr())], xoredAddresses[string(txJ.GetSndAddr())])
if delta == 0 {
delta = int(txI.GetNonce()) - int(txJ.GetNonce())
}
return delta < 0
}
sort.Slice(transactions, sorter)
}
// TODO remove duplicated function when will use the version of elrond-go which exports transaction order during processing
// SortTransactionsBySenderAndNonceWithFrontRunningProtectionExtendedTransactions - sorts the transactions by address and randomness source to protect from front running
func SortTransactionsBySenderAndNonceWithFrontRunningProtectionExtendedTransactions(transactions []data.TransactionHandlerWithGasUsedAndFee, hasher hashing.Hasher, randomness []byte) {
// make sure randomness is 32bytes and uniform
randSeed := hasher.Compute(string(randomness))
xoredAddresses := make(map[string][]byte)
for _, tx := range transactions {
xoredBytes := xorBytes(tx.GetSndAddr(), randSeed)
xoredAddresses[string(tx.GetSndAddr())] = hasher.Compute(string(xoredBytes))
}
sorter := func(i, j int) bool {
txI := transactions[i]
txJ := transactions[j]
delta := bytes.Compare(xoredAddresses[string(txI.GetSndAddr())], xoredAddresses[string(txJ.GetSndAddr())])
if delta == 0 {
delta = int(txI.GetNonce()) - int(txJ.GetNonce())
}
return delta < 0
}
sort.Slice(transactions, sorter)
}
// SortTransactionsBySenderAndNonce - sorts the transactions by address without the front running protection
func SortTransactionsBySenderAndNonce(transactions []data.TransactionHandler) {
sorter := func(i, j int) bool {
txI := transactions[i]
txJ := transactions[j]
delta := bytes.Compare(txI.GetSndAddr(), txJ.GetSndAddr())
if delta == 0 {
delta = int(txI.GetNonce()) - int(txJ.GetNonce())
}
return delta < 0
}
sort.Slice(transactions, sorter)
}
// SortTransactionsBySenderAndNonceExtendedTransactions - sorts the transactions by address without the front running protection
func SortTransactionsBySenderAndNonceExtendedTransactions(transactions []data.TransactionHandlerWithGasUsedAndFee) {
sorter := func(i, j int) bool {
txI := transactions[i]
txJ := transactions[j]
delta := bytes.Compare(txI.GetSndAddr(), txJ.GetSndAddr())
if delta == 0 {
delta = int(txI.GetNonce()) - int(txJ.GetNonce())
}
return delta < 0
}
sort.Slice(transactions, sorter)
}
// parameters need to be of the same len, otherwise it will panic (if second slice shorter)
func xorBytes(a, b []byte) []byte {
res := make([]byte, len(a))
for i := range a {
res[i] = a[i] ^ b[i]
}
return res
}