Skip to content

Commit

Permalink
Move "GetTransferredValue()" to "MempoolHost". Define transferred val…
Browse files Browse the repository at this point in the history
…ue as a "precomputed" field.
  • Loading branch information
andreibancioiu committed Nov 28, 2024
1 parent 77bbd7a commit ea3ee2d
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 39 deletions.
22 changes: 16 additions & 6 deletions testscommon/txcachemocks/mempoolHostMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ type MempoolHostMock struct {
minGasPrice uint64
gasPerDataByte uint64
gasPriceModifier float64

ComputeTxFeeCalled func(tx data.TransactionWithFeeHandler) *big.Int
GetTransferredValueCalled func(tx data.TransactionHandler) *big.Int
}

// NewMempoolHostMock -
Expand All @@ -25,14 +28,12 @@ func NewMempoolHostMock() *MempoolHostMock {
}
}

// WithGasPriceModifier -
func (mock *MempoolHostMock) WithGasPriceModifier(gasPriceModifier float64) *MempoolHostMock {
mock.gasPriceModifier = gasPriceModifier
return mock
}

// ComputeTxFee -
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) * mock.gasPriceModifier)
Expand All @@ -49,6 +50,15 @@ func (mock *MempoolHostMock) 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 (mock *MempoolHostMock) IsInterfaceNil() bool {
return mock == nil
Expand Down
10 changes: 0 additions & 10 deletions testscommon/txcachemocks/selectionSessionMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 -
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion txcache/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import (
// MempoolHost provides blockchain information for mempool operations
type MempoolHost interface {
ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int
GetTransferredValue(tx data.TransactionHandler) *big.Int
IsInterfaceNil() bool
}

// SelectionSession provides blockchain information for transaction selection
type SelectionSession interface {
GetAccountState(accountKey []byte) (*types.AccountState, error)
IsIncorrectlyGuarded(tx data.TransactionHandler) bool
GetTransferredValue(tx data.TransactionHandler) *big.Int
IsInterfaceNil() bool
}

Expand Down
2 changes: 1 addition & 1 deletion txcache/selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
3 changes: 3 additions & 0 deletions txcache/testutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 4 additions & 4 deletions txcache/transactionsHeapItem.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,22 @@ 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

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)
}
Expand Down
17 changes: 6 additions & 11 deletions txcache/transactionsHeapItem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ func TestNewTransactionsHeapItem(t *testing.T) {

func TestTransactionsHeapItem_selectTransaction(t *testing.T) {
host := txcachemocks.NewMempoolHostMock()
session := txcachemocks.NewSelectionSessionMock()

a := createTx([]byte("tx-1"), "alice", 42)
b := createTx([]byte("tx-2"), "alice", 43)
Expand All @@ -49,7 +48,7 @@ func TestTransactionsHeapItem_selectTransaction(t *testing.T) {
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))
Expand All @@ -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))
Expand Down Expand Up @@ -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)

Expand All @@ -166,16 +163,14 @@ 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())
require.True(t, item.detectWillFeeExceedBalance())
})

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)

Expand All @@ -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())
Expand Down
7 changes: 5 additions & 2 deletions txcache/wrappedTransaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ 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.
Expand All @@ -33,6 +34,8 @@ func (wrappedTx *WrappedTransaction) precomputeFields(host MempoolHost) {
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).
Expand Down
43 changes: 39 additions & 4 deletions txcache/wrappedTransaction_test.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
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) {
host := txcachemocks.NewMempoolHostMock()

t.Run("only move balance gas limit", func(t *testing.T) {
tx := createTx([]byte("a"), "a", 1).withDataLength(1).withGasLimit(51500).withGasPrice(oneBillion)
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(host)

Expand All @@ -27,6 +32,8 @@ func TestWrappedTransaction_precomputeFields(t *testing.T) {
})

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(host)

Expand All @@ -37,11 +44,39 @@ func TestWrappedTransaction_precomputeFields(t *testing.T) {
})

t.Run("with guardian", func(t *testing.T) {
tx := createTx([]byte("a"), "a", 1)
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())
})
}

Expand Down

0 comments on commit ea3ee2d

Please sign in to comment.