forked from TrueCloudLab/neoneo-go
mempool: use uint256 library for fee tracking
It's very effective in avoiding allocations for big.Int, we don't have a microbenchmark for memppol, but this improves TPS metrics by ~1-2%, so it's noticeable.
This commit is contained in:
parent
ee05f73b6f
commit
748a70569a
4 changed files with 32 additions and 30 deletions
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/btcsuite/btcd v0.22.0-beta
|
github.com/btcsuite/btcd v0.22.0-beta
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
github.com/holiman/uint256 v1.2.0
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac
|
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -128,6 +128,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||||
|
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
|
|
@ -3,11 +3,11 @@ package mempool
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -50,8 +50,8 @@ type items []item
|
||||||
// utilityBalanceAndFees stores sender's balance and overall fees of
|
// utilityBalanceAndFees stores sender's balance and overall fees of
|
||||||
// sender's transactions which are currently in mempool.
|
// sender's transactions which are currently in mempool.
|
||||||
type utilityBalanceAndFees struct {
|
type utilityBalanceAndFees struct {
|
||||||
balance *big.Int
|
balance uint256.Int
|
||||||
feeSum *big.Int
|
feeSum uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool stores the unconfirms transactions.
|
// Pool stores the unconfirms transactions.
|
||||||
|
@ -164,8 +164,7 @@ func (mp *Pool) tryAddSendersFee(tx *transaction.Transaction, feer Feer, needChe
|
||||||
payer := tx.Signers[mp.payerIndex].Account
|
payer := tx.Signers[mp.payerIndex].Account
|
||||||
senderFee, ok := mp.fees[payer]
|
senderFee, ok := mp.fees[payer]
|
||||||
if !ok {
|
if !ok {
|
||||||
senderFee.balance = feer.GetUtilityTokenBalance(payer)
|
_ = senderFee.balance.SetFromBig(feer.GetUtilityTokenBalance(payer))
|
||||||
senderFee.feeSum = big.NewInt(0)
|
|
||||||
mp.fees[payer] = senderFee
|
mp.fees[payer] = senderFee
|
||||||
}
|
}
|
||||||
if needCheck {
|
if needCheck {
|
||||||
|
@ -173,23 +172,26 @@ func (mp *Pool) tryAddSendersFee(tx *transaction.Transaction, feer Feer, needChe
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
senderFee.feeSum.Set(newFeeSum)
|
senderFee.feeSum = newFeeSum
|
||||||
} else {
|
} else {
|
||||||
senderFee.feeSum.Add(senderFee.feeSum, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
senderFee.feeSum.AddUint64(&senderFee.feeSum, uint64(tx.SystemFee+tx.NetworkFee))
|
||||||
}
|
}
|
||||||
|
mp.fees[payer] = senderFee
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkBalance returns new cumulative fee balance for account or an error in
|
// checkBalance returns new cumulative fee balance for account or an error in
|
||||||
// case sender doesn't have enough GAS to pay for the transaction.
|
// case sender doesn't have enough GAS to pay for the transaction.
|
||||||
func checkBalance(tx *transaction.Transaction, balance utilityBalanceAndFees) (*big.Int, error) {
|
func checkBalance(tx *transaction.Transaction, balance utilityBalanceAndFees) (uint256.Int, error) {
|
||||||
txFee := big.NewInt(tx.SystemFee + tx.NetworkFee)
|
var txFee uint256.Int
|
||||||
if balance.balance.Cmp(txFee) < 0 {
|
|
||||||
return nil, ErrInsufficientFunds
|
txFee.SetUint64(uint64(tx.SystemFee + tx.NetworkFee))
|
||||||
|
if balance.balance.Cmp(&txFee) < 0 {
|
||||||
|
return txFee, ErrInsufficientFunds
|
||||||
}
|
}
|
||||||
txFee.Add(txFee, balance.feeSum)
|
txFee.Add(&txFee, &balance.feeSum)
|
||||||
if balance.balance.Cmp(txFee) < 0 {
|
if balance.balance.Cmp(&txFee) < 0 {
|
||||||
return nil, ErrConflict
|
return txFee, ErrConflict
|
||||||
}
|
}
|
||||||
return txFee, nil
|
return txFee, nil
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,7 @@ func (mp *Pool) removeInternal(hash util.Uint256, feer Feer) {
|
||||||
}
|
}
|
||||||
payer := itm.txn.Signers[mp.payerIndex].Account
|
payer := itm.txn.Signers[mp.payerIndex].Account
|
||||||
senderFee := mp.fees[payer]
|
senderFee := mp.fees[payer]
|
||||||
senderFee.feeSum.Sub(senderFee.feeSum, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
senderFee.feeSum.SubUint64(&senderFee.feeSum, uint64(tx.SystemFee+tx.NetworkFee))
|
||||||
mp.fees[payer] = senderFee
|
mp.fees[payer] = senderFee
|
||||||
if feer.P2PSigExtensionsEnabled() {
|
if feer.P2PSigExtensionsEnabled() {
|
||||||
// remove all conflicting hashes from mp.conflicts list
|
// remove all conflicting hashes from mp.conflicts list
|
||||||
|
@ -507,8 +509,7 @@ func (mp *Pool) checkTxConflicts(tx *transaction.Transaction, fee Feer) ([]*tran
|
||||||
payer := tx.Signers[mp.payerIndex].Account
|
payer := tx.Signers[mp.payerIndex].Account
|
||||||
actualSenderFee, ok := mp.fees[payer]
|
actualSenderFee, ok := mp.fees[payer]
|
||||||
if !ok {
|
if !ok {
|
||||||
actualSenderFee.balance = fee.GetUtilityTokenBalance(payer)
|
actualSenderFee.balance.SetFromBig(fee.GetUtilityTokenBalance(payer))
|
||||||
actualSenderFee.feeSum = big.NewInt(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedSenderFee utilityBalanceAndFees
|
var expectedSenderFee utilityBalanceAndFees
|
||||||
|
@ -541,13 +542,10 @@ func (mp *Pool) checkTxConflicts(tx *transaction.Transaction, fee Feer) ([]*tran
|
||||||
conflictsToBeRemoved = append(conflictsToBeRemoved, existingTx)
|
conflictsToBeRemoved = append(conflictsToBeRemoved, existingTx)
|
||||||
}
|
}
|
||||||
// Step 3: take into account sender's conflicting transactions before balance check.
|
// Step 3: take into account sender's conflicting transactions before balance check.
|
||||||
expectedSenderFee = utilityBalanceAndFees{
|
expectedSenderFee = actualSenderFee
|
||||||
balance: new(big.Int).Set(actualSenderFee.balance),
|
|
||||||
feeSum: new(big.Int).Set(actualSenderFee.feeSum),
|
|
||||||
}
|
|
||||||
for _, conflictingTx := range conflictsToBeRemoved {
|
for _, conflictingTx := range conflictsToBeRemoved {
|
||||||
if conflictingTx.Signers[mp.payerIndex].Account.Equals(payer) {
|
if conflictingTx.Signers[mp.payerIndex].Account.Equals(payer) {
|
||||||
expectedSenderFee.feeSum.Sub(expectedSenderFee.feeSum, big.NewInt(conflictingTx.SystemFee+conflictingTx.NetworkFee))
|
expectedSenderFee.feeSum.SubUint64(&expectedSenderFee.feeSum, uint64(conflictingTx.SystemFee+conflictingTx.NetworkFee))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
|
@ -268,8 +269,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.NoError(t, mp.Add(tx1, fs))
|
require.NoError(t, mp.Add(tx1, fs))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(tx1.NetworkFee),
|
feeSum: *uint256.NewInt(uint64(tx1.NetworkFee)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// balance shouldn't change after adding one more transaction
|
// balance shouldn't change after adding one more transaction
|
||||||
|
@ -280,8 +281,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.Equal(t, 2, len(mp.verifiedTxes))
|
require.Equal(t, 2, len(mp.verifiedTxes))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(fs.balance),
|
feeSum: *uint256.NewInt(uint64(fs.balance)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// can't add more transactions as we don't have enough GAS
|
// can't add more transactions as we don't have enough GAS
|
||||||
|
@ -292,8 +293,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.Error(t, mp.Add(tx3, fs))
|
require.Error(t, mp.Add(tx3, fs))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(fs.balance),
|
feeSum: *uint256.NewInt(uint64(fs.balance)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// check whether sender's fee updates correctly
|
// check whether sender's fee updates correctly
|
||||||
|
@ -302,8 +303,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
}, fs)
|
}, fs)
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(tx2.NetworkFee),
|
feeSum: *uint256.NewInt(uint64(tx2.NetworkFee)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// there should be nothing left
|
// there should be nothing left
|
||||||
|
|
Loading…
Reference in a new issue