Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply new dust prevention KIP to miner's selection policy #2239

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions domain/dagconfig/consensus_defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,6 @@ const (
defaultDeflationaryPhaseDaaScore = 15778800 - 259200

defaultMergeDepth = 3600

defaultDustConst = 1e12 // TODO: Determine the right value
)
6 changes: 6 additions & 0 deletions domain/dagconfig/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ type Params struct {
MaxBlockLevel int

MergeDepth uint64

DustConst uint64
}

// NormalizeRPCServerAddress returns addr with the current network default
Expand Down Expand Up @@ -288,6 +290,7 @@ var MainnetParams = Params{
// This means that any block that has a level lower or equal to genesis will be level 0.
MaxBlockLevel: 225,
MergeDepth: defaultMergeDepth,
DustConst: defaultDustConst,
}

// TestnetParams defines the network parameters for the test Kaspa network.
Expand Down Expand Up @@ -354,6 +357,7 @@ var TestnetParams = Params{

MaxBlockLevel: 250,
MergeDepth: defaultMergeDepth,
DustConst: defaultDustConst,
}

// SimnetParams defines the network parameters for the simulation test Kaspa
Expand Down Expand Up @@ -420,6 +424,7 @@ var SimnetParams = Params{

MaxBlockLevel: 250,
MergeDepth: defaultMergeDepth,
DustConst: defaultDustConst,
}

// DevnetParams defines the network parameters for the development Kaspa network.
Expand Down Expand Up @@ -482,6 +487,7 @@ var DevnetParams = Params{

MaxBlockLevel: 250,
MergeDepth: defaultMergeDepth,
DustConst: defaultDustConst,
}

// ErrDuplicateNet describes an error where the parameters for a Kaspa
Expand Down
25 changes: 15 additions & 10 deletions domain/miningmanager/blocktemplatebuilder/blocktemplatebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/kaspanet/kaspad/domain/consensusreference"
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
"github.com/kaspanet/kaspad/util/mstime"
"math"
"sort"
Expand All @@ -22,6 +23,7 @@ type candidateTx struct {
*consensusexternalapi.DomainTransaction
txValue float64
gasLimit uint64
mass uint64

p float64
start float64
Expand All @@ -41,11 +43,11 @@ type blockTemplateBuilder struct {

// New creates a new blockTemplateBuilder
func New(consensusReference consensusreference.ConsensusReference, mempool miningmanagerapi.Mempool,
blockMaxMass uint64, coinbasePayloadScriptPublicKeyMaxLength uint8) miningmanagerapi.BlockTemplateBuilder {
blockMaxMass uint64, coinbasePayloadScriptPublicKeyMaxLength uint8, dustConst uint64) miningmanagerapi.BlockTemplateBuilder {
return &blockTemplateBuilder{
consensusReference: consensusReference,
mempool: mempool,
policy: policy{BlockMaxMass: blockMaxMass},
policy: policy{BlockMaxMass: blockMaxMass, DustConst: dustConst},

coinbasePayloadScriptPublicKeyMaxLength: coinbasePayloadScriptPublicKeyMaxLength,
}
Expand Down Expand Up @@ -121,15 +123,18 @@ func (btb *blockTemplateBuilder) BuildBlockTemplate(
mempoolTransactions := btb.mempool.BlockCandidateTransactions()
candidateTxs := make([]*candidateTx, 0, len(mempoolTransactions))
for _, tx := range mempoolTransactions {
// Calculate the tx value
if tx.Mass() == 0 {
panic(errors.Errorf("BuildBlockTemplate expects transactions with populated mass: %s has 0 mass", tx.TransactionID()))
}
gasLimit := uint64(0)
if !subnetworks.IsBuiltInOrNative(tx.SubnetworkID) {
if !subnetworks.IsBuiltInOrNative(tx.Transaction().SubnetworkID) {
panic("We currently don't support non native subnetworks")
}
candidateTxs = append(candidateTxs, &candidateTx{
DomainTransaction: tx,
DomainTransaction: tx.Transaction(),
txValue: btb.calcTxValue(tx),
gasLimit: gasLimit,
mass: tx.Mass(),
})
}

Expand Down Expand Up @@ -208,15 +213,15 @@ func (btb *blockTemplateBuilder) ModifyBlockTemplate(newCoinbaseData *consensuse
// calcTxValue calculates a value to be used in transaction selection.
// The higher the number the more likely it is that the transaction will be
// included in the block.
func (btb *blockTemplateBuilder) calcTxValue(tx *consensusexternalapi.DomainTransaction) float64 {
func (btb *blockTemplateBuilder) calcTxValue(tx *model.MempoolTransaction) float64 {
massLimit := btb.policy.BlockMaxMass

mass := tx.Mass
fee := tx.Fee
if subnetworks.IsBuiltInOrNative(tx.SubnetworkID) {
mass := tx.Mass()
fee := tx.Transaction().Fee
if subnetworks.IsBuiltInOrNative(tx.Transaction().SubnetworkID) {
return float64(fee) / (float64(mass) / float64(massLimit))
}
// TODO: Replace with real gas once implemented
gasLimit := uint64(math.MaxUint64)
return float64(fee) / (float64(mass)/float64(massLimit) + float64(tx.Gas)/float64(gasLimit))
return float64(fee) / (float64(mass)/float64(massLimit) + float64(tx.Transaction().Gas)/float64(gasLimit))
}
2 changes: 2 additions & 0 deletions domain/miningmanager/blocktemplatebuilder/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ type policy struct {
// BlockMaxMass is the maximum block mass to be used when generating a
// block template.
BlockMaxMass uint64

DustConst uint64
}
10 changes: 5 additions & 5 deletions domain/miningmanager/blocktemplatebuilder/txselection.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)

// Enforce maximum transaction mass per block. Also check
// for overflow.
if txsForBlockTemplate.totalMass+selectedTx.Mass < txsForBlockTemplate.totalMass ||
txsForBlockTemplate.totalMass+selectedTx.Mass > btb.policy.BlockMaxMass {
if txsForBlockTemplate.totalMass+selectedTx.mass < txsForBlockTemplate.totalMass ||
txsForBlockTemplate.totalMass+selectedTx.mass > btb.policy.BlockMaxMass {
log.Tracef("Tx %s would exceed the max block mass. "+
"As such, stopping.", consensushashing.TransactionID(tx))
break
Expand Down Expand Up @@ -143,11 +143,11 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)
// save the masses, fees, and signature operation counts to the
// result.
selectedTxs = append(selectedTxs, selectedTx)
txsForBlockTemplate.totalMass += selectedTx.Mass
txsForBlockTemplate.totalMass += selectedTx.mass
txsForBlockTemplate.totalFees += selectedTx.Fee

log.Tracef("Adding tx %s (feePerMegaGram %d)",
consensushashing.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.Mass)
consensushashing.TransactionID(tx), selectedTx.Fee*1e6/selectedTx.mass)

markCandidateTxForDeletion(selectedTx)
}
Expand All @@ -157,7 +157,7 @@ func (btb *blockTemplateBuilder) selectTransactions(candidateTxs []*candidateTx)
})
for _, selectedTx := range selectedTxs {
txsForBlockTemplate.selectedTxs = append(txsForBlockTemplate.selectedTxs, selectedTx.DomainTransaction)
txsForBlockTemplate.txMasses = append(txsForBlockTemplate.txMasses, selectedTx.Mass)
txsForBlockTemplate.txMasses = append(txsForBlockTemplate.txMasses, selectedTx.mass)
txsForBlockTemplate.txFees = append(txsForBlockTemplate.txFees, selectedTx.Fee)
}
return txsForBlockTemplate
Expand Down
2 changes: 1 addition & 1 deletion domain/miningmanager/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (f *factory) NewMiningManager(consensusReference consensusreference.Consens
mempoolConfig *mempoolpkg.Config) MiningManager {

mempool := mempoolpkg.New(mempoolConfig, consensusReference)
blockTemplateBuilder := blocktemplatebuilder.New(consensusReference, mempool, params.MaxBlockMass, params.CoinbasePayloadScriptPublicKeyMaxLength)
blockTemplateBuilder := blocktemplatebuilder.New(consensusReference, mempool, params.MaxBlockMass, params.CoinbasePayloadScriptPublicKeyMaxLength, params.DustConst)

return &miningManager{
consensusReference: consensusReference,
Expand Down
3 changes: 3 additions & 0 deletions domain/miningmanager/mempool/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
// as consensus.
defaultMinimumStandardTransactionVersion = constants.MaxTransactionVersion
defaultMaximumStandardTransactionVersion = constants.MaxTransactionVersion
defaultDustConst = 1e12 // TODO: Determine real value
)

// Config represents a mempool configuration
Expand All @@ -50,6 +51,7 @@ type Config struct {
MinimumRelayTransactionFee util.Amount
MinimumStandardTransactionVersion uint16
MaximumStandardTransactionVersion uint16
DustConst uint64
}

// DefaultConfig returns the default mempool configuration
Expand All @@ -70,5 +72,6 @@ func DefaultConfig(dagParams *dagconfig.Params) *Config {
MinimumRelayTransactionFee: defaultMinimumRelayTransactionFee,
MinimumStandardTransactionVersion: defaultMinimumStandardTransactionVersion,
MaximumStandardTransactionVersion: defaultMaximumStandardTransactionVersion,
DustConst: defaultDustConst,
}
}
3 changes: 2 additions & 1 deletion domain/miningmanager/mempool/mempool.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mempool

import (
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
"sync"

"github.com/kaspanet/kaspad/domain/consensusreference"
Expand Down Expand Up @@ -137,7 +138,7 @@ func (mp *mempool) HandleNewBlockTransactions(transactions []*externalapi.Domain
return mp.handleNewBlockTransactions(transactions)
}

func (mp *mempool) BlockCandidateTransactions() []*externalapi.DomainTransaction {
func (mp *mempool) BlockCandidateTransactions() []*model.MempoolTransaction {
mp.mtx.RLock()
defer mp.mtx.RUnlock()

Expand Down
17 changes: 17 additions & 0 deletions domain/miningmanager/mempool/model/mempool_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
parentTransactionsInPool IDToTransactionMap
isHighPriority bool
addedAtDAAScore uint64
mass uint64
}

// NewMempoolTransaction constructs a new MempoolTransaction
Expand All @@ -19,12 +20,14 @@
parentTransactionsInPool IDToTransactionMap,
isHighPriority bool,
addedAtDAAScore uint64,
mass uint64,
) *MempoolTransaction {
return &MempoolTransaction{
transaction: transaction,
parentTransactionsInPool: parentTransactionsInPool,
isHighPriority: isHighPriority,
addedAtDAAScore: addedAtDAAScore,
mass: mass,
}
}

Expand Down Expand Up @@ -57,3 +60,17 @@
func (mt *MempoolTransaction) AddedAtDAAScore() uint64 {
return mt.addedAtDAAScore
}

func (mt *MempoolTransaction) Mass() uint64 {

Check failure on line 64 in domain/miningmanager/mempool/model/mempool_transaction.go

View workflow job for this annotation

GitHub Actions / Tests, ubuntu-latest

exported method MempoolTransaction.Mass should have comment or be unexported

Check failure on line 64 in domain/miningmanager/mempool/model/mempool_transaction.go

View workflow job for this annotation

GitHub Actions / Tests, macos-latest

exported method MempoolTransaction.Mass should have comment or be unexported
return mt.mass
}

func (mt *MempoolTransaction) Clone() *MempoolTransaction {

Check failure on line 68 in domain/miningmanager/mempool/model/mempool_transaction.go

View workflow job for this annotation

GitHub Actions / Tests, ubuntu-latest

exported method MempoolTransaction.Clone should have comment or be unexported

Check failure on line 68 in domain/miningmanager/mempool/model/mempool_transaction.go

View workflow job for this annotation

GitHub Actions / Tests, macos-latest

exported method MempoolTransaction.Clone should have comment or be unexported
return &MempoolTransaction{
transaction: mt.transaction.Clone(),
parentTransactionsInPool: mt.parentTransactionsInPool,
isHighPriority: mt.isHighPriority,
addedAtDAAScore: mt.addedAtDAAScore,
mass: mt.mass,
}
}
1 change: 1 addition & 0 deletions domain/miningmanager/mempool/orphan_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func (op *orphansPool) unorphanTransaction(transaction *model.OrphanTransaction)
op.mempool.transactionsPool.getParentTransactionsInPool(transaction.Transaction()),
false,
virtualDAAScore,
0,
)
err = op.mempool.transactionsPool.addMempoolTransaction(mempoolTransaction)
if err != nil {
Expand Down
29 changes: 25 additions & 4 deletions domain/miningmanager/mempool/transactions_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransa
}

mempoolTransaction := model.NewMempoolTransaction(
transaction, parentTransactionsInPool, isHighPriority, virtualDAAScore)
transaction, parentTransactionsInPool, isHighPriority, virtualDAAScore, tp.calcMass(transaction))

err = tp.addMempoolTransaction(mempoolTransaction)
if err != nil {
Expand All @@ -51,6 +51,27 @@ func (tp *transactionsPool) addTransaction(transaction *externalapi.DomainTransa
return mempoolTransaction, nil
}

func (tp *transactionsPool) calcMass(tx *externalapi.DomainTransaction) uint64 {
// TODO: Insert link for relevant KIP
if tx.Mass == 0 {
panic(errors.Errorf("tx %s is expected to have a populated mass", consensushashing.TransactionID(tx)))
}

addedMass := uint64(0)
sumOutsValue := uint64(0)
for _, output := range tx.Outputs {
addedMass += tp.mempool.config.DustConst / output.Value
sumOutsValue += output.Value
}

reducedMass := uint64(len(tx.Inputs)*len(tx.Inputs)) * tp.mempool.config.DustConst / sumOutsValue
if addedMass < reducedMass {
return tx.Mass
}

return tx.Mass + addedMass - reducedMass
}

func (tp *transactionsPool) addMempoolTransaction(transaction *model.MempoolTransaction) error {
tp.allTransactions[*transaction.TransactionID()] = transaction

Expand Down Expand Up @@ -131,12 +152,12 @@ func (tp *transactionsPool) expireOldTransactions() error {
return nil
}

func (tp *transactionsPool) allReadyTransactions() []*externalapi.DomainTransaction {
result := []*externalapi.DomainTransaction{}
func (tp *transactionsPool) allReadyTransactions() []*model.MempoolTransaction {
result := []*model.MempoolTransaction{}

for _, mempoolTransaction := range tp.allTransactions {
if len(mempoolTransaction.ParentTransactionsInPool()) == 0 {
result = append(result, mempoolTransaction.Transaction().Clone()) //this pointer leaves the mempool, and gets its utxo set to nil, hence we clone.
result = append(result, mempoolTransaction.Clone()) //this pointer leaves the mempool, and gets its utxo set to nil, hence we clone.
}
}

Expand Down
3 changes: 2 additions & 1 deletion domain/miningmanager/model/interface_mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package model

import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
)

// Mempool maintains a set of known transactions that
// are intended to be mined into new blocks
type Mempool interface {
HandleNewBlockTransactions(txs []*externalapi.DomainTransaction) ([]*externalapi.DomainTransaction, error)
BlockCandidateTransactions() []*externalapi.DomainTransaction
BlockCandidateTransactions() []*model.MempoolTransaction
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
acceptedTransactions []*externalapi.DomainTransaction, err error)
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
Expand Down
2 changes: 1 addition & 1 deletion version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
const (
appMajor uint = 0
appMinor uint = 12
appPatch uint = 13
appPatch uint = 15
)

// appBuild is defined as a variable so it can be overridden during the build
Expand Down
Loading