[NOD-1519] Add TestAPI for BuildBlockWithParents (#1011)

* [NOD-1519] Separate BlockBuilder and BlockProcessor

* [NOD-1519] Wire blockBuilder properly + implement buildBlockWithParents

* [NOD-1519] Added testapi package, TestConsensus interface, and TestConsensus factory

* [NOD-1519] Add comments

* [NOD-1519] Separate TestBlockBuilder out of BlockBuilder

* [NOD-1519] TestBlockBuilder should also implement BlockBuilder

* [NOD-1519] Add NewTestConsensus to factory interface
This commit is contained in:
Svarog 2020-11-09 12:02:42 +02:00 committed by GitHub
parent 2282e36196
commit 6db337c8c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 440 additions and 207 deletions

View File

@ -5,30 +5,11 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// Consensus maintains the current core state of the node
type Consensus interface {
BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
ValidateTransactionAndPopulateWithConsensusData(transaction *externalapi.DomainTransaction) error
GetBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainBlock, error)
GetBlockHeader(blockHash *externalapi.DomainHash) (*externalapi.DomainBlockHeader, error)
GetBlockInfo(blockHash *externalapi.DomainHash) (*externalapi.BlockInfo, error)
GetHashesBetween(lowHash, highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
GetPruningPointUTXOSet() ([]byte, error)
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
CreateBlockLocator(lowHash, highHash *externalapi.DomainHash) (externalapi.BlockLocator, error)
FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error)
GetSyncInfo() (*externalapi.SyncInfo, error)
}
type consensus struct {
databaseContext model.DBReader
blockProcessor model.BlockProcessor
blockBuilder model.BlockBuilder
consensusStateManager model.ConsensusStateManager
transactionValidator model.TransactionValidator
syncManager model.SyncManager
@ -46,7 +27,7 @@ type consensus struct {
func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
return s.blockProcessor.BuildBlock(coinbaseData, transactions)
return s.blockBuilder.BuildBlock(coinbaseData, transactions)
}
// ValidateAndInsertBlock validates the given block and, if valid, applies it

View File

@ -16,6 +16,8 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/datastructures/utxodiffstore"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockbuilder"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockprocessor"
"github.com/kaspanet/kaspad/domain/consensus/processes/blockvalidator"
"github.com/kaspanet/kaspad/domain/consensus/processes/coinbasemanager"
@ -37,13 +39,19 @@ import (
// Factory instantiates new Consensuses
type Factory interface {
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Consensus, error)
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error)
NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (testapi.TestConsensus, error)
}
type factory struct{}
// NewFactory creates a new Consensus factory
func NewFactory() Factory {
return &factory{}
}
// NewConsensus instantiates a new Consensus
func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (Consensus, error) {
func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error) {
// Data Structures
acceptanceDataStore := acceptancedatastore.New()
blockStore := blockstore.New()
@ -193,6 +201,19 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
blockHeaderStore,
headerTipsStore)
blockBuilder := blockbuilder.New(
dbManager,
difficultyManager,
pastMedianTimeManager,
coinbaseManager,
consensusStateManager,
ghostdagManager,
acceptanceDataStore,
blockRelationStore,
multisetStore,
ghostdagDataStore,
)
blockProcessor := blockprocessor.New(
dagParams,
dbManager,
@ -225,6 +246,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
databaseContext: dbManager,
blockProcessor: blockProcessor,
blockBuilder: blockBuilder,
consensusStateManager: consensusStateManager,
transactionValidator: transactionValidator,
syncManager: syncManager,
@ -252,7 +274,18 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
return c, nil
}
// NewFactory creates a new Consensus factory
func NewFactory() Factory {
return &factory{}
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (
testapi.TestConsensus, error) {
consensusAsInterface, err := f.NewConsensus(dagParams, db)
if err != nil {
return nil, err
}
consensusAsImplementation := consensusAsInterface.(*consensus)
return &testConsensus{
consensus: consensusAsImplementation,
testBlockBuilder: blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder),
}, nil
}

View File

@ -0,0 +1,21 @@
package externalapi
// Consensus maintains the current core state of the node
type Consensus interface {
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
ValidateAndInsertBlock(block *DomainBlock) error
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
GetBlockHeader(blockHash *DomainHash) (*DomainBlockHeader, error)
GetBlockInfo(blockHash *DomainHash) (*BlockInfo, error)
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
GetPruningPointUTXOSet() ([]byte, error)
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
GetVirtualSelectedParent() (*DomainBlock, error)
CreateBlockLocator(lowHash, highHash *DomainHash) (BlockLocator, error)
FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error)
GetSyncInfo() (*SyncInfo, error)
}

View File

@ -0,0 +1,15 @@
package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// BlockBuilder is responsible for creating blocks from the current state
type BlockBuilder interface {
BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
}
// TestBlockBuilder adds to the main BlockBuilder methods required by tests
type TestBlockBuilder interface {
BlockBuilder
BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
}

View File

@ -3,8 +3,6 @@ package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// BlockProcessor is responsible for processing incoming blocks
// and creating blocks from the current state
type BlockProcessor interface {
BuildBlock(coinbaseData *externalapi.DomainCoinbaseData, transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
}

View File

@ -9,4 +9,5 @@ type ConsensusStateManager interface {
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
HeaderTipsPruningPoint() (*externalapi.DomainHash, error)
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (*UTXODiff, AcceptanceData, Multiset, error)
}

View File

@ -0,0 +1,11 @@
package testapi
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// TestConsensus wraps the Consensus interface with some methods that are needed by tests only
type TestConsensus interface {
externalapi.Consensus
BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error)
}

View File

@ -0,0 +1,210 @@
package blockbuilder
import (
"sort"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/mstime"
)
type blockBuilder struct {
databaseContext model.DBManager
difficultyManager model.DifficultyManager
pastMedianTimeManager model.PastMedianTimeManager
coinbaseManager model.CoinbaseManager
consensusStateManager model.ConsensusStateManager
ghostdagManager model.GHOSTDAGManager
acceptanceDataStore model.AcceptanceDataStore
blockRelationStore model.BlockRelationStore
multisetStore model.MultisetStore
ghostdagDataStore model.GHOSTDAGDataStore
}
// New creates a new instance of a BlockBuilder
func New(
databaseContext model.DBManager,
difficultyManager model.DifficultyManager,
pastMedianTimeManager model.PastMedianTimeManager,
coinbaseManager model.CoinbaseManager,
consensusStateManager model.ConsensusStateManager,
ghostdagManager model.GHOSTDAGManager,
acceptanceDataStore model.AcceptanceDataStore,
blockRelationStore model.BlockRelationStore,
multisetStore model.MultisetStore,
ghostdagDataStore model.GHOSTDAGDataStore,
) model.BlockBuilder {
return &blockBuilder{
databaseContext: databaseContext,
difficultyManager: difficultyManager,
pastMedianTimeManager: pastMedianTimeManager,
coinbaseManager: coinbaseManager,
consensusStateManager: consensusStateManager,
ghostdagManager: ghostdagManager,
acceptanceDataStore: acceptanceDataStore,
blockRelationStore: blockRelationStore,
multisetStore: multisetStore,
ghostdagDataStore: ghostdagDataStore,
}
}
// BuildBlock builds a block over the current state, with the given
// coinbaseData and the given transactions
func (bb *blockBuilder) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlock")
defer onEnd()
return bb.buildBlock(coinbaseData, transactions)
}
func (bb *blockBuilder) buildBlock(coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData)
if err != nil {
return nil, err
}
transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...)
header, err := bb.buildHeader(transactionsWithCoinbase)
if err != nil {
return nil, err
}
return &externalapi.DomainBlock{
Header: header,
Transactions: transactionsWithCoinbase,
}, nil
}
func (bb *blockBuilder) newBlockCoinbaseTransaction(
coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) {
return bb.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData)
}
func (bb blockBuilder) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) {
parentHashes, err := bb.newBlockParentHashes()
if err != nil {
return nil, err
}
virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
timeInMilliseconds, err := bb.newBlockTime(virtualGHOSTDAGData)
if err != nil {
return nil, err
}
bits, err := bb.newBlockDifficulty(virtualGHOSTDAGData)
if err != nil {
return nil, err
}
hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions)
acceptedIDMerkleRoot, err := bb.newBlockAcceptedIDMerkleRoot()
if err != nil {
return nil, err
}
utxoCommitment, err := bb.newBlockUTXOCommitment()
if err != nil {
return nil, err
}
return &externalapi.DomainBlockHeader{
Version: constants.BlockVersion,
ParentHashes: parentHashes,
HashMerkleRoot: *hashMerkleRoot,
AcceptedIDMerkleRoot: *acceptedIDMerkleRoot,
UTXOCommitment: *utxoCommitment,
TimeInMilliseconds: timeInMilliseconds,
Bits: bits,
}, nil
}
func (bb blockBuilder) newBlockParentHashes() ([]*externalapi.DomainHash, error) {
virtualBlockRelations, err := bb.blockRelationStore.BlockRelation(bb.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
return virtualBlockRelations.Parents, nil
}
func (bb blockBuilder) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (int64, error) {
// The timestamp for the block must not be before the median timestamp
// of the last several blocks. Thus, choose the maximum between the
// current time and one second after the past median time. The current
// timestamp is truncated to a millisecond boundary before comparison since a
// block timestamp does not supported a precision greater than one
// millisecond.
newTimestamp := mstime.Now().UnixMilliseconds() + 1
minTimestamp, err := bb.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent)
if err != nil {
return 0, err
}
if newTimestamp < minTimestamp {
newTimestamp = minTimestamp
}
return newTimestamp, nil
}
func (bb blockBuilder) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) {
virtualGHOSTDAGData, err := bb.ghostdagDataStore.Get(bb.databaseContext, model.VirtualBlockHash)
if err != nil {
return 0, err
}
return bb.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent)
}
func (bb blockBuilder) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
return merkle.CalculateHashMerkleRoot(transactions)
}
func (bb blockBuilder) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) {
newBlockAcceptanceData, err := bb.acceptanceDataStore.Get(bb.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
return bb.calculateAcceptedIDMerkleRoot(newBlockAcceptanceData)
}
func (bb blockBuilder) calculateAcceptedIDMerkleRoot(acceptanceData model.AcceptanceData) (*externalapi.DomainHash, error) {
var acceptedTransactions []*externalapi.DomainTransaction
for _, blockAcceptanceData := range acceptanceData {
for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData {
if !transactionAcceptance.IsAccepted {
continue
}
acceptedTransactions = append(acceptedTransactions, transactionAcceptance.Transaction)
}
}
sort.Slice(acceptedTransactions, func(i, j int) bool {
acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i])
acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j])
return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID)
})
return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil
}
func (bb blockBuilder) newBlockUTXOCommitment() (*externalapi.DomainHash, error) {
newBlockMultiset, err := bb.multisetStore.Get(bb.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
newBlockUTXOCommitment := newBlockMultiset.Hash()
return newBlockUTXOCommitment, nil
}

View File

@ -0,0 +1,7 @@
package blockbuilder
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
)
var log, _ = logger.Get(logger.SubsystemTags.BDAG)

View File

@ -0,0 +1,100 @@
package blockbuilder
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/infrastructure/logger"
)
type testBlockBuilder struct {
*blockBuilder
}
var tempBlockHash = &externalapi.DomainHash{
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
// NewTestBlockBuilder creates an instance of a TestBlockBuilder
func NewTestBlockBuilder(baseBlockBuilder model.BlockBuilder) model.TestBlockBuilder {
return &testBlockBuilder{blockBuilder: baseBlockBuilder.(*blockBuilder)}
}
func (bb *testBlockBuilder) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlockWithParents")
defer onEnd()
return bb.buildBlockWithParents(parentHashes, coinbaseData, transactions)
}
func (bb testBlockBuilder) buildHeaderWithParents(parentHashes []*externalapi.DomainHash,
transactions []*externalapi.DomainTransaction, acceptanceData model.AcceptanceData, multiset model.Multiset) (
*externalapi.DomainBlockHeader, error) {
ghostdagData, err := bb.ghostdagDataStore.Get(bb.databaseContext, tempBlockHash)
if err != nil {
return nil, err
}
timeInMilliseconds, err := bb.newBlockTime(ghostdagData)
if err != nil {
return nil, err
}
bits, err := bb.newBlockDifficulty(ghostdagData)
if err != nil {
return nil, err
}
hashMerkleRoot := bb.newBlockHashMerkleRoot(transactions)
acceptedIDMerkleRoot, err := bb.calculateAcceptedIDMerkleRoot(acceptanceData)
if err != nil {
return nil, err
}
utxoCommitment := multiset.Hash()
return &externalapi.DomainBlockHeader{
Version: constants.BlockVersion,
ParentHashes: parentHashes,
HashMerkleRoot: *hashMerkleRoot,
AcceptedIDMerkleRoot: *acceptedIDMerkleRoot,
UTXOCommitment: *utxoCommitment,
TimeInMilliseconds: timeInMilliseconds,
Bits: bits,
}, nil
}
func (bb *testBlockBuilder) buildBlockWithParents(
parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
bb.blockRelationStore.StageBlockRelation(tempBlockHash, &model.BlockRelations{Parents: parentHashes})
defer bb.blockRelationStore.Discard()
err := bb.ghostdagManager.GHOSTDAG(tempBlockHash)
if err != nil {
return nil, err
}
defer bb.ghostdagDataStore.Discard()
_, acceptanceData, multiset, err := bb.consensusStateManager.CalculatePastUTXOAndAcceptanceData(tempBlockHash)
if err != nil {
return nil, err
}
bb.acceptanceDataStore.Stage(tempBlockHash, acceptanceData)
defer bb.acceptanceDataStore.Discard()
coinbase, err := bb.newBlockCoinbaseTransaction(coinbaseData)
if err != nil {
return nil, err
}
transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...)
header, err := bb.buildHeaderWithParents(parentHashes, transactions, acceptanceData, multiset)
if err != nil {
return nil, err
}
return &externalapi.DomainBlock{
Header: header,
Transactions: transactionsWithCoinbase,
}, nil
}

View File

@ -116,17 +116,6 @@ func New(
}
}
// BuildBlock builds a block over the current state, with the given
// coinbaseData and the given transactions
func (bp *blockProcessor) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "BuildBlock")
defer onEnd()
return bp.buildBlock(coinbaseData, transactions)
}
// ValidateAndInsertBlock validates the given block and, if valid, applies it
// to the current state
func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) error {

View File

@ -1,150 +0,0 @@
package blockprocessor
import (
"sort"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
"github.com/kaspanet/kaspad/util/mstime"
)
func (bp *blockProcessor) buildBlock(coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
coinbase, err := bp.newBlockCoinbaseTransaction(coinbaseData)
if err != nil {
return nil, err
}
transactionsWithCoinbase := append([]*externalapi.DomainTransaction{coinbase}, transactions...)
header, err := bp.buildHeader(transactionsWithCoinbase)
if err != nil {
return nil, err
}
return &externalapi.DomainBlock{
Header: header,
Transactions: transactionsWithCoinbase,
}, nil
}
func (bp *blockProcessor) newBlockCoinbaseTransaction(
coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) {
return bp.coinbaseManager.ExpectedCoinbaseTransaction(model.VirtualBlockHash, coinbaseData)
}
func (bp *blockProcessor) buildHeader(transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlockHeader, error) {
parentHashes, err := bp.newBlockParentHashes()
if err != nil {
return nil, err
}
virtualGHOSTDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
timeInMilliseconds, err := bp.newBlockTime(virtualGHOSTDAGData)
if err != nil {
return nil, err
}
bits, err := bp.newBlockDifficulty(virtualGHOSTDAGData)
if err != nil {
return nil, err
}
hashMerkleRoot := bp.newBlockHashMerkleRoot(transactions)
acceptedIDMerkleRoot, err := bp.newBlockAcceptedIDMerkleRoot()
if err != nil {
return nil, err
}
utxoCommitment, err := bp.newBlockUTXOCommitment()
if err != nil {
return nil, err
}
return &externalapi.DomainBlockHeader{
Version: constants.BlockVersion,
ParentHashes: parentHashes,
HashMerkleRoot: *hashMerkleRoot,
AcceptedIDMerkleRoot: *acceptedIDMerkleRoot,
UTXOCommitment: *utxoCommitment,
TimeInMilliseconds: timeInMilliseconds,
Bits: bits,
}, nil
}
func (bp *blockProcessor) newBlockParentHashes() ([]*externalapi.DomainHash, error) {
virtualBlockRelations, err := bp.blockRelationStore.BlockRelation(bp.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
return virtualBlockRelations.Parents, nil
}
func (bp *blockProcessor) newBlockTime(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (int64, error) {
// The timestamp for the block must not be before the median timestamp
// of the last several blocks. Thus, choose the maximum between the
// current time and one second after the past median time. The current
// timestamp is truncated to a millisecond boundary before comparison since a
// block timestamp does not supported a precision greater than one
// millisecond.
newTimestamp := mstime.Now().UnixMilliseconds() + 1
minTimestamp, err := bp.pastMedianTimeManager.PastMedianTime(virtualGHOSTDAGData.SelectedParent)
if err != nil {
return 0, err
}
if newTimestamp < minTimestamp {
newTimestamp = minTimestamp
}
return newTimestamp, nil
}
func (bp *blockProcessor) newBlockDifficulty(virtualGHOSTDAGData *model.BlockGHOSTDAGData) (uint32, error) {
virtualGHOSTDAGData, err := bp.ghostdagDataStore.Get(bp.databaseContext, model.VirtualBlockHash)
if err != nil {
return 0, err
}
return bp.difficultyManager.RequiredDifficulty(virtualGHOSTDAGData.SelectedParent)
}
func (bp *blockProcessor) newBlockHashMerkleRoot(transactions []*externalapi.DomainTransaction) *externalapi.DomainHash {
return merkle.CalculateHashMerkleRoot(transactions)
}
func (bp *blockProcessor) newBlockAcceptedIDMerkleRoot() (*externalapi.DomainHash, error) {
newBlockAcceptanceData, err := bp.acceptanceDataStore.Get(bp.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
var acceptedTransactions []*externalapi.DomainTransaction
for _, blockAcceptanceData := range newBlockAcceptanceData {
for _, transactionAcceptance := range blockAcceptanceData.TransactionAcceptanceData {
if !transactionAcceptance.IsAccepted {
continue
}
acceptedTransactions = append(acceptedTransactions, transactionAcceptance.Transaction)
}
}
sort.Slice(acceptedTransactions, func(i, j int) bool {
acceptedTransactionIID := consensusserialization.TransactionID(acceptedTransactions[i])
acceptedTransactionJID := consensusserialization.TransactionID(acceptedTransactions[j])
return transactionid.Less(acceptedTransactionIID, acceptedTransactionJID)
})
return merkle.CalculateIDMerkleRoot(acceptedTransactions), nil
}
func (bp *blockProcessor) newBlockUTXOCommitment() (*externalapi.DomainHash, error) {
newBlockMultiset, err := bp.multisetStore.Get(bp.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
newBlockUTXOCommitment := newBlockMultiset.Hash()
return newBlockUTXOCommitment, nil
}

View File

@ -12,7 +12,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
)
func (csm *consensusStateManager) calculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (
func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (
*model.UTXODiff, model.AcceptanceData, model.Multiset, error) {
blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, blockHash)
@ -167,7 +167,7 @@ func (csm *consensusStateManager) checkTransactionMass(
}
func (csm *consensusStateManager) RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (model.ReadOnlyUTXOSetIterator, error) {
diff, _, _, err := csm.calculatePastUTXOAndAcceptanceData(blockHash)
diff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash)
if err != nil {
return nil, err
}

View File

@ -63,7 +63,7 @@ func (csm *consensusStateManager) getUnverifiedChainBlocksAndSelectedParentStatu
}
func (csm *consensusStateManager) resolveSingleBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
pastUTXODiff, acceptanceData, multiset, err := csm.calculatePastUTXOAndAcceptanceData(blockHash)
pastUTXODiff, acceptanceData, multiset, err := csm.CalculatePastUTXOAndAcceptanceData(blockHash)
if err != nil {
return 0, err
}

View File

@ -23,7 +23,7 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain
return err
}
virtualUTXODiff, _, _, err := csm.calculatePastUTXOAndAcceptanceData(model.VirtualBlockHash)
virtualUTXODiff, _, _, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash)
if err != nil {
return err
}

View File

@ -0,0 +1,17 @@
package consensus
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
type testConsensus struct {
*consensus
testBlockBuilder model.TestBlockBuilder
}
func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, error) {
return tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions)
}

View File

@ -2,6 +2,7 @@ package domain
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/domain/miningmanager"
@ -11,15 +12,15 @@ import (
// Domain provides a reference to the domain's external aps
type Domain interface {
MiningManager() miningmanager.MiningManager
Consensus() consensus.Consensus
Consensus() externalapi.Consensus
}
type domain struct {
miningManager miningmanager.MiningManager
consensus consensus.Consensus
consensus externalapi.Consensus
}
func (d domain) Consensus() consensus.Consensus {
func (d domain) Consensus() externalapi.Consensus {
return d.consensus
}

View File

@ -1,15 +1,15 @@
package blocktemplatebuilder
import (
"github.com/kaspanet/kaspad/domain/consensus"
"math"
"sort"
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
miningmanagerapi "github.com/kaspanet/kaspad/domain/miningmanager/model"
"github.com/kaspanet/kaspad/util"
"github.com/pkg/errors"
"math"
"sort"
)
type candidateTx struct {
@ -26,13 +26,13 @@ type candidateTx struct {
// blockTemplateBuilder creates block templates for a miner to consume
type blockTemplateBuilder struct {
consensus consensus.Consensus
consensus consensusexternalapi.Consensus
mempool miningmanagerapi.Mempool
policy policy
}
// New creates a new blockTemplateBuilder
func New(consensus consensus.Consensus, mempool miningmanagerapi.Mempool, blockMaxMass uint64) miningmanagerapi.BlockTemplateBuilder {
func New(consensus consensusexternalapi.Consensus, mempool miningmanagerapi.Mempool, blockMaxMass uint64) miningmanagerapi.BlockTemplateBuilder {
return &blockTemplateBuilder{
consensus: consensus,
mempool: mempool,

View File

@ -1,20 +1,20 @@
package miningmanager
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/miningmanager/blocktemplatebuilder"
mempoolpkg "github.com/kaspanet/kaspad/domain/miningmanager/mempool"
)
// Factory instantiates new mining managers
type Factory interface {
NewMiningManager(consensus consensus.Consensus, blockMaxMass uint64) MiningManager
NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager
}
type factory struct{}
// NewMiningManager instantiate a new mining manager
func (f *factory) NewMiningManager(consensus consensus.Consensus, blockMaxMass uint64) MiningManager {
func (f *factory) NewMiningManager(consensus externalapi.Consensus, blockMaxMass uint64) MiningManager {
mempool := mempoolpkg.New(consensus)
blockTemplateBuilder := blocktemplatebuilder.New(consensus, mempool, blockMaxMass)

View File

@ -12,7 +12,6 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/kaspanet/kaspad/domain/consensus"
consensusexternalapi "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensusserialization"
@ -75,7 +74,7 @@ type mempool struct {
orphansByPrev map[consensusexternalapi.DomainOutpoint]map[consensusexternalapi.DomainTransactionID]*consensusexternalapi.DomainTransaction
mempoolUTXOSet *mempoolUTXOSet
consensus consensus.Consensus
consensus consensusexternalapi.Consensus
// nextExpireScan is the time after which the orphan pool will be
// scanned in order to evict orphans. This is NOT a hard deadline as
@ -89,7 +88,7 @@ type mempool struct {
// New returns a new memory pool for validating and storing standalone
// transactions until they are mined into a block.
func New(consensus consensus.Consensus) miningmanagermodel.Mempool {
func New(consensus consensusexternalapi.Consensus) miningmanagermodel.Mempool {
policy := policy{
MaxTxVersion: 0,
AcceptNonStd: false,