mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-11-28 16:13:56 +00:00
Merge branch 'dev' into rpcdomainconverter-typo
This commit is contained in:
commit
11e001fa5f
2
.github/workflows/deploy.yaml
vendored
2
.github/workflows/deploy.yaml
vendored
@ -23,7 +23,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.19
|
go-version: 1.21
|
||||||
|
|
||||||
- name: Build on Linux
|
- name: Build on Linux
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
|
|||||||
@ -43,6 +43,9 @@ type TestConsensus interface {
|
|||||||
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
|
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
|
||||||
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||||
|
|
||||||
|
AddBlockOnTips(coinbaseData *externalapi.DomainCoinbaseData,
|
||||||
|
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||||
|
|
||||||
AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error)
|
||||||
|
|
||||||
AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
AddUTXOInvalidBlock(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
||||||
|
|||||||
@ -69,6 +69,17 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba
|
|||||||
return consensushashing.BlockHash(block), virtualChangeSet, nil
|
return consensushashing.BlockHash(block), virtualChangeSet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc *testConsensus) AddBlockOnTips(coinbaseData *externalapi.DomainCoinbaseData,
|
||||||
|
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.VirtualChangeSet, error) {
|
||||||
|
|
||||||
|
tips, err := tc.Tips()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tc.AddBlock(tips, coinbaseData, transactions)
|
||||||
|
}
|
||||||
|
|
||||||
func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
func (tc *testConsensus) AddUTXOInvalidHeader(parentHashes []*externalapi.DomainHash) (*externalapi.DomainHash,
|
||||||
*externalapi.VirtualChangeSet, error) {
|
*externalapi.VirtualChangeSet, error) {
|
||||||
|
|
||||||
|
|||||||
@ -232,6 +232,8 @@ var MainnetParams = Params{
|
|||||||
"seeder4.kaspad.net",
|
"seeder4.kaspad.net",
|
||||||
// This DNS seeder is run by Tim
|
// This DNS seeder is run by Tim
|
||||||
"kaspadns.kaspacalc.net",
|
"kaspadns.kaspacalc.net",
|
||||||
|
// This DNS seeder is run by supertypo
|
||||||
|
"n-mainnet.kaspa.ws",
|
||||||
},
|
},
|
||||||
|
|
||||||
// DAG parameters
|
// DAG parameters
|
||||||
|
|||||||
@ -147,16 +147,12 @@ func (btb *blockTemplateBuilder) BuildBlockTemplate(
|
|||||||
invalidTxsErr := ruleerrors.ErrInvalidTransactionsInNewBlock{}
|
invalidTxsErr := ruleerrors.ErrInvalidTransactionsInNewBlock{}
|
||||||
if errors.As(err, &invalidTxsErr) {
|
if errors.As(err, &invalidTxsErr) {
|
||||||
log.Criticalf("consensusReference.Consensus().BuildBlock returned invalid txs in BuildBlockTemplate")
|
log.Criticalf("consensusReference.Consensus().BuildBlock returned invalid txs in BuildBlockTemplate")
|
||||||
invalidTxs := make([]*consensusexternalapi.DomainTransaction, 0, len(invalidTxsErr.InvalidTransactions))
|
err = btb.mempool.RemoveInvalidTransactions(&invalidTxsErr)
|
||||||
for _, tx := range invalidTxsErr.InvalidTransactions {
|
|
||||||
invalidTxs = append(invalidTxs, tx.Transaction)
|
|
||||||
}
|
|
||||||
err = btb.mempool.RemoveTransactions(invalidTxs, true)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// mempool.RemoveTransactions might return errors in situations that are perfectly fine in this context.
|
// mempool.RemoveInvalidTransactions might return errors in situations that are perfectly fine in this context.
|
||||||
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
// TODO: Once the mempool invariants are clear, this should be converted back `return nil, err`:
|
||||||
// https://github.com/kaspanet/kaspad/issues/1553
|
// https://github.com/kaspanet/kaspad/issues/1553
|
||||||
log.Criticalf("Error from mempool.RemoveTransactions: %+v", err)
|
log.Criticalf("Error from mempool.RemoveInvalidTransactions: %+v", err)
|
||||||
}
|
}
|
||||||
// We can call this recursively without worry because this should almost never happen
|
// We can call this recursively without worry because this should almost never happen
|
||||||
return btb.BuildBlockTemplate(coinbaseData)
|
return btb.BuildBlockTemplate(coinbaseData)
|
||||||
|
|||||||
@ -51,6 +51,7 @@ const (
|
|||||||
RejectDifficulty RejectCode = 0x44
|
RejectDifficulty RejectCode = 0x44
|
||||||
RejectImmatureSpend RejectCode = 0x45
|
RejectImmatureSpend RejectCode = 0x45
|
||||||
RejectBadOrphan RejectCode = 0x64
|
RejectBadOrphan RejectCode = 0x64
|
||||||
|
RejectSpamTx RejectCode = 0x65
|
||||||
)
|
)
|
||||||
|
|
||||||
// Map of reject codes back strings for pretty printing.
|
// Map of reject codes back strings for pretty printing.
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package mempool
|
package mempool
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensusreference"
|
"github.com/kaspanet/kaspad/domain/consensusreference"
|
||||||
@ -141,7 +144,57 @@ func (mp *mempool) BlockCandidateTransactions() []*externalapi.DomainTransaction
|
|||||||
mp.mtx.RLock()
|
mp.mtx.RLock()
|
||||||
defer mp.mtx.RUnlock()
|
defer mp.mtx.RUnlock()
|
||||||
|
|
||||||
return mp.transactionsPool.allReadyTransactions()
|
readyTxs := mp.transactionsPool.allReadyTransactions()
|
||||||
|
var candidateTxs []*externalapi.DomainTransaction
|
||||||
|
var spamTx *externalapi.DomainTransaction
|
||||||
|
var spamTxNewestUTXODaaScore uint64
|
||||||
|
for _, tx := range readyTxs {
|
||||||
|
if len(tx.Outputs) > len(tx.Inputs) {
|
||||||
|
hasCoinbaseInput := false
|
||||||
|
for _, input := range tx.Inputs {
|
||||||
|
if input.UTXOEntry.IsCoinbase() {
|
||||||
|
hasCoinbaseInput = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numExtraOuts := len(tx.Outputs) - len(tx.Inputs)
|
||||||
|
if !hasCoinbaseInput && numExtraOuts > 2 && tx.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||||
|
log.Debugf("Filtered spam tx %s", consensushashing.TransactionID(tx))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasCoinbaseInput || tx.Fee > uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||||
|
candidateTxs = append(candidateTxs, tx)
|
||||||
|
} else {
|
||||||
|
txNewestUTXODaaScore := tx.Inputs[0].UTXOEntry.BlockDAAScore()
|
||||||
|
for _, input := range tx.Inputs {
|
||||||
|
if input.UTXOEntry.BlockDAAScore() > txNewestUTXODaaScore {
|
||||||
|
txNewestUTXODaaScore = input.UTXOEntry.BlockDAAScore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if spamTx != nil {
|
||||||
|
if txNewestUTXODaaScore < spamTxNewestUTXODaaScore {
|
||||||
|
spamTx = tx
|
||||||
|
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
spamTx = tx
|
||||||
|
spamTxNewestUTXODaaScore = txNewestUTXODaaScore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
candidateTxs = append(candidateTxs, tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if spamTx != nil {
|
||||||
|
log.Debugf("Adding spam tx candidate %s", consensushashing.TransactionID(spamTx))
|
||||||
|
candidateTxs = append(candidateTxs, spamTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidateTxs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) {
|
func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*externalapi.DomainTransaction, err error) {
|
||||||
@ -151,11 +204,29 @@ func (mp *mempool) RevalidateHighPriorityTransactions() (validTransactions []*ex
|
|||||||
return mp.revalidateHighPriorityTransactions()
|
return mp.revalidateHighPriorityTransactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) RemoveTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
func (mp *mempool) RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error {
|
||||||
mp.mtx.Lock()
|
mp.mtx.Lock()
|
||||||
defer mp.mtx.Unlock()
|
defer mp.mtx.Unlock()
|
||||||
|
|
||||||
return mp.removeTransactions(transactions, removeRedeemers)
|
for _, tx := range err.InvalidTransactions {
|
||||||
|
ruleErr, success := tx.Error.(ruleerrors.RuleError)
|
||||||
|
if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inner := ruleErr.Unwrap()
|
||||||
|
removeRedeemers := true
|
||||||
|
if _, ok := inner.(ruleerrors.ErrMissingTxOut); ok {
|
||||||
|
removeRedeemers = false
|
||||||
|
}
|
||||||
|
|
||||||
|
err := mp.removeTransaction(consensushashing.TransactionID(tx.Transaction), removeRedeemers)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) RemoveTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
func (mp *mempool) RemoveTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||||
|
|||||||
@ -2,20 +2,9 @@ package mempool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
||||||
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
"github.com/kaspanet/kaspad/domain/miningmanager/mempool/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (mp *mempool) removeTransactions(transactions []*externalapi.DomainTransaction, removeRedeemers bool) error {
|
|
||||||
for _, transaction := range transactions {
|
|
||||||
err := mp.removeTransaction(consensushashing.TransactionID(transaction), removeRedeemers)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
func (mp *mempool) removeTransaction(transactionID *externalapi.DomainTransactionID, removeRedeemers bool) error {
|
||||||
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
if _, ok := mp.orphansPool.allOrphans[*transactionID]; ok {
|
||||||
return mp.orphansPool.removeOrphan(transactionID, true)
|
return mp.orphansPool.removeOrphan(transactionID, true)
|
||||||
|
|||||||
@ -7,21 +7,86 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTransaction, error) {
|
func (mp *mempool) revalidateHighPriorityTransactions() ([]*externalapi.DomainTransaction, error) {
|
||||||
|
type txNode struct {
|
||||||
|
children map[externalapi.DomainTransactionID]struct{}
|
||||||
|
nonVisitedParents int
|
||||||
|
tx *model.MempoolTransaction
|
||||||
|
visited bool
|
||||||
|
}
|
||||||
|
|
||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "revalidateHighPriorityTransactions")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
|
|
||||||
|
// We revalidate transactions in topological order in case there are dependencies between them
|
||||||
|
|
||||||
|
// Naturally transactions point to their dependencies, but since we want to start processing the dependencies
|
||||||
|
// first, we build the opposite DAG. We initially fill `queue` with transactions with no dependencies.
|
||||||
|
txDAG := make(map[externalapi.DomainTransactionID]*txNode)
|
||||||
|
|
||||||
|
maybeAddNode := func(txID externalapi.DomainTransactionID) *txNode {
|
||||||
|
if node, ok := txDAG[txID]; ok {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
node := &txNode{
|
||||||
|
children: make(map[externalapi.DomainTransactionID]struct{}),
|
||||||
|
nonVisitedParents: 0,
|
||||||
|
tx: mp.transactionsPool.highPriorityTransactions[txID],
|
||||||
|
}
|
||||||
|
txDAG[txID] = node
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
queue := make([]*txNode, 0, len(mp.transactionsPool.highPriorityTransactions))
|
||||||
|
for id, transaction := range mp.transactionsPool.highPriorityTransactions {
|
||||||
|
node := maybeAddNode(id)
|
||||||
|
|
||||||
|
parents := make(map[externalapi.DomainTransactionID]struct{})
|
||||||
|
for _, input := range transaction.Transaction().Inputs {
|
||||||
|
if _, ok := mp.transactionsPool.highPriorityTransactions[input.PreviousOutpoint.TransactionID]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
parents[input.PreviousOutpoint.TransactionID] = struct{}{} // To avoid duplicate parents, we first add it to a set and then count it
|
||||||
|
maybeAddNode(input.PreviousOutpoint.TransactionID).children[id] = struct{}{}
|
||||||
|
}
|
||||||
|
node.nonVisitedParents = len(parents)
|
||||||
|
|
||||||
|
if node.nonVisitedParents == 0 {
|
||||||
|
queue = append(queue, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
validTransactions := []*externalapi.DomainTransaction{}
|
validTransactions := []*externalapi.DomainTransaction{}
|
||||||
for _, transaction := range mp.transactionsPool.highPriorityTransactions {
|
|
||||||
|
// Now we iterate the DAG in topological order using BFS
|
||||||
|
for len(queue) > 0 {
|
||||||
|
var node *txNode
|
||||||
|
node, queue = queue[0], queue[1:]
|
||||||
|
|
||||||
|
if node.visited {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
node.visited = true
|
||||||
|
|
||||||
|
transaction := node.tx
|
||||||
isValid, err := mp.revalidateTransaction(transaction)
|
isValid, err := mp.revalidateTransaction(transaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !isValid {
|
|
||||||
continue
|
for child := range node.children {
|
||||||
|
childNode := txDAG[child]
|
||||||
|
childNode.nonVisitedParents--
|
||||||
|
if childNode.nonVisitedParents == 0 {
|
||||||
|
queue = append(queue, txDAG[child])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isValid {
|
||||||
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
validTransactions = append(validTransactions, transaction.Transaction().Clone())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return validTransactions, nil
|
return validTransactions, nil
|
||||||
}
|
}
|
||||||
@ -35,7 +100,7 @@ func (mp *mempool) revalidateTransaction(transaction *model.MempoolTransaction)
|
|||||||
}
|
}
|
||||||
if len(missingParents) > 0 {
|
if len(missingParents) > 0 {
|
||||||
log.Debugf("Removing transaction %s, it failed revalidation", transaction.TransactionID())
|
log.Debugf("Removing transaction %s, it failed revalidation", transaction.TransactionID())
|
||||||
err := mp.removeTransaction(transaction.TransactionID(), true)
|
err := mp.removeTransaction(transaction.TransactionID(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package mempool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package mempool
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
@ -44,6 +45,20 @@ func (mp *mempool) validateTransactionInIsolation(transaction *externalapi.Domai
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error {
|
func (mp *mempool) validateTransactionInContext(transaction *externalapi.DomainTransaction) error {
|
||||||
|
hasCoinbaseInput := false
|
||||||
|
for _, input := range transaction.Inputs {
|
||||||
|
if input.UTXOEntry.IsCoinbase() {
|
||||||
|
hasCoinbaseInput = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numExtraOuts := len(transaction.Outputs) - len(transaction.Inputs)
|
||||||
|
if !hasCoinbaseInput && numExtraOuts > 2 && transaction.Fee < uint64(numExtraOuts)*constants.SompiPerKaspa {
|
||||||
|
log.Warnf("Rejected spam tx %s from mempool (%d outputs)", consensushashing.TransactionID(transaction), len(transaction.Outputs))
|
||||||
|
return transactionRuleError(RejectSpamTx, fmt.Sprintf("Rejected spam tx %s from mempool", consensushashing.TransactionID(transaction)))
|
||||||
|
}
|
||||||
|
|
||||||
if !mp.config.AcceptNonStandard {
|
if !mp.config.AcceptNonStandard {
|
||||||
err := mp.checkTransactionStandardInContext(transaction)
|
err := mp.checkTransactionStandardInContext(transaction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -577,6 +577,72 @@ func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRevalidateHighPriorityTransactionsWithChain(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
consensusConfig.BlockCoinbaseMaturity = 0
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestRevalidateHighPriorityTransactions")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed setting up TestConsensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
|
||||||
|
miningFactory := miningmanager.NewFactory()
|
||||||
|
mempoolConfig := mempool.DefaultConfig(&consensusConfig.Params)
|
||||||
|
tcAsConsensus := tc.(externalapi.Consensus)
|
||||||
|
tcAsConsensusPointer := &tcAsConsensus
|
||||||
|
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
||||||
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempoolConfig)
|
||||||
|
|
||||||
|
const chainSize = 10
|
||||||
|
chain, err := createTxChain(tc, chainSize)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = miningManager.ValidateAndInsertTransaction(chain[0], true, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockHash, _, err := tc.AddBlockOnTips(nil, []*externalapi.DomainTransaction{chain[0].Clone()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block, _, err := tc.GetBlock(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = miningManager.HandleNewBlockTransactions(block.Transactions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, transaction := range chain[1:] {
|
||||||
|
_, err = miningManager.ValidateAndInsertTransaction(transaction, true, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = tc.AddBlockOnTips(nil, []*externalapi.DomainTransaction{chain[1].Clone()})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
revalidated, err := miningManager.RevalidateHighPriorityTransactions()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(revalidated) != chainSize-2 {
|
||||||
|
t.Fatalf("expected %d transactions to revalidate but instead only %d revalidated", chainSize-2, len(revalidated))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// TestModifyBlockTemplate verifies that modifying a block template changes coinbase data correctly.
|
// TestModifyBlockTemplate verifies that modifying a block template changes coinbase data correctly.
|
||||||
func TestModifyBlockTemplate(t *testing.T) {
|
func TestModifyBlockTemplate(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
@ -904,40 +970,58 @@ func createArraysOfParentAndChildrenTransactions(tc testapi.TestConsensus) ([]*e
|
|||||||
func createParentAndChildrenTransactions(tc testapi.TestConsensus) (txParent *externalapi.DomainTransaction,
|
func createParentAndChildrenTransactions(tc testapi.TestConsensus) (txParent *externalapi.DomainTransaction,
|
||||||
txChild *externalapi.DomainTransaction, err error) {
|
txChild *externalapi.DomainTransaction, err error) {
|
||||||
|
|
||||||
|
chain, err := createTxChain(tc, 2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain[0], chain[1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTxChain(tc testapi.TestConsensus, numTxs int) ([]*externalapi.DomainTransaction, error) {
|
||||||
// We will add two blocks by consensus before the parent transactions, in order to fund the parent transactions.
|
// We will add two blocks by consensus before the parent transactions, in order to fund the parent transactions.
|
||||||
tips, err := tc.Tips()
|
tips, err := tc.Tips()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = tc.AddBlock(tips, nil, nil)
|
_, _, err = tc.AddBlock(tips, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrapf(err, "AddBlock: %v", err)
|
return nil, errors.Wrapf(err, "AddBlock: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tips, err = tc.Tips()
|
tips, err = tc.Tips()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fundingBlockHashForParent, _, err := tc.AddBlock(tips, nil, nil)
|
fundingBlockHashForParent, _, err := tc.AddBlock(tips, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "AddBlock: ")
|
return nil, errors.Wrap(err, "AddBlock: ")
|
||||||
}
|
}
|
||||||
fundingBlockForParent, _, err := tc.GetBlock(fundingBlockHashForParent)
|
fundingBlockForParent, _, err := tc.GetBlock(fundingBlockHashForParent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Wrap(err, "GetBlock: ")
|
return nil, errors.Wrap(err, "GetBlock: ")
|
||||||
}
|
}
|
||||||
fundingTransactionForParent := fundingBlockForParent.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
fundingTransactionForParent := fundingBlockForParent.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
||||||
txParent, err = testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
|
||||||
|
transactions := make([]*externalapi.DomainTransaction, numTxs)
|
||||||
|
transactions[0], err = testutils.CreateTransaction(fundingTransactionForParent, 1000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
txChild, err = testutils.CreateTransaction(txParent, 1000)
|
|
||||||
|
txParent := transactions[0]
|
||||||
|
for i := 1; i < numTxs; i++ {
|
||||||
|
transactions[i], err = testutils.CreateTransaction(txParent, 1000)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return txParent, txChild, nil
|
|
||||||
|
txParent = transactions[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createChildAndParentTxsAndAddParentToConsensus(tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
func createChildAndParentTxsAndAddParentToConsensus(tc testapi.TestConsensus) (*externalapi.DomainTransaction, error) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mempool maintains a set of known transactions that
|
// Mempool maintains a set of known transactions that
|
||||||
@ -11,7 +12,7 @@ type Mempool interface {
|
|||||||
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
BlockCandidateTransactions() []*externalapi.DomainTransaction
|
||||||
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
ValidateAndInsertTransaction(transaction *externalapi.DomainTransaction, isHighPriority bool, allowOrphan bool) (
|
||||||
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
acceptedTransactions []*externalapi.DomainTransaction, err error)
|
||||||
RemoveTransactions(txs []*externalapi.DomainTransaction, removeRedeemers bool) error
|
RemoveInvalidTransactions(err *ruleerrors.ErrInvalidTransactionsInNewBlock) error
|
||||||
GetTransaction(
|
GetTransaction(
|
||||||
transactionID *externalapi.DomainTransactionID,
|
transactionID *externalapi.DomainTransactionID,
|
||||||
includeTransactionPool bool,
|
includeTransactionPool bool,
|
||||||
|
|||||||
@ -52,6 +52,8 @@ func (ui *UTXOIndex) Reset() error {
|
|||||||
ui.mutex.Lock()
|
ui.mutex.Lock()
|
||||||
defer ui.mutex.Unlock()
|
defer ui.mutex.Unlock()
|
||||||
|
|
||||||
|
log.Infof("Starting UTXO index reset")
|
||||||
|
|
||||||
err := ui.store.deleteAll()
|
err := ui.store.deleteAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -88,7 +90,13 @@ func (ui *UTXOIndex) Reset() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This has to be done last to mark that the reset went smoothly and no reset has to be called next time.
|
// This has to be done last to mark that the reset went smoothly and no reset has to be called next time.
|
||||||
return ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
err = ui.store.updateAndCommitVirtualParentsWithoutTransaction(virtualInfo.ParentHashes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Finished UTXO index reset")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ui *UTXOIndex) isSynced() (bool, error) {
|
func (ui *UTXOIndex) isSynced() (bool, error) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
|||||||
const (
|
const (
|
||||||
appMajor uint = 0
|
appMajor uint = 0
|
||||||
appMinor uint = 12
|
appMinor uint = 12
|
||||||
appPatch uint = 13
|
appPatch uint = 15
|
||||||
)
|
)
|
||||||
|
|
||||||
// appBuild is defined as a variable so it can be overridden during the build
|
// appBuild is defined as a variable so it can be overridden during the build
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user