mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[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:
parent
2282e36196
commit
6db337c8c5
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
21
domain/consensus/model/externalapi/consensus.go
Normal file
21
domain/consensus/model/externalapi/consensus.go
Normal 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)
|
||||
}
|
15
domain/consensus/model/interface_processes_blockbuilder.go
Normal file
15
domain/consensus/model/interface_processes_blockbuilder.go
Normal 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)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
11
domain/consensus/model/testapi/test_consensus.go
Normal file
11
domain/consensus/model/testapi/test_consensus.go
Normal 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)
|
||||
}
|
210
domain/consensus/processes/blockbuilder/block_builder.go
Normal file
210
domain/consensus/processes/blockbuilder/block_builder.go
Normal 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
|
||||
}
|
7
domain/consensus/processes/blockbuilder/log.go
Normal file
7
domain/consensus/processes/blockbuilder/log.go
Normal file
@ -0,0 +1,7 @@
|
||||
package blockbuilder
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||
)
|
||||
|
||||
var log, _ = logger.Get(logger.SubsystemTags.BDAG)
|
100
domain/consensus/processes/blockbuilder/test_block_builder.go
Normal file
100
domain/consensus/processes/blockbuilder/test_block_builder.go
Normal 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
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
17
domain/consensus/test_consensus.go
Normal file
17
domain/consensus/test_consensus.go
Normal 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)
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user