mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-06 14:16:43 +00:00

* [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.
240 lines
6.5 KiB
Go
240 lines
6.5 KiB
Go
// Copyright (c) 2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package mining
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/daglabs/btcd/util/subnetworkid"
|
|
|
|
"bou.ke/monkey"
|
|
"github.com/daglabs/btcd/blockdag"
|
|
"github.com/daglabs/btcd/dagconfig"
|
|
"github.com/daglabs/btcd/txscript"
|
|
"github.com/daglabs/btcd/util/daghash"
|
|
"github.com/daglabs/btcd/wire"
|
|
|
|
"github.com/daglabs/btcd/util"
|
|
)
|
|
|
|
func TestNewBlockTemplate(t *testing.T) {
|
|
params := dagconfig.SimNetParams
|
|
params.BlockCoinbaseMaturity = 0
|
|
|
|
dag, teardownFunc, err := blockdag.DAGSetup("TestNewBlockTemplate", blockdag.Config{
|
|
DAGParams: ¶ms,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to setup DAG instance: %v", err)
|
|
}
|
|
defer teardownFunc()
|
|
|
|
pkScript, err := txscript.NewScriptBuilder().AddOp(txscript.OpTrue).Script()
|
|
if err != nil {
|
|
t.Fatalf("Failed to create pkScript: %v", err)
|
|
}
|
|
|
|
policy := Policy{
|
|
BlockMaxMass: 50000,
|
|
}
|
|
|
|
// First we create a block to have coinbase funds for the rest of the test.
|
|
txSource := &fakeTxSource{
|
|
txDescs: []*TxDesc{},
|
|
}
|
|
|
|
blockTemplateGenerator := NewBlkTmplGenerator(&policy,
|
|
¶ms, txSource, dag, blockdag.NewMedianTime(), txscript.NewSigCache(100000))
|
|
|
|
OpTrueAddr, err := OpTrueAddress(params.Prefix)
|
|
if err != nil {
|
|
t.Fatalf("OpTrueAddress: %s", err)
|
|
}
|
|
template1, err := blockTemplateGenerator.NewBlockTemplate(OpTrueAddr)
|
|
if err != nil {
|
|
t.Fatalf("NewBlockTemplate: %v", err)
|
|
}
|
|
|
|
isOrphan, delay, err := dag.ProcessBlock(util.NewBlock(template1.Block), blockdag.BFNoPoWCheck)
|
|
if err != nil {
|
|
t.Fatalf("ProcessBlock: %v", err)
|
|
}
|
|
|
|
if delay != 0 {
|
|
t.Fatalf("ProcessBlock: template1 " +
|
|
"is too far in the future")
|
|
}
|
|
|
|
if isOrphan {
|
|
t.Fatalf("ProcessBlock: template1 got unexpectedly orphan")
|
|
}
|
|
|
|
// We create another 4 blocks to in order to create more funds for tests.
|
|
cbTxs := []*wire.MsgTx{template1.Block.Transactions[util.CoinbaseTransactionIndex]}
|
|
for i := 0; i < 4; i++ {
|
|
template, err := blockTemplateGenerator.NewBlockTemplate(OpTrueAddr)
|
|
if err != nil {
|
|
t.Fatalf("NewBlockTemplate: %v", err)
|
|
}
|
|
isOrphan, delay, err = dag.ProcessBlock(util.NewBlock(template.Block), blockdag.BFNoPoWCheck)
|
|
if err != nil {
|
|
t.Fatalf("ProcessBlock: %v", err)
|
|
}
|
|
if delay != 0 {
|
|
t.Fatalf("ProcessBlock: template " +
|
|
"is too far in the future")
|
|
}
|
|
if isOrphan {
|
|
t.Fatalf("ProcessBlock: template got unexpectedly orphan")
|
|
}
|
|
cbTxs = append(cbTxs, template.Block.Transactions[util.CoinbaseTransactionIndex])
|
|
}
|
|
|
|
signatureScript, err := txscript.PayToScriptHashSignatureScript(blockdag.OpTrueScript, nil)
|
|
if err != nil {
|
|
t.Fatalf("Error creating signature script: %s", err)
|
|
}
|
|
|
|
// tx is a regular transaction, and should not be filtered by the miner
|
|
txIn := &wire.TxIn{
|
|
PreviousOutpoint: wire.Outpoint{
|
|
TxID: *cbTxs[0].TxID(),
|
|
Index: 0,
|
|
},
|
|
Sequence: wire.MaxTxInSequenceNum,
|
|
SignatureScript: signatureScript,
|
|
}
|
|
txOut := &wire.TxOut{
|
|
PkScript: pkScript,
|
|
Value: 1,
|
|
}
|
|
tx := wire.NewNativeMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut})
|
|
|
|
// We want to check that the miner filters non finalized transactions
|
|
txIn = &wire.TxIn{
|
|
PreviousOutpoint: wire.Outpoint{
|
|
TxID: *cbTxs[1].TxID(),
|
|
Index: 0,
|
|
},
|
|
Sequence: 0,
|
|
SignatureScript: signatureScript,
|
|
}
|
|
txOut = &wire.TxOut{
|
|
PkScript: pkScript,
|
|
Value: 1,
|
|
}
|
|
nonFinalizedTx := wire.NewNativeMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut})
|
|
nonFinalizedTx.LockTime = dag.ChainHeight() + 2
|
|
|
|
existingSubnetwork := &subnetworkid.SubnetworkID{0xff}
|
|
nonExistingSubnetwork := &subnetworkid.SubnetworkID{0xfe}
|
|
|
|
// We want to check that the miner filters transactions with non-existing subnetwork id. (It should first push it to the priority queue, and then ignore it)
|
|
txIn = &wire.TxIn{
|
|
PreviousOutpoint: wire.Outpoint{
|
|
TxID: *cbTxs[2].TxID(),
|
|
Index: 0,
|
|
},
|
|
Sequence: 0,
|
|
SignatureScript: signatureScript,
|
|
}
|
|
txOut = &wire.TxOut{
|
|
PkScript: pkScript,
|
|
Value: 1,
|
|
}
|
|
nonExistingSubnetworkTx := wire.NewSubnetworkMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut},
|
|
nonExistingSubnetwork, 1, []byte{})
|
|
|
|
// We want to check that the miner doesn't filters transactions that do not exceed the subnetwork gas limit
|
|
txIn = &wire.TxIn{
|
|
PreviousOutpoint: wire.Outpoint{
|
|
TxID: *cbTxs[3].TxID(),
|
|
Index: 0,
|
|
},
|
|
Sequence: 0,
|
|
SignatureScript: signatureScript,
|
|
}
|
|
txOut = &wire.TxOut{
|
|
PkScript: pkScript,
|
|
Value: 1,
|
|
}
|
|
subnetworkTx1 := wire.NewSubnetworkMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut}, existingSubnetwork, 1, []byte{})
|
|
|
|
// We want to check that the miner filters transactions that exceed the subnetwork gas limit. (It should first push it to the priority queue, and then ignore it)
|
|
txIn = &wire.TxIn{
|
|
PreviousOutpoint: wire.Outpoint{
|
|
TxID: *cbTxs[4].TxID(),
|
|
},
|
|
Sequence: 0,
|
|
SignatureScript: signatureScript,
|
|
}
|
|
txOut = &wire.TxOut{
|
|
PkScript: pkScript,
|
|
Value: 1,
|
|
}
|
|
subnetworkTx2 := wire.NewSubnetworkMsgTx(wire.TxVersion, []*wire.TxIn{txIn}, []*wire.TxOut{txOut}, existingSubnetwork,
|
|
100, // Subnetwork gas limit is 90
|
|
[]byte{})
|
|
|
|
txSource.txDescs = []*TxDesc{
|
|
{
|
|
Tx: util.NewTx(tx),
|
|
Fee: 1,
|
|
},
|
|
{
|
|
Tx: util.NewTx(nonFinalizedTx),
|
|
Fee: 1,
|
|
},
|
|
{
|
|
Tx: util.NewTx(subnetworkTx1),
|
|
Fee: 1,
|
|
},
|
|
{
|
|
Tx: util.NewTx(subnetworkTx2),
|
|
Fee: 1,
|
|
},
|
|
{
|
|
Tx: util.NewTx(nonExistingSubnetworkTx),
|
|
Fee: 1,
|
|
},
|
|
}
|
|
|
|
// Here we define nonExistingSubnetwork to be non-exist, and existingSubnetwork to have a gas limit of 90
|
|
gasLimitPatch := monkey.Patch((*blockdag.SubnetworkStore).GasLimit, func(_ *blockdag.SubnetworkStore, subnetworkID *subnetworkid.SubnetworkID) (uint64, error) {
|
|
if subnetworkID.IsEqual(nonExistingSubnetwork) {
|
|
return 0, errors.New("not found")
|
|
}
|
|
return 90, nil
|
|
})
|
|
defer gasLimitPatch.Unpatch()
|
|
|
|
template3, err := blockTemplateGenerator.NewBlockTemplate(OpTrueAddr)
|
|
gasLimitPatch.Unpatch()
|
|
|
|
if err != nil {
|
|
t.Errorf("NewBlockTemplate: unexpected error: %v", err)
|
|
}
|
|
|
|
expectedTxs := map[daghash.TxID]bool{
|
|
*tx.TxID(): false,
|
|
*subnetworkTx1.TxID(): false,
|
|
}
|
|
|
|
for _, tx := range template3.Block.Transactions[util.CoinbaseTransactionIndex+1:] {
|
|
id := *tx.TxID()
|
|
if _, ok := expectedTxs[id]; !ok {
|
|
t.Errorf("Unexpected tx %v in template3's candidate block", id)
|
|
}
|
|
expectedTxs[id] = true
|
|
}
|
|
|
|
for id, exists := range expectedTxs {
|
|
if !exists {
|
|
t.Errorf("tx %v was expected to be in template3's candidate block, but wasn't", id)
|
|
}
|
|
}
|
|
}
|