Skip to content

Commit

Permalink
Merge pull request #144 from ElrondNetwork/merge-rc-v140-freeze-account
Browse files Browse the repository at this point in the history
Merge rc v140 freeze account
  • Loading branch information
AdoAdoAdo authored Dec 27, 2022
2 parents 67fffa6 + 1a71b43 commit c16d47b
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 6 deletions.
106 changes: 106 additions & 0 deletions core/transaction/transactionSorter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,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
}
110 changes: 110 additions & 0 deletions core/transaction/transactionSorter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package transaction

import (
"encoding/hex"
"fmt"
"math/big"
"testing"

"github.com/ElrondNetwork/elrond-go-core/core/mock"
"github.com/ElrondNetwork/elrond-go-core/data"
"github.com/ElrondNetwork/elrond-go-core/data/outport"
"github.com/ElrondNetwork/elrond-go-core/data/transaction"
"github.com/stretchr/testify/assert"
)

func Test_SortTransactionsBySenderAndNonceWithFrontRunningProtection(t *testing.T) {
randomness := "randomness"
nbSenders := 5

hasher := &mock.HasherStub{
ComputeCalled: func(s string) []byte {
if s == randomness {
return []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
}

return []byte(s)
},
}

usedRandomness := hasher.Compute(randomness)
senders := make([][]byte, 0)
for i := 0; i < nbSenders; i++ {
sender := make([]byte, len(usedRandomness))
copy(sender, usedRandomness)
sender[len(usedRandomness)-1-i] = 0
senders = append(senders, sender)
}

txs := []data.TransactionHandler{
&transaction.Transaction{Nonce: 1, SndAddr: senders[0]},
&transaction.Transaction{Nonce: 2, SndAddr: senders[2]},
&transaction.Transaction{Nonce: 1, SndAddr: senders[2]},
&transaction.Transaction{Nonce: 2, SndAddr: senders[0]},
&transaction.Transaction{Nonce: 7, SndAddr: senders[1]},
&transaction.Transaction{Nonce: 6, SndAddr: senders[1]},
&transaction.Transaction{Nonce: 1, SndAddr: senders[4]},
&transaction.Transaction{Nonce: 3, SndAddr: senders[3]},
&transaction.Transaction{Nonce: 3, SndAddr: senders[2]},
}
wrappedTxs := make([]data.TransactionHandlerWithGasUsedAndFee, 0, len(txs))
for _, tx := range txs {
wrappedTxs = append(wrappedTxs, outport.NewTransactionHandlerWithGasAndFee(tx, 0, big.NewInt(0)))
}

SortTransactionsBySenderAndNonceWithFrontRunningProtection(txs, hasher, []byte(randomness))
SortTransactionsBySenderAndNonceWithFrontRunningProtectionExtendedTransactions(wrappedTxs, hasher, []byte(randomness))

expectedOutput := []string{
"1 ffffffffffffffffffffffffffffff00",
"2 ffffffffffffffffffffffffffffff00",
"6 ffffffffffffffffffffffffffff00ff",
"7 ffffffffffffffffffffffffffff00ff",
"1 ffffffffffffffffffffffffff00ffff",
"2 ffffffffffffffffffffffffff00ffff",
"3 ffffffffffffffffffffffffff00ffff",
"3 ffffffffffffffffffffffff00ffffff",
"1 ffffffffffffffffffffff00ffffffff",
}

for i, item := range txs {
assert.Equal(t, expectedOutput[i], fmt.Sprintf("%d %s", item.GetNonce(), hex.EncodeToString(item.GetSndAddr())))
assert.Equal(t, expectedOutput[i], fmt.Sprintf("%d %s", wrappedTxs[i].GetNonce(), hex.EncodeToString(wrappedTxs[i].GetSndAddr())))
}
}

func Test_SortTransactionsBySenderAndNonceLegacy(t *testing.T) {
txs := []data.TransactionHandler{
&transaction.Transaction{Nonce: 3, SndAddr: []byte("bbbb")},
&transaction.Transaction{Nonce: 1, SndAddr: []byte("aaaa")},
&transaction.Transaction{Nonce: 5, SndAddr: []byte("bbbb")},
&transaction.Transaction{Nonce: 2, SndAddr: []byte("aaaa")},
&transaction.Transaction{Nonce: 7, SndAddr: []byte("aabb")},
&transaction.Transaction{Nonce: 6, SndAddr: []byte("aabb")},
&transaction.Transaction{Nonce: 3, SndAddr: []byte("ffff")},
&transaction.Transaction{Nonce: 3, SndAddr: []byte("eeee")},
}
wrappedTxs := make([]data.TransactionHandlerWithGasUsedAndFee, 0, len(txs))
for _, tx := range txs {
wrappedTxs = append(wrappedTxs, outport.NewTransactionHandlerWithGasAndFee(tx, 0, big.NewInt(0)))
}

SortTransactionsBySenderAndNonce(txs)
SortTransactionsBySenderAndNonceExtendedTransactions(wrappedTxs)

expectedOutput := []string{
"1 aaaa",
"2 aaaa",
"6 aabb",
"7 aabb",
"3 bbbb",
"5 bbbb",
"3 eeee",
"3 ffff",
}

for i, item := range txs {
assert.Equal(t, expectedOutput[i], fmt.Sprintf("%d %s", item.GetNonce(), string(item.GetSndAddr())))
assert.Equal(t, expectedOutput[i], fmt.Sprintf("%d %s", wrappedTxs[i].GetNonce(), string(wrappedTxs[i].GetSndAddr())))
}
}
2 changes: 2 additions & 0 deletions data/api/apiBlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Block struct {
AccumulatedFeesInEpoch string `json:"accumulatedFeesInEpoch,omitempty"`
DeveloperFeesInEpoch string `json:"developerFeesInEpoch,omitempty"`
Status string `json:"status,omitempty"`
RandSeed string `json:"randSeed,omitempty"`
PrevRandSeed string `json:"prevRandSeed,omitempty"`
Timestamp time.Duration `json:"timestamp,omitempty"`
NotarizedBlocks []*NotarizedBlock `json:"notarizedBlocks,omitempty"`
MiniBlocks []*MiniBlock `json:"miniBlocks,omitempty"`
Expand Down
2 changes: 2 additions & 0 deletions data/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ type TransactionHandlerWithGasUsedAndFee interface {
GetGasUsed() uint64
GetFee() *big.Int
GetTxHandler() TransactionHandler
SetExecutionOrder(order int)
GetExecutionOrder() int
}

// Encoder represents a byte slice to string encoder
Expand Down
14 changes: 8 additions & 6 deletions data/outport/dtos.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ type HeaderGasConsumption struct {

// Pool will hold all types of transaction
type Pool struct {
Txs map[string]data.TransactionHandlerWithGasUsedAndFee
Scrs map[string]data.TransactionHandlerWithGasUsedAndFee
Rewards map[string]data.TransactionHandlerWithGasUsedAndFee
Invalid map[string]data.TransactionHandlerWithGasUsedAndFee
Receipts map[string]data.TransactionHandlerWithGasUsedAndFee
Logs []*data.LogData
Txs map[string]data.TransactionHandlerWithGasUsedAndFee
Scrs map[string]data.TransactionHandlerWithGasUsedAndFee
Rewards map[string]data.TransactionHandlerWithGasUsedAndFee
Invalid map[string]data.TransactionHandlerWithGasUsedAndFee
Receipts map[string]data.TransactionHandlerWithGasUsedAndFee
Logs []*data.LogData
ScheduledExecutedSCRSHashesPrevBlock []string
ScheduledExecutedInvalidTxsHashesPrevBlock []string
}

// ValidatorRatingInfo is a structure containing validator rating information
Expand Down
11 changes: 11 additions & 0 deletions data/outport/txWithFee.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type FeeInfo struct {
type TransactionHandlerWithGasAndFee struct {
data.TransactionHandler
FeeInfo
ExecutionOrder int
}

// NewTransactionHandlerWithGasAndFee returns a new instance of transactionHandlerWithGasAndFee which matches the interface
Expand Down Expand Up @@ -65,6 +66,16 @@ func (t *TransactionHandlerWithGasAndFee) GetTxHandler() data.TransactionHandler
return t.TransactionHandler
}

// SetExecutionOrder will set the execution order of the TransactionHandler
func (t *TransactionHandlerWithGasAndFee) SetExecutionOrder(order int) {
t.ExecutionOrder = order
}

// GetExecutionOrder will return the execution order of the TransactionHandler
func (t *TransactionHandlerWithGasAndFee) GetExecutionOrder() int {
return t.ExecutionOrder
}

// WrapTxsMap will wrap the provided transactions map in a map fo transactions with fee and gas used
func WrapTxsMap(txs map[string]data.TransactionHandler) map[string]data.TransactionHandlerWithGasUsedAndFee {
newMap := make(map[string]data.TransactionHandlerWithGasUsedAndFee, len(txs))
Expand Down

0 comments on commit c16d47b

Please sign in to comment.