mirror of
https://github.com/kaspanet/kaspad.git
synced 2026-02-28 06:03:19 +00:00
* [NOD-1190] Move non-processBlock stuff out of process.go. * [NOD-1190] Move everything out of accept.go. * [NOD-1190] Move all processBlock functions to process.go. * [NOD-1190] Move orphan stuff to orphan.go. * [NOD-1190] Remove thresholdstate stuff. * [NOD-1190] Move isSynced to sync_rate.go. * [NOD-1190] Move delayed block stuff to delayed_blocks.go. * [NOD-1190] Rename orphans.go to orphaned_blocks.go. * [NOD-1190] Move non-BlockDAG structs out of dag.go. * [NOD-1190] Remove unused fields. * [NOD-1190] Fixup BlockDAG.New a bit. * [NOD-1190] Move sequence lock stuff to sequence_lock.go * [NOD-1190] Move some multiset stuff out of dag.go. * [NOD-1190] Move finality stuff out of dag.go. * [NOD-1190] Move blocklocator stuff out of dag.go. * [NOD-1190] Move confirmation stuff out of dag.go. * [NOD-1190] Move utxo and selected parent chain stuff out of dag.go. * [NOD-1190] Move BlockDAG lock functions to the beginning of dag.go. * [NOD-1190] Move verifyAndBuildUTXO out of process.go. * [NOD-1190] Extract handleProcessBlockError to a function. * [NOD-1190] Remove daglock unlock in notifyBlockAccepted. * [NOD-1190] Extract checkDuplicateBlock to a method. * [NOD-1190] Fix merge errors. * [NOD-1190] Remove unused parameter from CalcSequenceLock. * [NOD-1190] Extract processBlock contents into functions. * [NOD-1190] Fix parent delayed blocks not marking their children as delayed * [NOD-1190] Fix TestProcessDelayedBlocks. * [NOD-1190] Extract stuff in maybeAcceptBlock to separate functions. * [NOD-1190] Rename handleProcessBlockError to handleConnectBlockError. * [NOD-1190] Remove some comments. * [NOD-1190] Use lowercase in error messages. * [NOD-1190] Rename createNewBlockNode to createBlockNodeFromBlock. * [NOD-1190] Rename orphaned_blocks.go to orpan_blocks.go. * [NOD-1190] Extract validateUTXOCommitment to a separate function. * [NOD-1190] Fix a bug in validateUTXOCommitment. * [NOD-1190] Rename checkBlockTxsFinalized to checkBlockTransactionsFinalized. * [NOD-1190] Add a comment over createBlockNodeFromBlock. * [NOD-1190] Fold validateAllTxsFinalized into checkBlockTransactionsFinalized. * [NOD-1190] Return parents from checkBlockParents. * [NOD-1190] Remove the processBlock prefix from the functions that had it. * [NOD-1190] Begin extracting functions out of checkTransactionSanity. * [NOD-1190] Finish extracting functions out of checkTransactionSanity. * [NOD-1190] Remove an unused parameter. * [NOD-1190] Fix merge errors. * [NOD-1190] Added an explanation as to why we change the nonce in TestProcessDelayedBlocks. * [NOD-1190] Fix a comment. * [NOD-1190] Fix a comment. * [NOD-1190] Fix a typo. * [NOD-1190] Replace checkBlockParents with handleLookupParentNodesError.
144 lines
5.9 KiB
Go
144 lines
5.9 KiB
Go
package blockdag
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/kaspanet/kaspad/domainmessage"
|
|
"github.com/kaspanet/kaspad/util"
|
|
)
|
|
|
|
// SequenceLock represents the converted relative lock-time in seconds, and
|
|
// absolute block-blue-score for a transaction input's relative lock-times.
|
|
// According to SequenceLock, after the referenced input has been confirmed
|
|
// within a block, a transaction spending that input can be included into a
|
|
// block either after 'seconds' (according to past median time), or once the
|
|
// 'BlockBlueScore' has been reached.
|
|
type SequenceLock struct {
|
|
Milliseconds int64
|
|
BlockBlueScore int64
|
|
}
|
|
|
|
// CalcSequenceLock computes a relative lock-time SequenceLock for the passed
|
|
// transaction using the passed UTXOSet to obtain the past median time
|
|
// for blocks in which the referenced inputs of the transactions were included
|
|
// within. The generated SequenceLock lock can be used in conjunction with a
|
|
// block height, and adjusted median block time to determine if all the inputs
|
|
// referenced within a transaction have reached sufficient maturity allowing
|
|
// the candidate transaction to be included in a block.
|
|
//
|
|
// This function is safe for concurrent access.
|
|
func (dag *BlockDAG) CalcSequenceLock(tx *util.Tx, utxoSet UTXOSet) (*SequenceLock, error) {
|
|
dag.dagLock.RLock()
|
|
defer dag.dagLock.RUnlock()
|
|
|
|
return dag.calcSequenceLock(dag.selectedTip(), utxoSet, tx)
|
|
}
|
|
|
|
// CalcSequenceLockNoLock is lock free version of CalcSequenceLockWithLock
|
|
// This function is unsafe for concurrent access.
|
|
func (dag *BlockDAG) CalcSequenceLockNoLock(tx *util.Tx, utxoSet UTXOSet) (*SequenceLock, error) {
|
|
return dag.calcSequenceLock(dag.selectedTip(), utxoSet, tx)
|
|
}
|
|
|
|
// calcSequenceLock computes the relative lock-times for the passed
|
|
// transaction. See the exported version, CalcSequenceLock for further details.
|
|
//
|
|
// This function MUST be called with the DAG state lock held (for writes).
|
|
func (dag *BlockDAG) calcSequenceLock(node *blockNode, utxoSet UTXOSet, tx *util.Tx) (*SequenceLock, error) {
|
|
// A value of -1 for each relative lock type represents a relative time
|
|
// lock value that will allow a transaction to be included in a block
|
|
// at any given height or time.
|
|
sequenceLock := &SequenceLock{Milliseconds: -1, BlockBlueScore: -1}
|
|
|
|
// Sequence locks don't apply to coinbase transactions Therefore, we
|
|
// return sequence lock values of -1 indicating that this transaction
|
|
// can be included within a block at any given height or time.
|
|
if tx.IsCoinBase() {
|
|
return sequenceLock, nil
|
|
}
|
|
|
|
mTx := tx.MsgTx()
|
|
for txInIndex, txIn := range mTx.TxIn {
|
|
entry, ok := utxoSet.Get(txIn.PreviousOutpoint)
|
|
if !ok {
|
|
str := fmt.Sprintf("output %s referenced from "+
|
|
"transaction %s input %d either does not exist or "+
|
|
"has already been spent", txIn.PreviousOutpoint,
|
|
tx.ID(), txInIndex)
|
|
return sequenceLock, ruleError(ErrMissingTxOut, str)
|
|
}
|
|
|
|
// If the input blue score is set to the mempool blue score, then we
|
|
// assume the transaction makes it into the next block when
|
|
// evaluating its sequence blocks.
|
|
inputBlueScore := entry.BlockBlueScore()
|
|
if entry.IsUnaccepted() {
|
|
inputBlueScore = dag.virtual.blueScore
|
|
}
|
|
|
|
// Given a sequence number, we apply the relative time lock
|
|
// mask in order to obtain the time lock delta required before
|
|
// this input can be spent.
|
|
sequenceNum := txIn.Sequence
|
|
relativeLock := int64(sequenceNum & domainmessage.SequenceLockTimeMask)
|
|
|
|
switch {
|
|
// Relative time locks are disabled for this input, so we can
|
|
// skip any further calculation.
|
|
case sequenceNum&domainmessage.SequenceLockTimeDisabled == domainmessage.SequenceLockTimeDisabled:
|
|
continue
|
|
case sequenceNum&domainmessage.SequenceLockTimeIsSeconds == domainmessage.SequenceLockTimeIsSeconds:
|
|
// This input requires a relative time lock expressed
|
|
// in seconds before it can be spent. Therefore, we
|
|
// need to query for the block prior to the one in
|
|
// which this input was accepted within so we can
|
|
// compute the past median time for the block prior to
|
|
// the one which accepted this referenced output.
|
|
blockNode := node
|
|
for blockNode.selectedParent.blueScore > inputBlueScore {
|
|
blockNode = blockNode.selectedParent
|
|
}
|
|
medianTime := blockNode.PastMedianTime(dag)
|
|
|
|
// Time based relative time-locks have a time granularity of
|
|
// domainmessage.SequenceLockTimeGranularity, so we shift left by this
|
|
// amount to convert to the proper relative time-lock. We also
|
|
// subtract one from the relative lock to maintain the original
|
|
// lockTime semantics.
|
|
timeLockMilliseconds := (relativeLock << domainmessage.SequenceLockTimeGranularity) - 1
|
|
timeLock := medianTime.UnixMilliseconds() + timeLockMilliseconds
|
|
if timeLock > sequenceLock.Milliseconds {
|
|
sequenceLock.Milliseconds = timeLock
|
|
}
|
|
default:
|
|
// The relative lock-time for this input is expressed
|
|
// in blocks so we calculate the relative offset from
|
|
// the input's blue score as its converted absolute
|
|
// lock-time. We subtract one from the relative lock in
|
|
// order to maintain the original lockTime semantics.
|
|
blockBlueScore := int64(inputBlueScore) + relativeLock - 1
|
|
if blockBlueScore > sequenceLock.BlockBlueScore {
|
|
sequenceLock.BlockBlueScore = blockBlueScore
|
|
}
|
|
}
|
|
}
|
|
|
|
return sequenceLock, nil
|
|
}
|
|
|
|
// LockTimeToSequence converts the passed relative locktime to a sequence
|
|
// number.
|
|
func LockTimeToSequence(isMilliseconds bool, locktime uint64) uint64 {
|
|
// If we're expressing the relative lock time in blocks, then the
|
|
// corresponding sequence number is simply the desired input age.
|
|
if !isMilliseconds {
|
|
return locktime
|
|
}
|
|
|
|
// Set the 22nd bit which indicates the lock time is in milliseconds, then
|
|
// shift the locktime over by 19 since the time granularity is in
|
|
// 524288-millisecond intervals (2^19). This results in a max lock-time of
|
|
// 34,359,214,080 seconds, or 1.1 years.
|
|
return domainmessage.SequenceLockTimeIsSeconds |
|
|
locktime>>domainmessage.SequenceLockTimeGranularity
|
|
}
|