kaspad/mining/test_utils.go
stasatdaglabs 70737e4e94 [NOD-264] Implement tx-selection algorithm (#358)
* [NOD-264] Implemented calcTxSelectionValue.

* [NOD-264] Fixed bad subnetworkID in calcTxSelectionValue.

* [NOD-264] Implemented sorting the txDescs by value.

* [NOD-264] Got rid of txPrioItem.

* [NOD-264] Moved transaction selection to a separate file.

* [NOD-264] Renamed the result object to txsForBlockTemplate.

* [NOD-264] Implemented tx selection.

* [NOD-264] Fixed trying to get the gas limit for built-in subnetworks.

* [NOD-264] Wrote comments where appropriate.

* [NOD-264] Moved calcTxSelectionValue to the mining package. (Non-mining nodes shouldn't be forced to calc selection value for every transaction)

* [NOD-264] Wrote a test for selectTxs.

* [NOD-264] Fixed a comment.

* [NOD-264] Fixed misunderstood test.

* [NOD-264] Added zero fee check. Added a couple more tests.

* [NOD-264] Added probabilistic tests. Fixed a couple of bugs in tx selection.

* [NOD-264] Fixed tests with missing fees.

* [NOD-264] Added a test over a range of txs with different gas/mass.

* [NOD-264] Added expected probability to the rest of the test cases.

* [NOD-264] Tightened bounds in probability test.

* [NOD-264] Fixed values in probabily test.

* [NOD-264] Added a comments for alpha and rebalanceThreshold.

* [NOD-264] Fixed a couple of comments, renamed result to txsForBlockTemplate.

* [NOD-264] Removed an irrelevant comment. Changed Tracef to Warnf in some logs.

* [NOD-264] Renamed selectionValue -> txValue.

* [NOD-264] Moved rebalancing to the start of the tx selection loop.

* [NOD-264] Added overflow check for gasUsage.

* [NOD-264] Renamed blockSigOps and blockMass to totalSigOps and totalMass.

* [NOD-264] Removed the need to pass usedCount to reblanaceCandidates. Also relaxed bounds in a test.

* [NOD-264] Split selectTxs into smaller functions. Also relaxed bounds in a test some more.

* [NOD-264] Added a comment for findTx.

* [NOD-264] Ordered candidateTxs by subnetwork instead of txValue.

* [NOD-264] Disallowed zero tx fees in mempool and config. Renamed iterateCandidateTxs to populateTemplateFromCandidates.

* [NOD-264] Changed isFinalizedTransaction log level from Warn to Debug.

* [NOD-264] Removed references to SigOps in txSelection.

* [NOD-264] Removed SigOps validation. Validating mass should suffice.

* [NOD-264] Renamed wasUsed to isMarkedForDeletion.

* [NOD-264] Renamed markCandidateTxUsed to markCandidateTxForDeletion.

* [NOD-264] Made some probabilistic tests less likely to fail when they shouldn't.

* [NOD-264] Added a message warning people about probabilistic tests.

* [NOD-264] Rephrased a comment about rebalanceThreshold.

* [NOD-264] Removed IsCoinBase, CheckTransactionInputsAndCalulateFee, and ValidateTransactionScripts from txSelection.

* [NOD-264] Removed a condition that is no longer relevant.

* [NOD-264] "which's" -> "whose"

* [NOD-264] Removed wasteful preallocations.

* [NOD-264] Fixed a comment referring to "used" transactions.
2019-08-19 12:08:48 +03:00

130 lines
3.5 KiB
Go

package mining
// This file functions are not considered safe for regular use, and should be used for test purposes only.
import (
"fmt"
"time"
"github.com/daglabs/btcd/dagconfig"
"github.com/daglabs/btcd/blockdag"
"github.com/daglabs/btcd/txscript"
"github.com/daglabs/btcd/util"
"github.com/daglabs/btcd/util/daghash"
"github.com/daglabs/btcd/wire"
)
// fakeTxSource is a simple implementation of TxSource interface
type fakeTxSource struct {
txDescs []*TxDesc
}
func (txs *fakeTxSource) LastUpdated() time.Time {
return time.Unix(0, 0)
}
func (txs *fakeTxSource) MiningDescs() []*TxDesc {
return txs.txDescs
}
func (txs *fakeTxSource) HaveTransaction(txID *daghash.TxID) bool {
for _, desc := range txs.txDescs {
if *desc.Tx.ID() == *txID {
return true
}
}
return false
}
// PrepareBlockForTest generates a block with the proper merkle roots, coinbase transaction etc. This function is used for test purposes only
func PrepareBlockForTest(dag *blockdag.BlockDAG, params *dagconfig.Params, parentHashes []*daghash.Hash, transactions []*wire.MsgTx, forceTransactions bool) (*wire.MsgBlock, error) {
newVirtual, err := blockdag.GetVirtualFromParentsForTest(dag, parentHashes)
if err != nil {
return nil, err
}
oldVirtual := blockdag.SetVirtualForTest(dag, newVirtual)
defer blockdag.SetVirtualForTest(dag, oldVirtual)
policy := Policy{
BlockMaxMass: 50000,
}
txSource := &fakeTxSource{
txDescs: make([]*TxDesc, len(transactions)),
}
for i, tx := range transactions {
txSource.txDescs[i] = &TxDesc{
Tx: util.NewTx(tx),
Fee: 1,
}
}
blockTemplateGenerator := NewBlkTmplGenerator(&policy,
params, txSource, dag, blockdag.NewMedianTime(), txscript.NewSigCache(100000))
OpTrueAddr, err := OpTrueAddress(params.Prefix)
if err != nil {
return nil, err
}
template, err := blockTemplateGenerator.NewBlockTemplate(OpTrueAddr)
if err != nil {
return nil, err
}
// In order of creating deterministic coinbase tx ids.
err = blockTemplateGenerator.UpdateExtraNonce(template.Block, GenerateDeterministicExtraNonceForTest())
if err != nil {
return nil, err
}
txsToAdd := make([]*wire.MsgTx, 0)
for _, tx := range transactions {
found := false
for _, blockTx := range template.Block.Transactions {
if blockTx.TxHash().IsEqual(tx.TxHash()) {
found = true
break
}
}
if !found {
if !forceTransactions {
return nil, fmt.Errorf("tx %s wasn't found in the block", tx.TxHash())
}
txsToAdd = append(txsToAdd, tx)
}
}
if forceTransactions && len(txsToAdd) > 0 {
for _, tx := range txsToAdd {
template.Block.Transactions = append(template.Block.Transactions, tx)
}
}
updateHeaderFields := forceTransactions && len(txsToAdd) > 0
if updateHeaderFields {
utilTxs := make([]*util.Tx, len(template.Block.Transactions))
for i, tx := range template.Block.Transactions {
utilTxs[i] = util.NewTx(tx)
}
template.Block.Header.HashMerkleRoot = blockdag.BuildHashMerkleTreeStore(utilTxs).Root()
template.Block.Header.UTXOCommitment, err = blockTemplateGenerator.buildUTXOCommitment(template.Block.Transactions)
if err != nil {
return nil, err
}
}
return template.Block, nil
}
// GenerateDeterministicExtraNonceForTest returns a unique deterministic extra nonce for coinbase data, in order to create unique coinbase transactions.
func GenerateDeterministicExtraNonceForTest() uint64 {
extraNonceForTest++
return extraNonceForTest
}
func OpTrueAddress(prefix util.Bech32Prefix) (util.Address, error) {
return util.NewAddressScriptHash(blockdag.OpTrueScript, prefix)
}
var extraNonceForTest = uint64(0)