mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-24 07:46:45 +00:00

* [NOD-1416] Add entry/exit logs to all the functions. * [NOD-1416] Build some scaffolding inside BlockProcessor. * [NOD-1416] Implement selectParentsForNewBlock. * [NOD-1416] Implement validateBlock. * [NOD-1476] Fix merge errors. * [NOD-1416] Move buildBlock and validateAndInsertBlock to separate files. * [NOD-1416] Begin implementing buildBlock. * [NOD-1416] Implement newBlockDifficulty. * [NOD-1416] Add skeletons for the rest of the buildBlock functions. * [NOD-1416] Implement newBlockUTXOCommitment. * [NOD-1416] Implement newBlockAcceptedIDMerkleRoot. * [NOD-1416] Implement newBlockHashMerkleRoot. * [NOD-1416] Fix bad function call. * [NOD-1416] Implement validateHeaderAndProofOfWork and validateBody. * [NOD-1416] Use ValidateProofOfWorkAndDifficulty. * [NOD-1416] Finish validateAndInsertBlock. * [NOD-1416] Implement newBlockHashMerkleRoot. * [NOD-1416] Implement newBlockAcceptedIDMerkleRoot. * [NOD-1416] Fix a comment. * [NOD-1416] Implement newBlockCoinbaseTransaction. * [NOD-1416] Add VirtualBlockHash. * [NOD-1416] Add ParentHashes and SelectedParent to VirtualData(). * [NOD-1416] Make go vet happy. * [NOD-1416] Implement discardAllChanges. * [NOD-1416] Implement commitAllChanges. * [NOD-1416] Fix factory. * [NOD-1416] Make go vet happy. * [NOD-1416] Format factory. * [NOD-1416] Pass transactionsWithCoinbase to buildHeader. * [NOD-1416] Call VirtualData() from buildHeader. * [NOD-1416] Fix a typo. * [NOD-1416] Fix in-out-of-context/header-body confusion. * [NOD-1416] Extract LogAndMeasureExecutionTime. * [NOD-1416] Add a comment about LogAndMeasureExecutionTime. * [NOD-1416] Simplify discardAllChanges and commitAllChanges. * [NOD-1416] If in-context validations fail, discard all changes and store the block with StatusInvalid. * [NOD-1416] Add a comment above Store. * [NOD-1416] Use errors.As instead of errors.Is.
143 lines
4.8 KiB
Go
143 lines
4.8 KiB
Go
package blockprocessor
|
|
|
|
import (
|
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashserialization"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionid"
|
|
"github.com/kaspanet/kaspad/util/mstime"
|
|
"sort"
|
|
)
|
|
|
|
const blockVersion = 1
|
|
|
|
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
|
|
}
|
|
headerHash := hashserialization.HeaderHash(header)
|
|
|
|
return &externalapi.DomainBlock{
|
|
Header: header,
|
|
Transactions: transactionsWithCoinbase,
|
|
Hash: headerHash,
|
|
}, 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) {
|
|
virtualData, err := bp.consensusStateManager.VirtualData()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
parentHashes, err := bp.newBlockParentHashes(virtualData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
timeInMilliseconds, err := bp.newBlockTime(virtualData)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bits, err := bp.newBlockDifficulty(virtualData)
|
|
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: blockVersion,
|
|
ParentHashes: parentHashes,
|
|
HashMerkleRoot: *hashMerkleRoot,
|
|
AcceptedIDMerkleRoot: *acceptedIDMerkleRoot,
|
|
UTXOCommitment: *utxoCommitment,
|
|
TimeInMilliseconds: timeInMilliseconds,
|
|
Bits: bits,
|
|
}, nil
|
|
}
|
|
|
|
func (bp *blockProcessor) newBlockParentHashes(virtualData *model.VirtualData) ([]*externalapi.DomainHash, error) {
|
|
return virtualData.ParentHashes, nil
|
|
}
|
|
|
|
func (bp *blockProcessor) newBlockTime(virtualData *model.VirtualData) (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(virtualData.SelectedParent)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if newTimestamp < minTimestamp {
|
|
newTimestamp = minTimestamp
|
|
}
|
|
return newTimestamp, nil
|
|
}
|
|
|
|
func (bp *blockProcessor) newBlockDifficulty(virtualData *model.VirtualData) (uint32, error) {
|
|
return bp.difficultyManager.RequiredDifficulty(virtualData.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 := hashserialization.TransactionID(acceptedTransactions[i])
|
|
acceptedTransactionJID := hashserialization.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
|
|
}
|