Skip to content

Commit

Permalink
Refactor, fix logging.
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu committed Nov 4, 2024
1 parent 62c0f96 commit 8348e11
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 82 deletions.
67 changes: 56 additions & 11 deletions txcache/diagnosis.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package txcache

import (
"encoding/hex"
"encoding/json"
"fmt"
"strings"

"github.com/multiversx/mx-chain-core-go/core"
logger "github.com/multiversx/mx-chain-logger-go"
)

type printedTransaction struct {
Hash string `json:"hash"`
Nonce uint64 `json:"nonce"`
PPU float64 `json:"ppu"`
GasPrice uint64 `json:"gasPrice"`
GasLimit uint64 `json:"gasLimit"`
Sender string `json:"sender"`
Receiver string `json:"receiver"`
DataLength int `json:"dataLength"`
}

// Diagnose checks the state of the cache for inconsistencies and displays a summary, senders and transactions.
func (cache *TxCache) Diagnose(_ bool) {
cache.diagnoseCounters()
Expand Down Expand Up @@ -48,37 +64,66 @@ func (cache *TxCache) diagnoseTransactions() {
}

transactions := cache.getAllTransactions()

if len(transactions) == 0 {
return
}

numToDisplay := core.MinInt(diagnosisMaxTransactionsToDisplay, len(transactions))
logDiagnoseTransactions.Trace("diagnoseTransactions", "numTransactions", len(transactions), "numToDisplay", numToDisplay)
logDiagnoseTransactions.Trace(marshalTransactionsToNewlineDelimitedJson(transactions[:numToDisplay]))
logDiagnoseTransactions.Trace(marshalTransactionsToNewlineDelimitedJson(transactions[:numToDisplay], "diagnoseTransactions"))
}

// marshalTransactionsToNewlineDelimitedJson converts a list of transactions to a newline-delimited JSON string.
// Note: each line is indexed, to improve readability. The index is easily removable for if separate analysis is needed.
func marshalTransactionsToNewlineDelimitedJson(transactions []*WrappedTransaction, linePrefix string) string {
builder := strings.Builder{}
builder.WriteString("\n")

for i, wrappedTx := range transactions {
printedTx := convertWrappedTransactionToPrintedTransaction(wrappedTx)
printedTxJson, _ := json.Marshal(printedTx)

builder.WriteString(fmt.Sprintf("%s#%d: ", linePrefix, i))
builder.WriteString(string(printedTxJson))
builder.WriteString("\n")
}

builder.WriteString("\n")
return builder.String()
}

func convertWrappedTransactionToPrintedTransaction(wrappedTx *WrappedTransaction) *printedTransaction {
transaction := wrappedTx.Tx

return &printedTransaction{
Hash: hex.EncodeToString(wrappedTx.TxHash),
Nonce: transaction.GetNonce(),
Receiver: hex.EncodeToString(transaction.GetRcvAddr()),
Sender: hex.EncodeToString(transaction.GetSndAddr()),
GasPrice: transaction.GetGasPrice(),
GasLimit: transaction.GetGasLimit(),
DataLength: len(transaction.GetData()),
PPU: wrappedTx.PricePerUnit,
}
}

func (cache *TxCache) diagnoseSelection() {
if logDiagnoseSelection.GetLevel() > logger.LogDebug {
return
}

transactions := cache.doSelectTransactions(
logDiagnoseSelection,
diagnosisSelectionGasRequested,
)

displaySelectionOutcome(logDiagnoseSelection, transactions)
transactions := cache.doSelectTransactions(diagnosisSelectionGasRequested)
displaySelectionOutcome(logDiagnoseSelection, "diagnoseSelection", transactions)
}

func displaySelectionOutcome(contextualLogger logger.Logger, selection []*WrappedTransaction) {
func displaySelectionOutcome(contextualLogger logger.Logger, linePrefix string, transactions []*WrappedTransaction) {
if contextualLogger.GetLevel() > logger.LogTrace {
return
}

if len(selection) > 0 {
if len(transactions) > 0 {
contextualLogger.Trace("displaySelectionOutcome - transactions (as newline-separated JSON):")
contextualLogger.Trace(marshalTransactionsToNewlineDelimitedJson(selection))
contextualLogger.Trace(marshalTransactionsToNewlineDelimitedJson(transactions, linePrefix))
} else {
contextualLogger.Trace("displaySelectionOutcome - transactions: none")
}
Expand Down
53 changes: 0 additions & 53 deletions txcache/printing.go

This file was deleted.

4 changes: 2 additions & 2 deletions txcache/txCache.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) {

cache.mutTxOperation.Lock()
addedInByHash := cache.txByHash.addTx(tx)
addedInBySender, evicted := cache.txListBySender.addTx(tx)
addedInBySender, evicted := cache.txListBySender.addTxReturnEvicted(tx)
cache.mutTxOperation.Unlock()
if addedInByHash != addedInBySender {
// This can happen when two go-routines concur to add the same transaction:
Expand Down Expand Up @@ -117,7 +117,7 @@ func (cache *TxCache) SelectTransactions(gasRequested uint64) []*WrappedTransact
)

go cache.diagnoseCounters()
go displaySelectionOutcome(logSelect, transactions)
go displaySelectionOutcome(logSelect, "selection", transactions)

return transactions
}
Expand Down
2 changes: 1 addition & 1 deletion txcache/txCache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ func TestTxCache_TransactionIsAdded_EvenWhenInternalMapsAreInconsistent(t *testi
cache.Clear()

// Setup inconsistency: transaction already exists in map by sender, but not in map by hash
cache.txListBySender.addTx(createTx([]byte("alice-x"), "alice", 42))
cache.txListBySender.addTxReturnEvicted(createTx([]byte("alice-x"), "alice", 42))

require.False(t, cache.Has([]byte("alice-x")))
ok, added = cache.AddTx(createTx([]byte("alice-x"), "alice", 42))
Expand Down
16 changes: 13 additions & 3 deletions txcache/txListBySenderMap.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,22 @@ func newTxListBySenderMap(
}
}

// addTx adds a transaction in the map, in the corresponding list (selected by its sender)
func (txMap *txListBySenderMap) addTx(tx *WrappedTransaction) (bool, [][]byte) {
// addTxReturnEvicted adds a transaction in the map, in the corresponding list (selected by its sender).
// This function returns a boolean indicating whether the transaction was added, and a slice of evicted transaction hashes (upon applying sender-level constraints).
func (txMap *txListBySenderMap) addTxReturnEvicted(tx *WrappedTransaction) (bool, [][]byte) {
sender := string(tx.Tx.GetSndAddr())
listForSender := txMap.getOrAddListForSender(sender)
tx.computePricePerGasUnit(txMap.txGasHandler)
return listForSender.AddTx(tx)

added, evictedHashes := listForSender.AddTx(tx)

if listForSender.IsEmpty() {
// Generally speaking, a sender cannot become empty after upon applying sender-level constraints.
// However:
txMap.removeSender(sender)
}

return added, evictedHashes
}

// getOrAddListForSender gets or lazily creates a list (using double-checked locking pattern)
Expand Down
22 changes: 11 additions & 11 deletions txcache/txListBySenderMap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
func TestSendersMap_AddTx_IncrementsCounter(t *testing.T) {
myMap := newSendersMapToTest()

myMap.addTx(createTx([]byte("a"), "alice", 1))
myMap.addTx(createTx([]byte("aa"), "alice", 2))
myMap.addTx(createTx([]byte("b"), "bob", 1))
myMap.addTxReturnEvicted(createTx([]byte("a"), "alice", 1))
myMap.addTxReturnEvicted(createTx([]byte("aa"), "alice", 2))
myMap.addTxReturnEvicted(createTx([]byte("b"), "bob", 1))

// There are 2 senders
require.Equal(t, int64(2), myMap.counter.Get())
Expand All @@ -27,9 +27,9 @@ func TestSendersMap_RemoveTx_AlsoRemovesSenderWhenNoTransactionLeft(t *testing.T
txAlice2 := createTx([]byte("a2"), "alice", 2)
txBob := createTx([]byte("b"), "bob", 1)

myMap.addTx(txAlice1)
myMap.addTx(txAlice2)
myMap.addTx(txBob)
myMap.addTxReturnEvicted(txAlice1)
myMap.addTxReturnEvicted(txAlice2)
myMap.addTxReturnEvicted(txBob)
require.Equal(t, int64(2), myMap.counter.Get())
require.Equal(t, uint64(2), myMap.testGetListForSender("alice").countTx())
require.Equal(t, uint64(1), myMap.testGetListForSender("bob").countTx())
Expand All @@ -51,7 +51,7 @@ func TestSendersMap_RemoveTx_AlsoRemovesSenderWhenNoTransactionLeft(t *testing.T
func TestSendersMap_RemoveSender(t *testing.T) {
myMap := newSendersMapToTest()

myMap.addTx(createTx([]byte("a"), "alice", 1))
myMap.addTxReturnEvicted(createTx([]byte("a"), "alice", 1))
require.Equal(t, int64(1), myMap.counter.Get())

// Bob is unknown
Expand Down Expand Up @@ -86,9 +86,9 @@ func TestSendersMap_RemoveSendersBulk_ConcurrentWithAddition(t *testing.T) {
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
myMap.addTx(createTx([]byte("a"), "alice", uint64(i)))
myMap.addTx(createTx([]byte("b"), "bob", uint64(i)))
myMap.addTx(createTx([]byte("c"), "carol", uint64(i)))
myMap.addTxReturnEvicted(createTx([]byte("a"), "alice", uint64(i)))
myMap.addTxReturnEvicted(createTx([]byte("b"), "bob", uint64(i)))
myMap.addTxReturnEvicted(createTx([]byte("c"), "carol", uint64(i)))

wg.Done()
}(i)
Expand All @@ -103,7 +103,7 @@ func TestSendersMap_notifyAccountNonce(t *testing.T) {
// Discarded notification, since sender not added yet
myMap.notifyAccountNonceReturnEvictedTransactions([]byte("alice"), 42)

myMap.addTx(createTx([]byte("tx-42"), "alice", 42))
myMap.addTxReturnEvicted(createTx([]byte("tx-42"), "alice", 42))
alice, _ := myMap.getListForSender("alice")
require.Equal(t, uint64(0), alice.accountNonce.Get())
require.False(t, alice.accountNonceKnown.IsSet())
Expand Down
1 change: 0 additions & 1 deletion txcache/txListForSender.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ func (listForSender *txListForSender) AddTx(tx *WrappedTransaction) (bool, [][]b

listForSender.onAddedTransaction(tx)

// TODO: Check how does the sender get removed if empty afterwards (maybe the answer is: "it never gets empty after applySizeConstraints()").
evicted := listForSender.applySizeConstraints()
return true, evicted
}
Expand Down

0 comments on commit 8348e11

Please sign in to comment.