diff --git a/testscommon/txcachemocks/txGasHandlerMock.go b/testscommon/txcachemocks/mempoolHostMock.go similarity index 53% rename from testscommon/txcachemocks/txGasHandlerMock.go rename to testscommon/txcachemocks/mempoolHostMock.go index 46e18141..d8d797b0 100644 --- a/testscommon/txcachemocks/txGasHandlerMock.go +++ b/testscommon/txcachemocks/mempoolHostMock.go @@ -7,17 +7,20 @@ import ( "github.com/multiversx/mx-chain-core-go/data" ) -// TxGasHandlerMock - -type TxGasHandlerMock struct { +// MempoolHostMock - +type MempoolHostMock struct { minGasLimit uint64 minGasPrice uint64 gasPerDataByte uint64 gasPriceModifier float64 + + ComputeTxFeeCalled func(tx data.TransactionWithFeeHandler) *big.Int + GetTransferredValueCalled func(tx data.TransactionHandler) *big.Int } -// NewTxGasHandlerMock - -func NewTxGasHandlerMock() *TxGasHandlerMock { - return &TxGasHandlerMock{ +// NewMempoolHostMock - +func NewMempoolHostMock() *MempoolHostMock { + return &MempoolHostMock{ minGasLimit: 50000, minGasPrice: 1000000000, gasPerDataByte: 1500, @@ -25,19 +28,17 @@ func NewTxGasHandlerMock() *TxGasHandlerMock { } } -// WithGasPriceModifier - -func (ghm *TxGasHandlerMock) WithGasPriceModifier(gasPriceModifier float64) *TxGasHandlerMock { - ghm.gasPriceModifier = gasPriceModifier - return ghm -} - // ComputeTxFee - -func (ghm *TxGasHandlerMock) ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int { +func (mock *MempoolHostMock) ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int { + if mock.ComputeTxFeeCalled != nil { + return mock.ComputeTxFeeCalled(tx) + } + dataLength := uint64(len(tx.GetData())) gasPriceForMovement := tx.GetGasPrice() - gasPriceForProcessing := uint64(float64(gasPriceForMovement) * ghm.gasPriceModifier) + gasPriceForProcessing := uint64(float64(gasPriceForMovement) * mock.gasPriceModifier) - gasLimitForMovement := ghm.minGasLimit + dataLength*ghm.gasPerDataByte + gasLimitForMovement := mock.minGasLimit + dataLength*mock.gasPerDataByte if tx.GetGasLimit() < gasLimitForMovement { panic("tx.GetGasLimit() < gasLimitForMovement") } @@ -49,7 +50,16 @@ func (ghm *TxGasHandlerMock) ComputeTxFee(tx data.TransactionWithFeeHandler) *bi return fee } +// GetTransferredValue - +func (mock *MempoolHostMock) GetTransferredValue(tx data.TransactionHandler) *big.Int { + if mock.GetTransferredValueCalled != nil { + return mock.GetTransferredValueCalled(tx) + } + + return tx.GetValue() +} + // IsInterfaceNil - -func (ghm *TxGasHandlerMock) IsInterfaceNil() bool { - return ghm == nil +func (mock *MempoolHostMock) IsInterfaceNil() bool { + return mock == nil } diff --git a/testscommon/txcachemocks/selectionSessionMock.go b/testscommon/txcachemocks/selectionSessionMock.go index 537584d1..db789b51 100644 --- a/testscommon/txcachemocks/selectionSessionMock.go +++ b/testscommon/txcachemocks/selectionSessionMock.go @@ -15,7 +15,6 @@ type SelectionSessionMock struct { AccountStateByAddress map[string]*types.AccountState GetAccountStateCalled func(address []byte) (*types.AccountState, error) IsIncorrectlyGuardedCalled func(tx data.TransactionHandler) bool - GetTransferredValueCalled func(tx data.TransactionHandler) *big.Int } // NewSelectionSessionMock - @@ -79,15 +78,6 @@ func (mock *SelectionSessionMock) IsIncorrectlyGuarded(tx data.TransactionHandle return false } -// GetTransferredValue - -func (mock *SelectionSessionMock) GetTransferredValue(tx data.TransactionHandler) *big.Int { - if mock.GetTransferredValueCalled != nil { - return mock.GetTransferredValueCalled(tx) - } - - return tx.GetValue() -} - // IsInterfaceNil - func (mock *SelectionSessionMock) IsInterfaceNil() bool { return mock == nil diff --git a/txcache/errors.go b/txcache/errors.go index 4a7ded65..71ee0169 100644 --- a/txcache/errors.go +++ b/txcache/errors.go @@ -2,7 +2,7 @@ package txcache import "errors" -var errNilTxGasHandler = errors.New("nil tx gas handler") +var errNilMempoolHost = errors.New("nil mempool host") var errNilSelectionSession = errors.New("nil selection session") var errItemAlreadyInCache = errors.New("item already in cache") var errEmptyBunchOfTransactions = errors.New("empty bunch of transactions") diff --git a/txcache/eviction_test.go b/txcache/eviction_test.go index fb51859f..9b435d8e 100644 --- a/txcache/eviction_test.go +++ b/txcache/eviction_test.go @@ -22,9 +22,9 @@ func TestTxCache_DoEviction_BecauseOfCount(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -57,9 +57,9 @@ func TestTxCache_DoEviction_BecauseOfSize(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -93,9 +93,9 @@ func TestTxCache_DoEviction_DoesNothingWhenAlreadyInProgress(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -132,12 +132,12 @@ func TestBenchmarkTxCache_DoEviction(t *testing.T) { NumItemsToPreemptivelyEvict: 50000, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() sw := core.NewStopWatch() t.Run("numSenders = 35000, numTransactions = 10", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) cache.config.EvictionEnabled = false @@ -155,7 +155,7 @@ func TestBenchmarkTxCache_DoEviction(t *testing.T) { }) t.Run("numSenders = 100000, numTransactions = 5", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) cache.config.EvictionEnabled = false @@ -173,7 +173,7 @@ func TestBenchmarkTxCache_DoEviction(t *testing.T) { }) t.Run("numSenders = 400000, numTransactions = 1", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) cache.config.EvictionEnabled = false @@ -191,7 +191,7 @@ func TestBenchmarkTxCache_DoEviction(t *testing.T) { }) t.Run("numSenders = 10000, numTransactions = 100", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) cache.config.EvictionEnabled = false diff --git a/txcache/interface.go b/txcache/interface.go index 45cb1a49..b6d0aee5 100644 --- a/txcache/interface.go +++ b/txcache/interface.go @@ -7,9 +7,10 @@ import ( "github.com/multiversx/mx-chain-storage-go/types" ) -// TxGasHandler handles a transaction gas and gas cost -type TxGasHandler interface { +// MempoolHost provides blockchain information for mempool operations +type MempoolHost interface { ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int + GetTransferredValue(tx data.TransactionHandler) *big.Int IsInterfaceNil() bool } @@ -17,7 +18,6 @@ type TxGasHandler interface { type SelectionSession interface { GetAccountState(accountKey []byte) (*types.AccountState, error) IsIncorrectlyGuarded(tx data.TransactionHandler) bool - GetTransferredValue(tx data.TransactionHandler) *big.Int IsInterfaceNil() bool } diff --git a/txcache/selection.go b/txcache/selection.go index d495c7ba..f889a3a9 100644 --- a/txcache/selection.go +++ b/txcache/selection.go @@ -80,7 +80,7 @@ func selectTransactionsFromBunches(session SelectionSession, bunches []bunchOfTr shouldSkipTransaction := detectSkippableTransaction(session, item) if !shouldSkipTransaction { accumulatedGas += gasLimit - selectedTransactions = append(selectedTransactions, item.selectCurrentTransaction(session)) + selectedTransactions = append(selectedTransactions, item.selectCurrentTransaction()) } // If there are more transactions in the same bunch (same sender as the popped item), diff --git a/txcache/selection_test.go b/txcache/selection_test.go index 099e1b3e..21bc6920 100644 --- a/txcache/selection_test.go +++ b/txcache/selection_test.go @@ -309,12 +309,12 @@ func TestBenchmarkTxCache_acquireBunchesOfTransactions(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() sw := core.NewStopWatch() t.Run("numSenders = 10000, numTransactions = 100", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 10000, 100) @@ -331,7 +331,7 @@ func TestBenchmarkTxCache_acquireBunchesOfTransactions(t *testing.T) { }) t.Run("numSenders = 50000, numTransactions = 2", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 50000, 2) @@ -348,7 +348,7 @@ func TestBenchmarkTxCache_acquireBunchesOfTransactions(t *testing.T) { }) t.Run("numSenders = 100000, numTransactions = 1", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 100000, 1) @@ -365,7 +365,7 @@ func TestBenchmarkTxCache_acquireBunchesOfTransactions(t *testing.T) { }) t.Run("numSenders = 300000, numTransactions = 1", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 300000, 1) @@ -491,13 +491,13 @@ func TestBenchmarkTxCache_doSelectTransactions(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() session := txcachemocks.NewSelectionSessionMock() sw := core.NewStopWatch() t.Run("numSenders = 10000, numTransactions = 100, maxNum = 50_000", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 10000, 100) @@ -513,7 +513,7 @@ func TestBenchmarkTxCache_doSelectTransactions(t *testing.T) { }) t.Run("numSenders = 50000, numTransactions = 2, maxNum = 50_000", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 50000, 2) @@ -529,7 +529,7 @@ func TestBenchmarkTxCache_doSelectTransactions(t *testing.T) { }) t.Run("numSenders = 100000, numTransactions = 1, maxNum = 50_000", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 100000, 1) @@ -545,7 +545,7 @@ func TestBenchmarkTxCache_doSelectTransactions(t *testing.T) { }) t.Run("numSenders = 300000, numTransactions = 1, maxNum = 50_000", func(t *testing.T) { - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) addManyTransactionsWithUniformDistribution(cache, 300000, 1) diff --git a/txcache/testutils_test.go b/txcache/testutils_test.go index 2592a834..6902f1d7 100644 --- a/txcache/testutils_test.go +++ b/txcache/testutils_test.go @@ -13,8 +13,11 @@ import ( const oneMilion = 1000000 const oneBillion = oneMilion * 1000 +const oneQuintillion = 1_000_000_000_000_000_000 const estimatedSizeOfBoundedTxFields = uint64(128) +var oneQuintillionBig = big.NewInt(oneQuintillion) + // The GitHub Actions runners are (extremely) slow. const selectionLoopMaximumDuration = 30 * time.Second @@ -112,7 +115,7 @@ func addManyTransactionsWithUniformDistribution(cache *TxCache, nSenders int, nT func createBunchesOfTransactionsWithUniformDistribution(nSenders int, nTransactionsPerSender int) []bunchOfTransactions { bunches := make([]bunchOfTransactions, 0, nSenders) - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() for senderTag := 0; senderTag < nSenders; senderTag++ { bunch := make(bunchOfTransactions, 0, nTransactionsPerSender) @@ -122,7 +125,7 @@ func createBunchesOfTransactionsWithUniformDistribution(nSenders int, nTransacti transactionHash := createFakeTxHash(sender, nonce) gasPrice := oneBillion + rand.Intn(3*oneBillion) transaction := createTx(transactionHash, string(sender), uint64(nonce)).withGasPrice(uint64(gasPrice)) - transaction.precomputeFields(txGasHandler) + transaction.precomputeFields(host) bunch = append(bunch, transaction) } diff --git a/txcache/transactionsHeapItem.go b/txcache/transactionsHeapItem.go index 97ce431a..5d09dd59 100644 --- a/txcache/transactionsHeapItem.go +++ b/txcache/transactionsHeapItem.go @@ -44,8 +44,8 @@ func newTransactionsHeapItem(bunch bunchOfTransactions) (*transactionsHeapItem, }, nil } -func (item *transactionsHeapItem) selectCurrentTransaction(session SelectionSession) *WrappedTransaction { - item.accumulateConsumedBalance(session) +func (item *transactionsHeapItem) selectCurrentTransaction() *WrappedTransaction { + item.accumulateConsumedBalance() item.latestSelectedTransaction = item.currentTransaction item.latestSelectedTransactionNonce = item.currentTransactionNonce @@ -53,13 +53,13 @@ func (item *transactionsHeapItem) selectCurrentTransaction(session SelectionSess return item.currentTransaction } -func (item *transactionsHeapItem) accumulateConsumedBalance(session SelectionSession) { +func (item *transactionsHeapItem) accumulateConsumedBalance() { fee := item.currentTransaction.Fee if fee != nil { item.consumedBalance.Add(item.consumedBalance, fee) } - transferredValue := session.GetTransferredValue(item.currentTransaction.Tx) + transferredValue := item.currentTransaction.TransferredValue if transferredValue != nil { item.consumedBalance.Add(item.consumedBalance, transferredValue) } diff --git a/txcache/transactionsHeapItem_test.go b/txcache/transactionsHeapItem_test.go index a1868cb3..55199472 100644 --- a/txcache/transactionsHeapItem_test.go +++ b/txcache/transactionsHeapItem_test.go @@ -38,18 +38,17 @@ func TestNewTransactionsHeapItem(t *testing.T) { } func TestTransactionsHeapItem_selectTransaction(t *testing.T) { - txGasHandler := txcachemocks.NewTxGasHandlerMock() - session := txcachemocks.NewSelectionSessionMock() + host := txcachemocks.NewMempoolHostMock() a := createTx([]byte("tx-1"), "alice", 42) b := createTx([]byte("tx-2"), "alice", 43) - a.precomputeFields(txGasHandler) - b.precomputeFields(txGasHandler) + a.precomputeFields(host) + b.precomputeFields(host) item, err := newTransactionsHeapItem(bunchOfTransactions{a, b}) require.NoError(t, err) - selected := item.selectCurrentTransaction(session) + selected := item.selectCurrentTransaction() require.Equal(t, a, selected) require.Equal(t, a, item.latestSelectedTransaction) require.Equal(t, 42, int(item.latestSelectedTransactionNonce)) @@ -58,7 +57,7 @@ func TestTransactionsHeapItem_selectTransaction(t *testing.T) { ok := item.gotoNextTransaction() require.True(t, ok) - selected = item.selectCurrentTransaction(session) + selected = item.selectCurrentTransaction() require.Equal(t, b, selected) require.Equal(t, b, item.latestSelectedTransaction) require.Equal(t, 43, int(item.latestSelectedTransactionNonce)) @@ -135,17 +134,17 @@ func TestTransactionsHeapItem_detectMiddleGap(t *testing.T) { } func TestTransactionsHeapItem_detectWillFeeExceedBalance(t *testing.T) { - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() a := createTx([]byte("tx-1"), "alice", 42) b := createTx([]byte("tx-2"), "alice", 43) c := createTx([]byte("tx-3"), "alice", 44).withValue(big.NewInt(1000000000000000000)) d := createTx([]byte("tx-4"), "alice", 45) - a.precomputeFields(txGasHandler) - b.precomputeFields(txGasHandler) - c.precomputeFields(txGasHandler) - d.precomputeFields(txGasHandler) + a.precomputeFields(host) + b.precomputeFields(host) + c.precomputeFields(host) + d.precomputeFields(host) t.Run("unknown", func(t *testing.T) { item, err := newTransactionsHeapItem(bunchOfTransactions{a, b}) @@ -155,8 +154,6 @@ func TestTransactionsHeapItem_detectWillFeeExceedBalance(t *testing.T) { }) t.Run("known, not exceeded, then exceeded (a)", func(t *testing.T) { - session := txcachemocks.NewSelectionSessionMock() - item, err := newTransactionsHeapItem(bunchOfTransactions{a, b}) require.NoError(t, err) @@ -166,7 +163,7 @@ func TestTransactionsHeapItem_detectWillFeeExceedBalance(t *testing.T) { require.False(t, item.detectWillFeeExceedBalance()) - _ = item.selectCurrentTransaction(session) + _ = item.selectCurrentTransaction() _ = item.gotoNextTransaction() require.Equal(t, "50000000000000", item.consumedBalance.String()) @@ -174,8 +171,6 @@ func TestTransactionsHeapItem_detectWillFeeExceedBalance(t *testing.T) { }) t.Run("known, not exceeded, then exceeded (b)", func(t *testing.T) { - session := txcachemocks.NewSelectionSessionMock() - item, err := newTransactionsHeapItem(bunchOfTransactions{a, b, c, d}) require.NoError(t, err) @@ -186,21 +181,21 @@ func TestTransactionsHeapItem_detectWillFeeExceedBalance(t *testing.T) { require.False(t, item.detectWillFeeExceedBalance()) // Select "a", move to "b". - _ = item.selectCurrentTransaction(session) + _ = item.selectCurrentTransaction() _ = item.gotoNextTransaction() require.Equal(t, "50000000000000", item.consumedBalance.String()) require.False(t, item.detectWillFeeExceedBalance()) // Select "b", move to "c". - _ = item.selectCurrentTransaction(session) + _ = item.selectCurrentTransaction() _ = item.gotoNextTransaction() require.Equal(t, "100000000000000", item.consumedBalance.String()) require.False(t, item.detectWillFeeExceedBalance()) // Select "c", move to "d". - _ = item.selectCurrentTransaction(session) + _ = item.selectCurrentTransaction() _ = item.gotoNextTransaction() require.Equal(t, "1000150000000000000", item.consumedBalance.String()) diff --git a/txcache/txCache.go b/txcache/txCache.go index 37f0c0be..df69c7ec 100644 --- a/txcache/txCache.go +++ b/txcache/txCache.go @@ -19,14 +19,14 @@ type TxCache struct { txListBySender *txListBySenderMap txByHash *txByHashMap config ConfigSourceMe - txGasHandler TxGasHandler + host MempoolHost evictionMutex sync.Mutex isEvictionInProgress atomic.Flag mutTxOperation sync.Mutex } // NewTxCache creates a new transaction cache -func NewTxCache(config ConfigSourceMe, txGasHandler TxGasHandler) (*TxCache, error) { +func NewTxCache(config ConfigSourceMe, host MempoolHost) (*TxCache, error) { log.Debug("NewTxCache", "config", config.String()) monitoring.MonitorNewCache(config.Name, uint64(config.NumBytesThreshold)) @@ -34,8 +34,8 @@ func NewTxCache(config ConfigSourceMe, txGasHandler TxGasHandler) (*TxCache, err if err != nil { return nil, err } - if check.IfNil(txGasHandler) { - return nil, errNilTxGasHandler + if check.IfNil(host) { + return nil, errNilMempoolHost } // Note: for simplicity, we use the same "numChunks" for both internal concurrent maps @@ -47,7 +47,7 @@ func NewTxCache(config ConfigSourceMe, txGasHandler TxGasHandler) (*TxCache, err txListBySender: newTxListBySenderMap(numChunks, senderConstraintsObj), txByHash: newTxByHashMap(numChunks), config: config, - txGasHandler: txGasHandler, + host: host, } return txCache, nil @@ -62,7 +62,7 @@ func (cache *TxCache) AddTx(tx *WrappedTransaction) (ok bool, added bool) { logAdd.Trace("TxCache.AddTx", "tx", tx.TxHash, "nonce", tx.Tx.GetNonce(), "sender", tx.Tx.GetSndAddr()) - tx.precomputeFields(cache.txGasHandler) + tx.precomputeFields(cache.host) if cache.config.EvictionEnabled { _ = cache.doEviction() diff --git a/txcache/txCache_test.go b/txcache/txCache_test.go index 88748e3a..d8984718 100644 --- a/txcache/txCache_test.go +++ b/txcache/txCache_test.go @@ -27,44 +27,44 @@ func Test_NewTxCache(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) badConfig := config badConfig.Name = "" - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.Name", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.Name", host) badConfig = config badConfig.NumChunks = 0 - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumChunks", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumChunks", host) badConfig = config badConfig.NumBytesPerSenderThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumBytesPerSenderThreshold", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumBytesPerSenderThreshold", host) badConfig = config badConfig.CountPerSenderThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.CountPerSenderThreshold", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.CountPerSenderThreshold", host) badConfig = config cache, err = NewTxCache(config, nil) require.Nil(t, cache) - require.Equal(t, errNilTxGasHandler, err) + require.Equal(t, errNilMempoolHost, err) badConfig = config badConfig.NumBytesThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumBytesThreshold", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.NumBytesThreshold", host) badConfig = config badConfig.CountThreshold = 0 - requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.CountThreshold", txGasHandler) + requireErrorOnNewTxCache(t, badConfig, common.ErrInvalidConfig, "config.CountThreshold", host) } -func requireErrorOnNewTxCache(t *testing.T, config ConfigSourceMe, errExpected error, errPartialMessage string, txGasHandler TxGasHandler) { - cache, errReceived := NewTxCache(config, txGasHandler) +func requireErrorOnNewTxCache(t *testing.T, config ConfigSourceMe, errExpected error, errPartialMessage string, host MempoolHost) { + cache, errReceived := NewTxCache(config, host) require.Nil(t, cache) require.True(t, errors.Is(errReceived, errExpected)) require.Contains(t, errReceived.Error(), errPartialMessage) @@ -310,7 +310,7 @@ func Test_Keys(t *testing.T) { } func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() t.Run("numSenders = 11, numTransactions = 10, countThreshold = 100, numItemsToPreemptivelyEvict = 1", func(t *testing.T) { config := ConfigSourceMe{ @@ -324,7 +324,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -348,7 +348,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumItemsToPreemptivelyEvict: 3, } - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -368,7 +368,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumItemsToPreemptivelyEvict: 2, } - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -388,7 +388,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumItemsToPreemptivelyEvict: 1, } - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -408,7 +408,7 @@ func Test_AddWithEviction_UniformDistributionOfTxsPerSender(t *testing.T) { NumItemsToPreemptivelyEvict: 10000, } - cache, err := NewTxCache(config, txGasHandler) + cache, err := NewTxCache(config, host) require.Nil(t, err) require.NotNil(t, cache) @@ -514,7 +514,7 @@ func TestTxCache_NoCriticalInconsistency_WhenConcurrentAdditionsAndRemovals(t *t } func newUnconstrainedCacheToTest() *TxCache { - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() cache, err := NewTxCache(ConfigSourceMe{ Name: "test", @@ -525,7 +525,7 @@ func newUnconstrainedCacheToTest() *TxCache { CountPerSenderThreshold: math.MaxUint32, EvictionEnabled: false, NumItemsToPreemptivelyEvict: 1, - }, txGasHandler) + }, host) if err != nil { panic(fmt.Sprintf("newUnconstrainedCacheToTest(): %s", err)) } @@ -534,7 +534,7 @@ func newUnconstrainedCacheToTest() *TxCache { } func newCacheToTest(numBytesPerSenderThreshold uint32, countPerSenderThreshold uint32) *TxCache { - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() cache, err := NewTxCache(ConfigSourceMe{ Name: "test", @@ -545,7 +545,7 @@ func newCacheToTest(numBytesPerSenderThreshold uint32, countPerSenderThreshold u CountPerSenderThreshold: countPerSenderThreshold, EvictionEnabled: false, NumItemsToPreemptivelyEvict: 1, - }, txGasHandler) + }, host) if err != nil { panic(fmt.Sprintf("newCacheToTest(): %s", err)) } diff --git a/txcache/wrappedTransaction.go b/txcache/wrappedTransaction.go index 6bcaf471..499c695e 100644 --- a/txcache/wrappedTransaction.go +++ b/txcache/wrappedTransaction.go @@ -21,18 +21,21 @@ type WrappedTransaction struct { // These fields are only set within "precomputeFields". // We don't need to protect them with a mutex, since "precomputeFields" is called only once for each transaction. // Additional note: "WrappedTransaction" objects are created by the Node, in dataRetriever/txpool/shardedTxPool.go. - Fee *big.Int - PricePerUnit uint64 + Fee *big.Int + PricePerUnit uint64 + TransferredValue *big.Int } // precomputeFields computes (and caches) the (average) price per gas unit. -func (wrappedTx *WrappedTransaction) precomputeFields(txGasHandler TxGasHandler) { - wrappedTx.Fee = txGasHandler.ComputeTxFee(wrappedTx.Tx) +func (wrappedTx *WrappedTransaction) precomputeFields(host MempoolHost) { + wrappedTx.Fee = host.ComputeTxFee(wrappedTx.Tx) gasLimit := wrappedTx.Tx.GetGasLimit() if gasLimit != 0 { wrappedTx.PricePerUnit = wrappedTx.Fee.Uint64() / gasLimit } + + wrappedTx.TransferredValue = host.GetTransferredValue(wrappedTx.Tx) } // Equality is out of scope (not possible in our case). diff --git a/txcache/wrappedTransaction_test.go b/txcache/wrappedTransaction_test.go index d479c365..398c97b2 100644 --- a/txcache/wrappedTransaction_test.go +++ b/txcache/wrappedTransaction_test.go @@ -1,34 +1,41 @@ package txcache import ( + "math/big" "testing" + "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-storage-go/testscommon/txcachemocks" "github.com/stretchr/testify/require" ) func TestWrappedTransaction_precomputeFields(t *testing.T) { - txGasHandler := txcachemocks.NewTxGasHandlerMock() - t.Run("only move balance gas limit", func(t *testing.T) { - tx := createTx([]byte("a"), "a", 1).withDataLength(1).withGasLimit(51500).withGasPrice(oneBillion) - tx.precomputeFields(txGasHandler) + host := txcachemocks.NewMempoolHostMock() + + tx := createTx([]byte("a"), "a", 1).withValue(oneQuintillionBig).withDataLength(1).withGasLimit(51500).withGasPrice(oneBillion) + tx.precomputeFields(host) require.Equal(t, "51500000000000", tx.Fee.String()) require.Equal(t, oneBillion, int(tx.PricePerUnit)) + require.Equal(t, "1000000000000000000", tx.TransferredValue.String()) }) t.Run("move balance gas limit and execution gas limit (a)", func(t *testing.T) { + host := txcachemocks.NewMempoolHostMock() + tx := createTx([]byte("b"), "b", 1).withDataLength(1).withGasLimit(51501).withGasPrice(oneBillion) - tx.precomputeFields(txGasHandler) + tx.precomputeFields(host) require.Equal(t, "51500010000000", tx.Fee.String()) require.Equal(t, 999_980_777, int(tx.PricePerUnit)) }) t.Run("move balance gas limit and execution gas limit (b)", func(t *testing.T) { + host := txcachemocks.NewMempoolHostMock() + tx := createTx([]byte("c"), "c", 1).withDataLength(1).withGasLimit(oneMilion).withGasPrice(oneBillion) - tx.precomputeFields(txGasHandler) + tx.precomputeFields(host) actualFee := 51500*oneBillion + (oneMilion-51500)*oneBillion/100 require.Equal(t, "60985000000000", tx.Fee.String()) @@ -37,33 +44,61 @@ func TestWrappedTransaction_precomputeFields(t *testing.T) { }) t.Run("with guardian", func(t *testing.T) { - tx := createTx([]byte("a"), "a", 1) - tx.precomputeFields(txGasHandler) + host := txcachemocks.NewMempoolHostMock() + + tx := createTx([]byte("a"), "a", 1).withValue(oneQuintillionBig) + tx.precomputeFields(host) require.Equal(t, "50000000000000", tx.Fee.String()) require.Equal(t, oneBillion, int(tx.PricePerUnit)) + require.Equal(t, "1000000000000000000", tx.TransferredValue.String()) + }) + + t.Run("with nil transferred value", func(t *testing.T) { + host := txcachemocks.NewMempoolHostMock() + + tx := createTx([]byte("a"), "a", 1) + tx.precomputeFields(host) + + require.Nil(t, tx.TransferredValue) + }) + + t.Run("queries host", func(t *testing.T) { + host := txcachemocks.NewMempoolHostMock() + host.ComputeTxFeeCalled = func(_ data.TransactionWithFeeHandler) *big.Int { + return big.NewInt(42) + } + host.GetTransferredValueCalled = func(_ data.TransactionHandler) *big.Int { + return big.NewInt(43) + } + + tx := createTx([]byte("a"), "a", 1).withGasLimit(50_000) + tx.precomputeFields(host) + + require.Equal(t, "42", tx.Fee.String()) + require.Equal(t, "43", tx.TransferredValue.String()) }) } func TestWrappedTransaction_isTransactionMoreValuableForNetwork(t *testing.T) { - txGasHandler := txcachemocks.NewTxGasHandlerMock() + host := txcachemocks.NewMempoolHostMock() t.Run("decide by price per unit", func(t *testing.T) { a := createTx([]byte("a-1"), "a", 1).withDataLength(1).withGasLimit(51500).withGasPrice(oneBillion) - a.precomputeFields(txGasHandler) + a.precomputeFields(host) b := createTx([]byte("b-1"), "b", 1).withDataLength(1).withGasLimit(51501).withGasPrice(oneBillion) - b.precomputeFields(txGasHandler) + b.precomputeFields(host) require.True(t, a.isTransactionMoreValuableForNetwork(b)) }) t.Run("decide by gas limit (set them up to have the same PPU)", func(t *testing.T) { a := createTx([]byte("a-7"), "a", 7).withDataLength(30).withGasLimit(95_000).withGasPrice(oneBillion) - a.precomputeFields(txGasHandler) + a.precomputeFields(host) b := createTx([]byte("b-7"), "b", 7).withDataLength(60).withGasLimit(140_000).withGasPrice(oneBillion) - b.precomputeFields(txGasHandler) + b.precomputeFields(host) require.Equal(t, a.PricePerUnit, b.PricePerUnit) require.True(t, b.isTransactionMoreValuableForNetwork(a)) @@ -71,10 +106,10 @@ func TestWrappedTransaction_isTransactionMoreValuableForNetwork(t *testing.T) { t.Run("decide by transaction hash (set them up to have the same PPU and gas limit)", func(t *testing.T) { a := createTx([]byte("a-7"), "a", 7) - a.precomputeFields(txGasHandler) + a.precomputeFields(host) b := createTx([]byte("b-7"), "b", 7) - b.precomputeFields(txGasHandler) + b.precomputeFields(host) require.Equal(t, a.PricePerUnit, b.PricePerUnit) require.True(t, a.isTransactionMoreValuableForNetwork(b))