mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* Check blue score before requesting a pruning proof * BuildPruningPointProof should return empty proof if the pruning point is genesis * Don't fail many-tips if kaspad exits ungracefully
337 lines
14 KiB
Go
337 lines
14 KiB
Go
package ruleerrors
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// These constants are used to identify a specific RuleError.
|
|
var (
|
|
// ErrDuplicateBlock indicates a block with the same hash already
|
|
// exists.
|
|
ErrDuplicateBlock = newRuleError("ErrDuplicateBlock")
|
|
|
|
// ErrBlockVersionTooOld indicates the block version is too old and is
|
|
// no longer accepted since the majority of the network has upgraded
|
|
// to a newer version.
|
|
ErrBlockVersionTooOld = newRuleError("ErrBlockVersionTooOld")
|
|
|
|
// ErrTimeTooOld indicates the time is either before the median time of
|
|
// the last several blocks per the DAG consensus rules.
|
|
ErrTimeTooOld = newRuleError("ErrTimeTooOld")
|
|
|
|
//ErrTimeTooMuchInTheFuture indicates that the block timestamp is too much in the future.
|
|
ErrTimeTooMuchInTheFuture = newRuleError("ErrTimeTooMuchInTheFuture")
|
|
|
|
// ErrNoParents indicates that the block is missing parents
|
|
ErrNoParents = newRuleError("ErrNoParents")
|
|
|
|
// ErrUnexpectedDifficulty indicates specified bits do not align with
|
|
// the expected value either because it doesn't match the calculated
|
|
// valued based on difficulty regarted rules.
|
|
ErrUnexpectedDifficulty = newRuleError("ErrUnexpectedDifficulty")
|
|
|
|
// ErrUnexpectedDAAScore indicates specified DAA score does not align with
|
|
// the expected value.
|
|
ErrUnexpectedDAAScore = newRuleError("ErrUnexpectedDAAScore")
|
|
|
|
// ErrUnexpectedBlueWork indicates specified blue work does not align with
|
|
// the expected value.
|
|
ErrUnexpectedBlueWork = newRuleError("ErrUnexpectedBlueWork")
|
|
|
|
// ErrUnexpectedFinalityPoint indicates specified finality point does not align with
|
|
// the expected value.
|
|
ErrUnexpectedFinalityPoint = newRuleError("ErrUnexpectedFinalityPoint")
|
|
|
|
// ErrUnexpectedCoinbaseBlueScore indicates specified blue score in the coinbase does not align with
|
|
// the expected value.
|
|
ErrUnexpectedCoinbaseBlueScore = newRuleError("ErrUnexpectedCoinbaseBlueScore")
|
|
|
|
// ErrUnexpectedHeaderBlueScore indicates specified blue score in the header does not align with
|
|
// the expected value.
|
|
ErrUnexpectedHeaderBlueScore = newRuleError("ErrUnexpectedHeaderBlueScore")
|
|
|
|
// ErrTargetTooHigh indicates specified bits do not align with
|
|
// the expected value either because it is above the valid
|
|
// range.
|
|
ErrTargetTooHigh = newRuleError("ErrTargetTooHigh")
|
|
|
|
// ErrUnexpectedDifficulty indicates specified bits do not align with
|
|
// the expected value either because it is negative.
|
|
ErrNegativeTarget = newRuleError("ErrNegativeTarget")
|
|
|
|
// ErrInvalidPoW indicates that the block proof-of-work is invalid.
|
|
ErrInvalidPoW = newRuleError("ErrInvalidPoW")
|
|
|
|
// ErrBadMerkleRoot indicates the calculated merkle root does not match
|
|
// the expected value.
|
|
ErrBadMerkleRoot = newRuleError("ErrBadMerkleRoot")
|
|
|
|
// ErrBadUTXOCommitment indicates the calculated UTXO commitment does not match
|
|
// the expected value.
|
|
ErrBadUTXOCommitment = newRuleError("ErrBadUTXOCommitment")
|
|
|
|
// ErrFinalityPointTimeTooOld indicates a block has a timestamp before the
|
|
// last finality point.
|
|
ErrFinalityPointTimeTooOld = newRuleError("ErrFinalityPointTimeTooOld")
|
|
|
|
// ErrNoTransactions indicates the block does not have a least one
|
|
// transaction. A valid block must have at least the coinbase
|
|
// transaction.
|
|
ErrNoTransactions = newRuleError("ErrNoTransactions")
|
|
|
|
// ErrNoTxInputs indicates a transaction does not have any inputs. A
|
|
// valid transaction must have at least one input.
|
|
ErrNoTxInputs = newRuleError("ErrNoTxInputs")
|
|
|
|
// ErrBadTxOutValue indicates an output value for a transaction is
|
|
// invalid in some way such as being out of range.
|
|
ErrBadTxOutValue = newRuleError("ErrBadTxOutValue")
|
|
ErrTxOutValueZero = newRuleError("ErrTxOutValueZero")
|
|
|
|
// ErrDuplicateTxInputs indicates a transaction references the same
|
|
// input more than once.
|
|
ErrDuplicateTxInputs = newRuleError("ErrDuplicateTxInputs")
|
|
|
|
// ErrDoubleSpendInSameBlock indicates a transaction
|
|
// that spends an output that was already spent by another
|
|
// transaction in the same block.
|
|
ErrDoubleSpendInSameBlock = newRuleError("ErrDoubleSpendInSameBlock")
|
|
|
|
// ErrUnfinalizedTx indicates a transaction has not been finalized.
|
|
// A valid block may only contain finalized transactions.
|
|
ErrUnfinalizedTx = newRuleError("ErrUnfinalizedTx")
|
|
|
|
// ErrDuplicateTx indicates a block contains an identical transaction
|
|
// (or at least two transactions which hash to the same value). A
|
|
// valid block may only contain unique transactions.
|
|
ErrDuplicateTx = newRuleError("ErrDuplicateTx")
|
|
|
|
// ErrImmatureSpend indicates a transaction is attempting to spend a
|
|
// coinbase that has not yet reached the required maturity.
|
|
ErrImmatureSpend = newRuleError("ErrImmatureSpend")
|
|
|
|
// ErrSpendTooHigh indicates a transaction is attempting to spend more
|
|
// value than the sum of all of its inputs.
|
|
ErrSpendTooHigh = newRuleError("ErrSpendTooHigh")
|
|
|
|
// ErrFirstTxNotCoinbase indicates the first transaction in a block
|
|
// is not a coinbase transaction.
|
|
ErrFirstTxNotCoinbase = newRuleError("ErrFirstTxNotCoinbase")
|
|
|
|
// ErrMultipleCoinbases indicates a block contains more than one
|
|
// coinbase transaction.
|
|
ErrMultipleCoinbases = newRuleError("ErrMultipleCoinbases")
|
|
|
|
// ErrBadCoinbasePayloadLen indicates the length of the payload
|
|
// for a coinbase transaction is too high.
|
|
ErrBadCoinbasePayloadLen = newRuleError("ErrBadCoinbasePayloadLen")
|
|
|
|
// ErrBadCoinbaseTransaction indicates that the block's coinbase transaction is not build as expected
|
|
ErrBadCoinbaseTransaction = newRuleError("ErrBadCoinbaseTransaction")
|
|
|
|
// ErrScriptMalformed indicates a transaction script is malformed in
|
|
// some way. For example, it might be longer than the maximum allowed
|
|
// length or fail to parse.
|
|
ErrScriptMalformed = newRuleError("ErrScriptMalformed")
|
|
|
|
// ErrScriptValidation indicates the result of executing transaction
|
|
// script failed. The error covers any failure when executing scripts
|
|
// such signature verification failures and execution past the end of
|
|
// the stack.
|
|
ErrScriptValidation = newRuleError("ErrScriptValidation")
|
|
|
|
// ErrInvalidAncestorBlock indicates that an ancestor of this block has
|
|
// already failed validation.
|
|
ErrInvalidAncestorBlock = newRuleError("ErrInvalidAncestorBlock")
|
|
|
|
// ErrTransactionsNotSorted indicates that transactions in block are not
|
|
// sorted by subnetwork
|
|
ErrTransactionsNotSorted = newRuleError("ErrTransactionsNotSorted")
|
|
|
|
// ErrInvalidGas transaction wants to use more GAS than allowed
|
|
// by subnetwork
|
|
ErrInvalidGas = newRuleError("ErrInvalidGas")
|
|
|
|
// ErrInvalidPayload transaction includes a payload in a subnetwork that doesn't allow
|
|
// a Payload
|
|
ErrInvalidPayload = newRuleError("ErrInvalidPayload")
|
|
|
|
// ErrWrongSigOpCount transaction input specifies an incorrect SigOpCount
|
|
ErrWrongSigOpCount = newRuleError("ErrWrongSigOpCount")
|
|
|
|
// ErrSubnetwork indicates that a block doesn't adhere to the subnetwork
|
|
// registry rules
|
|
ErrSubnetworkRegistry = newRuleError("ErrSubnetworkRegistry")
|
|
|
|
// ErrInvalidParentsRelation indicates that one of the parents of a block
|
|
// is also an ancestor of another parent
|
|
ErrInvalidParentsRelation = newRuleError("ErrInvalidParentsRelation")
|
|
|
|
// ErrTooManyParents indicates that a block points to more then `MaxNumParentBlocks` parents
|
|
ErrTooManyParents = newRuleError("ErrTooManyParents")
|
|
|
|
// ErrViolatingBoundedMergeDepth indicates that a block is violating finality from
|
|
// its own point of view
|
|
ErrViolatingBoundedMergeDepth = newRuleError("ErrViolatingBoundedMergeDepth")
|
|
|
|
// ErrViolatingMergeLimit indicates that a block merges more than mergeLimit blocks
|
|
ErrViolatingMergeLimit = newRuleError("ErrViolatingMergeLimit")
|
|
|
|
// ErrChainedTransactions indicates that a block contains a transaction that spends an output of a transaction
|
|
// In the same block
|
|
ErrChainedTransactions = newRuleError("ErrChainedTransactions")
|
|
|
|
// ErrBlockMassTooHigh indicates the mass of a block exceeds the maximum
|
|
// allowed limits.
|
|
ErrBlockMassTooHigh = newRuleError("ErrBlockMassTooHigh")
|
|
|
|
ErrKnownInvalid = newRuleError("ErrKnownInvalid")
|
|
|
|
ErrSubnetworksDisabled = newRuleError("ErrSubnetworksDisabled")
|
|
ErrBadPruningPointUTXOSet = newRuleError("ErrBadPruningPointUTXOSet")
|
|
|
|
ErrMalformedUTXO = newRuleError("ErrMalformedUTXO")
|
|
|
|
ErrWrongPruningPointHash = newRuleError("ErrWrongPruningPointHash")
|
|
|
|
//ErrPruningPointViolation indicates that the pruning point isn't in the block past.
|
|
ErrPruningPointViolation = newRuleError("ErrPruningPointViolation")
|
|
|
|
ErrUnexpectedParents = newRuleError("ErrUnexpectedParents")
|
|
|
|
ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint")
|
|
|
|
ErrInvalidPruningPointsChain = newRuleError("ErrInvalidPruningPointsChain")
|
|
|
|
ErrSuggestedPruningViolatesFinality = newRuleError("ErrSuggestedPruningViolatesFinality")
|
|
|
|
//ErrBlockVersionIsUnknown indicates that the block version is unknown.
|
|
ErrBlockVersionIsUnknown = newRuleError("ErrBlockVersionIsUnknown")
|
|
|
|
//ErrTransactionVersionIsUnknown indicates that the transaction version is unknown.
|
|
ErrTransactionVersionIsUnknown = newRuleError("ErrTransactionVersionIsUnknown")
|
|
|
|
// ErrPrunedBlock indicates that the block currently being validated had already been pruned.
|
|
ErrPrunedBlock = newRuleError("ErrPrunedBlock")
|
|
|
|
ErrGetVirtualUTXOsWrongVirtualParents = newRuleError("ErrGetVirtualUTXOsWrongVirtualParents")
|
|
|
|
ErrVirtualGenesisParent = newRuleError("ErrVirtualGenesisParent")
|
|
|
|
ErrGenesisOnInitializedConsensus = newRuleError("ErrGenesisOnInitializedConsensus")
|
|
|
|
ErrPruningPointSelectedChildDisqualifiedFromChain = newRuleError("ErrPruningPointSelectedChildDisqualifiedFromChain")
|
|
|
|
// ErrUnexpectedFinalityPoint indicates a block header pruning point does not align with
|
|
// the expected value.
|
|
ErrUnexpectedHeaderPruningPoint = newRuleError("ErrUnexpectedHeaderPruningPoint")
|
|
|
|
ErrPruningProofHeaderWithNoKnownParents = newRuleError("ErrPruningProofHeaderWithNoKnownParents")
|
|
ErrPruningProofMissingBlockLevels = newRuleError("ErrPruningProofMissingBlockLevels")
|
|
ErrPruningProofWrongBlockLevel = newRuleError("ErrPruningProofWrongBlockLevel")
|
|
ErrPruningProofSelectedTipNotParentOfPruningPoint = newRuleError("ErrPruningProofSelectedTipNotParentOfPruningPoint")
|
|
ErrPruningProofSelectedTipIsNotThePruningPoint = newRuleError("ErrPruningProofSelectedTipIsNotThePruningPoint")
|
|
ErrPruningProofInsufficientBlueWork = newRuleError("ErrPruningProofInsufficientBlueWork")
|
|
ErrPruningProofMissingBlockAtDepthMFromNextLevel = newRuleError("ErrPruningProofMissingBlockAtDepthMFromNextLevel")
|
|
ErrPruningProofMissesBlocksBelowPruningPoint = newRuleError("ErrPruningProofMissesBlocksBelowPruningPoint")
|
|
ErrPruningProofEmpty = newRuleError("ErrPruningProofEmpty")
|
|
ErrWrongCoinbaseSubsidy = newRuleError("ErrWrongCoinbaseSubsidy")
|
|
)
|
|
|
|
// RuleError identifies a rule violation. It is used to indicate that
|
|
// processing of a block or transaction failed due to one of the many validation
|
|
// rules. The caller can use type assertions to determine if a failure was
|
|
// specifically due to a rule violation.
|
|
type RuleError struct {
|
|
message string
|
|
inner error
|
|
}
|
|
|
|
// Error satisfies the error interface and prints human-readable errors.
|
|
func (e RuleError) Error() string {
|
|
if e.inner != nil {
|
|
return e.message + ": " + e.inner.Error()
|
|
}
|
|
return e.message
|
|
}
|
|
|
|
// Unwrap satisfies the errors.Unwrap interface
|
|
func (e RuleError) Unwrap() error {
|
|
return e.inner
|
|
}
|
|
|
|
// Cause satisfies the github.com/pkg/errors.Cause interface
|
|
func (e RuleError) Cause() error {
|
|
return e.inner
|
|
}
|
|
|
|
func newRuleError(message string) RuleError {
|
|
return RuleError{message: message, inner: nil}
|
|
}
|
|
|
|
// ErrMissingTxOut indicates a transaction output referenced by an input
|
|
// either does not exist or has already been spent.
|
|
type ErrMissingTxOut struct {
|
|
MissingOutpoints []*externalapi.DomainOutpoint
|
|
}
|
|
|
|
func (e ErrMissingTxOut) Error() string {
|
|
return fmt.Sprintf("missing the following outpoint: %v", e.MissingOutpoints)
|
|
}
|
|
|
|
// NewErrMissingTxOut Creates a new ErrMissingTxOut error wrapped in a RuleError
|
|
func NewErrMissingTxOut(missingOutpoints []*externalapi.DomainOutpoint) error {
|
|
return errors.WithStack(RuleError{
|
|
message: "ErrMissingTxOut",
|
|
inner: ErrMissingTxOut{missingOutpoints},
|
|
})
|
|
}
|
|
|
|
// ErrMissingParents indicates a block points to unknown parent(s).
|
|
type ErrMissingParents struct {
|
|
MissingParentHashes []*externalapi.DomainHash
|
|
}
|
|
|
|
func (e ErrMissingParents) Error() string {
|
|
return fmt.Sprintf("missing the following parent hashes: %v", e.MissingParentHashes)
|
|
}
|
|
|
|
// NewErrMissingParents creates a new ErrMissingParents error wrapped in a RuleError
|
|
func NewErrMissingParents(missingParentHashes []*externalapi.DomainHash) error {
|
|
return errors.WithStack(RuleError{
|
|
message: "ErrMissingParents",
|
|
inner: ErrMissingParents{missingParentHashes},
|
|
})
|
|
}
|
|
|
|
// InvalidTransaction is a struct containing an invalid transaction, and the error explaining why it's invalid.
|
|
type InvalidTransaction struct {
|
|
Transaction *externalapi.DomainTransaction
|
|
Error error
|
|
}
|
|
|
|
func (invalid InvalidTransaction) String() string {
|
|
return fmt.Sprintf("(%v: %s)", consensushashing.TransactionID(invalid.Transaction), invalid.Error)
|
|
}
|
|
|
|
// ErrInvalidTransactionsInNewBlock indicates that some transactions in a new block are invalid
|
|
type ErrInvalidTransactionsInNewBlock struct {
|
|
InvalidTransactions []InvalidTransaction
|
|
}
|
|
|
|
func (e ErrInvalidTransactionsInNewBlock) Error() string {
|
|
return fmt.Sprint(e.InvalidTransactions)
|
|
}
|
|
|
|
// NewErrInvalidTransactionsInNewBlock Creates a new ErrInvalidTransactionsInNewBlock error wrapped in a RuleError
|
|
func NewErrInvalidTransactionsInNewBlock(invalidTransactions []InvalidTransaction) error {
|
|
return errors.WithStack(RuleError{
|
|
message: "ErrInvalidTransactionsInNewBlock",
|
|
inner: ErrInvalidTransactionsInNewBlock{invalidTransactions},
|
|
})
|
|
}
|