This is based on https://proposals.decred.org/proposals/c96290a but was modified in order to deal with realities that were unknown at the time of the specification draft. It is large and could not really be broken apart due to the pervasive use of the isTreasuryEnabled flag. It was primarily authored by * Marco Peereboom <marco@peereboom.us> * Dave Collins <davec@conformal.com> * Matheus Degiovani <opensource@matheusd.com> With additional contributions from * Donald Adu-Poku <donald.adu@gmail.com> * Jamie Holdstock <jholdstock@decred.org> Major changes: * Add decentralized treasury agenda, as specified in DCP0006, to all supported nets. * Add functions to determine if the decentralized treasury agenda is active at given block. * Add new opcode OP_TADD that is a nop in txscript but is used to tag scripts that credit the treasury account. This opcode is overloaded for treasurybase and for normal transactions. * Add new opcode OP_TSPEND that is a nop in txscript but is used to tag scripts that debit the treasury account. * Add new opcode OP_TGEN that is a nop in txscript but is used to tag P2PKH and P2SH outputs in a TSpend transaction. * Add functions that detect if a transaction is a valid TAdd, TSpend or treasurybase transaction. * Add error codes that return specific treasurybase/TAdd/TSpend consensus violations. * Modify countSpentOutputs to deal with treasury opcodes accordingly. * Modify indexBlock to skip treasury transactions that do not have inputs. * Add IsTreasuryEnabled call to ChainQueryer interface. * Add treasury logger for debugging and logging the decentralized treasury subsystem. * Add IsTreasuryActive flag to BlockConnectedNtfnsData and BlockDisconnectedNtfnsData. * Modify OP_SSGEN to allow an optional output that contains votes for a TSpend transaction hash. * Add function that returns TSpend votes from an SSGen transaction. * Modify CalcStakeVoteSubsidy so that treasurybase, unlike coinbase, is always awarded the full percentage of the assigned block reward. * Add helper functions to do all TSpend math so that callers don't roll their own. * Modify IsCoinBaseTx to not mistake a TSpend transaction as a coinbase. * Add checkTreasuryBase function that verifies that a treasurybase is properly constructed and pays the right amount to the treasury account. * Add functions to calculate treasury balance for the provided block hash/node. * Add function that verifies if a TSpend has a valid signature. * Add functions to determine if a TSpend is not overspending. * Add function to determine if a TSpend has been mined on the provided chain. * Add functions that count and verifies treasury spend votes. * Modify connectTransaction and disconnectTransactions to deal with the various treasury transactions. * Split CheckTransactionSanity in two functions checkTransactionSanityContextFree and checkTransactionSanityContextual. This is done in order to keep the decentralized treasury, which is always contextual, from infecting the context free checks. * Modify checkTransactionSanityContextual to recognize and verify treasury transactions. * Modify CheckTransactionSanity to deal with treasury transactions. * Split checkBlockSanity in two functions checkBlockSanityContextFree and checkBlockSanityContextual. This is done in order to keep the decentralized treasury, which is always contextual, from infecting the context free checks. * Modify checkBlockSanityContextual to enforce treasurybase and TAdd consensus checks. * Modify checkBlockPositional by unindenting it and adding TSpend consensus enforcement. * Modify checkCoinbaseUniqueHeightWithAddress to deal with the removal of the project subsidy from output 0. * Add checkCoinbaseUniqueHeightWithTreasuryBase that verifies coinbase and treasurybase in the provided block. * Unindent checkBlockContext. * Modify checkTicketRedeemerCommitments and checkVoteInputs to deal with potential tspend votes. * Modify CheckTransactionInputs to skip treasurybase transactions. * Modify CheckTransactionInputs to deal with TSpend transactions. Ensure the provided Pi key is valid and that the signature is valid for the transaction. Ensure that treasury TAdd and TSpend transaction utxo can only be spent after coinbase maturity. * Modify CountSigOps to deal with treasury transactions. * Modify CountP2SHSigOps to deal with treasury transactions. * Modify getStakeTreeFees to skip treasury transactions. Modify totalOutputs to subtract ValueIn 0 for TSpend and treasurybase transactions. * Modify checkTransactionsAndConnect to deal with modified amounts. * Add tspendChecks function that verifies an entire TSpend transaction validity at the point of the provided block. It ensures a TSpend is on a TVI. It ensures the TSpend is in the valid window. It verifies that a TSpend In and Out amounts match. It ensures a TSpend has the ValueIn amount encoded in the OP_RETURN in Out 0. It ensures a TSpend has not been mined before on this chain. It ensures a TSpend has the requisite votes. It ensures a TSpend is not overspending. * Modify checkConnectBlock to call checkTreasuryBase and tspendChecks when treasury agenda is active. * Add two tables to the database. Table "treasury" records the balance as of this block and balance changes that occurred in this block which will become active in CoinbaseMaturity blocks. Table "tspend" records all block hashes where a TSpend has been mined this is to detect forks and prevent a Tspend from being mined more than once. * Modify handleBlockchainNotification to communicate if the treasury agenda is active and skip treasurybase transaction when needed. * Add various Treasury parameters to chaincfg params. * Add hardcoded Tspend signatures in dcr_tmux_simnet_setup.sh. * Add notifytspend and stoptspend calls to the RPC server. notifytspend notifies the mempool when a TSpend transaction arrives. * Modify commit filters V2 to recognize TAdd and TSpend transactions. It was possible to modify V2 instead of introducing V3 because nothing changes from the viewpoint of the wallet and treasury opcodes are disallowed prior to agenda activation. * Modify AddMemPoolTransaction to skip TSpend transactions that would throw the fee estimator off. * Add IsTreasuryAgendaActive, OnTSpendReceived and TSpendMinedOnAncestor to mempool.Config in order to reject/accept TSpends in the mempool. * Modify checkPoolDoubleSpend to ignore treasurybase. * Modify mempool.maybeAcceptTransaction to enforce treasury standardness rules. Don't allow TSpend transactions prior to stake validation height. Skip treasurybase and tspend transactions in the orphan test. Ensure a tspend is in a valid window. Ensure not more than 7 TSpends are active in the mempool. Ensure TSpend has a well-known Pi key. Ensure The provided Pi key was used to sign the transaction. Ensure TSpend was not mined in an ancestor block. Notify subscribers that a valid TSpend was received. * Add standardCoinbaseOpReturn and standardTreasurybaseOpReturn to create an OP_RETURN followed by a data push that little endian encodes the height of the block. Then there are a number of random bytes to ensure that the transaction hash is always random. * Modify createCoinbaseTx to create a coinbase that is valid when treasury is enabled or not. Additionally, alter the transaction version if treasury is enabled. * Add createTreasuryBaseTx that creates a standard treasurybase. * Modify maybeInsertStakeTx to recognize treasurybase and TSpend transactions. * Modify handleTooFewVoters to call createTreasuryBaseTx when the treasury agenda is active. Skip copying treasurybase. * Modify NewBlockTemplate to recognize and deal with treasury transactions. Skip TSpend transaction if block is not a TVI. Skip TSpend transaction if it is not in the proper window. Skip TSpend transaction if a TSpend does not have enough yes votes. Skip TSpend transaction if it overspends the treasury account. Skip TAdd if there are more than 20 TAdds in the block. Create treasurybase if required. Insert valid TAdd/TSpend transactions into stake tree. * Add TreasuryBalance and IsTreasuryAgendaActive to rpcserver Chain interface. * Add gettreasurybalance, sendfromtreasury and sendtotreasury calls to RPC server. * Add notifytspend and stopnotifytspend to RPC websocket commands. * Add simnet miner to generate large number of blocks during rpctests without triggering PoW difficulty increases. This is used to verify various treasury and tspend conditions during CI/CT. * Modify RPC voting wallet to also vote on TSpends. * Add json tests to verify all new opcodes and corner cases in the script engine. * Modify isStakeOpcode to recognize treasury opcodes. * Modify countSigOpsV0 to count TSpends. * Modify handleStakeOutSign to deal with TSpends. * Modify SignTxOutput to recognize TSpends. * Add TSpendSignatureScript that signs a TSpend transaction. * Add TreasuryAddTy and TreasurySpendTy types to the standard scripts. * Add isTreasuryAddScript and isTreasurySpendScript functions that recognize a form of TAdd and TSpend transactions. * Modify ExtractPkScriptAddrs to deal with TAdd and TSpend outputs. * Add TxVersionSeqLock = 2 and TxVersionTreasury = 3 to wire. This is used to discriminate between treasury and non-treasury scripts. * Rig up all functions that need the isTreasuryEnabledflag directly or indirectly. * Shuffle various functions around and export them when they were needed to be called from other packages. * Added and modified numerous tests to verify (hopefully) all corner cases that the decentralized treasury agenda has added.
806 lines
30 KiB
Go
806 lines
30 KiB
Go
// Copyright (c) 2014-2016 The btcsuite developers
|
|
// Copyright (c) 2015-2020 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package blockchain
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/decred/dcrd/chaincfg/chainhash"
|
|
)
|
|
|
|
// UnknownBlockError identifies an error that indicates a requested block
|
|
// does not exist.
|
|
type UnknownBlockError chainhash.Hash
|
|
|
|
// Error returns the error as a human-readable string and satisfies the error
|
|
// interface.
|
|
func (e UnknownBlockError) Error() string {
|
|
return fmt.Sprintf("block %s is not known", chainhash.Hash(e))
|
|
}
|
|
|
|
// VoteVersionError identifies an error that indicates a vote version was
|
|
// specified that does not exist.
|
|
type VoteVersionError uint32
|
|
|
|
// Error returns the assertion error as a human-readable string and satisfies
|
|
// the error interface.
|
|
func (e VoteVersionError) Error() string {
|
|
return fmt.Sprintf("stake version %v does not exist", uint32(e))
|
|
}
|
|
|
|
// HashError identifies an error that indicates a hash was specified that does
|
|
// not exist.
|
|
type HashError string
|
|
|
|
// Error returns the error as a human-readable string and satisfies the error
|
|
// interface.
|
|
func (e HashError) Error() string {
|
|
return fmt.Sprintf("hash %v does not exist", string(e))
|
|
}
|
|
|
|
// DeploymentError identifies an error that indicates a deployment ID was
|
|
// specified that does not exist.
|
|
type DeploymentError string
|
|
|
|
// Error returns the assertion error as a human-readable string and satisfies
|
|
// the error interface.
|
|
func (e DeploymentError) Error() string {
|
|
return fmt.Sprintf("deployment ID %v does not exist", string(e))
|
|
}
|
|
|
|
// DuplicateDeploymentError identifies an error that indicates a duplicate
|
|
// deployment ID was specified in the network parameter deployment definitions.
|
|
type DuplicateDeploymentError string
|
|
|
|
// Error returns the assertion error as a human-readable string and satisfies
|
|
// the error interface.
|
|
func (e DuplicateDeploymentError) Error() string {
|
|
return fmt.Sprintf("deployment ID %v exists in more than one deployment",
|
|
string(e))
|
|
}
|
|
|
|
// NoFilterError identifies an error that indicates a filter for a given block
|
|
// hash does not exist.
|
|
type NoFilterError string
|
|
|
|
// Error returns the error as a human-readable string and satisfies the error
|
|
// interface.
|
|
func (e NoFilterError) Error() string {
|
|
return fmt.Sprintf("no filter available for block %s", string(e))
|
|
}
|
|
|
|
// NoTreasuryError identifies an error that indicates the treasury balance for a
|
|
// given block hash does not exist.
|
|
type NoTreasuryError string
|
|
|
|
// Error returns the error as a human-readable string and satisfies the error
|
|
// interface.
|
|
func (e NoTreasuryError) Error() string {
|
|
return fmt.Sprintf("treasury balance not available for block %s", string(e))
|
|
}
|
|
|
|
// AssertError identifies an error that indicates an internal code consistency
|
|
// issue and should be treated as a critical and unrecoverable error.
|
|
type AssertError string
|
|
|
|
// Error returns the assertion error as a huma-readable string and satisfies
|
|
// the error interface.
|
|
func (e AssertError) Error() string {
|
|
return "assertion failed: " + string(e)
|
|
}
|
|
|
|
// ErrorCode identifies a kind of error.
|
|
type ErrorCode int
|
|
|
|
// These constants are used to identify a specific RuleError.
|
|
const (
|
|
// ErrDuplicateBlock indicates a block with the same hash already
|
|
// exists.
|
|
ErrDuplicateBlock ErrorCode = iota
|
|
|
|
// ErrMissingParent indicates that the block was an orphan.
|
|
ErrMissingParent
|
|
|
|
// ErrBlockTooBig indicates the serialized block size exceeds the
|
|
// maximum allowed size.
|
|
ErrBlockTooBig
|
|
|
|
// ErrWrongBlockSize indicates that the block size in the header is not
|
|
// the actual serialized size of the block.
|
|
ErrWrongBlockSize
|
|
|
|
// 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
|
|
|
|
// ErrBadStakeVersionindicates the block version is too old and is no
|
|
// longer accepted since the majority of the network has upgraded to a
|
|
// newer version.
|
|
ErrBadStakeVersion
|
|
|
|
// ErrInvalidTime indicates the time in the passed block has a precision
|
|
// that is more than one second. The chain consensus rules require
|
|
// timestamps to have a maximum precision of one second.
|
|
ErrInvalidTime
|
|
|
|
// ErrTimeTooOld indicates the time is either before the median time of
|
|
// the last several blocks per the chain consensus rules or prior to the
|
|
// most recent checkpoint.
|
|
ErrTimeTooOld
|
|
|
|
// ErrTimeTooNew indicates the time is too far in the future as compared
|
|
// the current time.
|
|
ErrTimeTooNew
|
|
|
|
// ErrDifficultyTooLow indicates the difficulty for the block is lower
|
|
// than the difficulty required by the most recent checkpoint.
|
|
ErrDifficultyTooLow
|
|
|
|
// ErrUnexpectedDifficulty indicates specified bits do not align with
|
|
// the expected value either because it doesn't match the calculated
|
|
// value based on difficulty regarding the rules or it is out of the
|
|
// valid range.
|
|
ErrUnexpectedDifficulty
|
|
|
|
// ErrHighHash indicates the block does not hash to a value which is
|
|
// lower than the required target difficultly.
|
|
ErrHighHash
|
|
|
|
// ErrBadMerkleRoot indicates the calculated merkle root does not match
|
|
// the expected value.
|
|
ErrBadMerkleRoot
|
|
|
|
// ErrBadCommitmentRoot indicates the calculated commitment root does
|
|
// not match the expected value.
|
|
ErrBadCommitmentRoot
|
|
|
|
// ErrBadCheckpoint indicates a block that is expected to be at a
|
|
// checkpoint height does not match the expected one.
|
|
ErrBadCheckpoint
|
|
|
|
// ErrForkTooOld indicates a block is attempting to fork the block chain
|
|
// before the most recent checkpoint.
|
|
ErrForkTooOld
|
|
|
|
// ErrCheckpointTimeTooOld indicates a block has a timestamp before the
|
|
// most recent checkpoint.
|
|
ErrCheckpointTimeTooOld
|
|
|
|
// ErrNoTransactions indicates the block does not have a least one
|
|
// transaction. A valid block must have at least the coinbase
|
|
// transaction.
|
|
ErrNoTransactions
|
|
|
|
// ErrTooManyTransactions indicates the block has more transactions than
|
|
// are allowed.
|
|
ErrTooManyTransactions
|
|
|
|
// ErrNoTxInputs indicates a transaction does not have any inputs. A
|
|
// valid transaction must have at least one input.
|
|
ErrNoTxInputs
|
|
|
|
// ErrNoTxOutputs indicates a transaction does not have any outputs. A
|
|
// valid transaction must have at least one output.
|
|
ErrNoTxOutputs
|
|
|
|
// ErrInvalidTxOutputs indicates a transaction does not have the exact
|
|
// number of outputs.
|
|
ErrInvalidTxOutputs
|
|
|
|
// ErrTxTooBig indicates a transaction exceeds the maximum allowed size
|
|
// when serialized.
|
|
ErrTxTooBig
|
|
|
|
// ErrBadTxOutValue indicates an output value for a transaction is
|
|
// invalid in some way such as being out of range.
|
|
ErrBadTxOutValue
|
|
|
|
// ErrDuplicateTxInputs indicates a transaction references the same
|
|
// input more than once.
|
|
ErrDuplicateTxInputs
|
|
|
|
// ErrBadTxInput indicates a transaction input is invalid in some way
|
|
// such as referencing a previous transaction outpoint which is out of
|
|
// range or not referencing one at all.
|
|
ErrBadTxInput
|
|
|
|
// ErrMissingTxOut indicates a transaction output referenced by an input
|
|
// either does not exist or has already been spent.
|
|
ErrMissingTxOut
|
|
|
|
// ErrUnfinalizedTx indicates a transaction has not been finalized.
|
|
// A valid block may only contain finalized transactions.
|
|
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
|
|
|
|
// ErrOverwriteTx indicates a block contains a transaction that has
|
|
// the same hash as a previous transaction which has not been fully
|
|
// spent.
|
|
ErrOverwriteTx
|
|
|
|
// ErrImmatureSpend indicates a transaction is attempting to spend a
|
|
// coinbase that has not yet reached the required maturity.
|
|
ErrImmatureSpend
|
|
|
|
// ErrSpendTooHigh indicates a transaction is attempting to spend more
|
|
// value than the sum of all of its inputs.
|
|
ErrSpendTooHigh
|
|
|
|
// ErrBadFees indicates the total fees for a block are invalid due to
|
|
// exceeding the maximum possible value.
|
|
ErrBadFees
|
|
|
|
// ErrTooManySigOps indicates the total number of signature operations
|
|
// for a transaction or block exceed the maximum allowed limits.
|
|
ErrTooManySigOps
|
|
|
|
// ErrFirstTxNotCoinbase indicates the first transaction in a block
|
|
// is not a coinbase transaction.
|
|
ErrFirstTxNotCoinbase
|
|
|
|
// ErrFirstTxNotOpReturn indicates the first transaction in a block
|
|
// is not an OP_RETURN.
|
|
ErrFirstTxNotOpReturn
|
|
|
|
// ErrCoinbaseHeight indicates that the encoded height in the coinbase
|
|
// is incorrect.
|
|
ErrCoinbaseHeight
|
|
|
|
// ErrMultipleCoinbases indicates a block contains more than one
|
|
// coinbase transaction.
|
|
ErrMultipleCoinbases
|
|
|
|
// ErrStakeTxInRegularTree indicates a stake transaction was found in
|
|
// the regular transaction tree.
|
|
ErrStakeTxInRegularTree
|
|
|
|
// ErrRegTxInStakeTree indicates that a regular transaction was found in
|
|
// the stake transaction tree.
|
|
ErrRegTxInStakeTree
|
|
|
|
// ErrBadCoinbaseScriptLen indicates the length of the signature script
|
|
// for a coinbase transaction is not within the valid range.
|
|
ErrBadCoinbaseScriptLen
|
|
|
|
// ErrBadCoinbaseValue indicates the amount of a coinbase value does
|
|
// not match the expected value of the subsidy plus the sum of all fees.
|
|
ErrBadCoinbaseValue
|
|
|
|
// ErrBadCoinbaseOutpoint indicates that the outpoint used by a coinbase
|
|
// as input was non-null.
|
|
ErrBadCoinbaseOutpoint
|
|
|
|
// ErrBadCoinbaseFraudProof indicates that the fraud proof for a coinbase
|
|
// input was non-null.
|
|
ErrBadCoinbaseFraudProof
|
|
|
|
// ErrBadCoinbaseAmountIn indicates that the AmountIn (=subsidy) for a
|
|
// coinbase input was incorrect.
|
|
ErrBadCoinbaseAmountIn
|
|
|
|
// ErrBadStakebaseAmountIn indicates that the AmountIn (=subsidy) for a
|
|
// stakebase input was incorrect.
|
|
ErrBadStakebaseAmountIn
|
|
|
|
// ErrBadStakebaseScriptLen indicates the length of the signature script
|
|
// for a stakebase transaction is not within the valid range.
|
|
ErrBadStakebaseScriptLen
|
|
|
|
// ErrBadStakebaseScrVal indicates the signature script for a stakebase
|
|
// transaction was not set to the network consensus value.
|
|
ErrBadStakebaseScrVal
|
|
|
|
// 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
|
|
|
|
// 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
|
|
|
|
// ErrNotEnoughStake indicates that there was for some SStx in a given block,
|
|
// the given SStx did not have enough stake to meet the network target.
|
|
ErrNotEnoughStake
|
|
|
|
// ErrStakeBelowMinimum indicates that for some SStx in a given block,
|
|
// the given SStx had an amount of stake below the minimum network target.
|
|
ErrStakeBelowMinimum
|
|
|
|
// ErrNonstandardStakeTx indicates that a block contained a stake tx that
|
|
// was not one of the allowed types of a stake transactions.
|
|
ErrNonstandardStakeTx
|
|
|
|
// ErrNotEnoughVotes indicates that a block contained less than a majority
|
|
// of voters.
|
|
ErrNotEnoughVotes
|
|
|
|
// ErrTooManyVotes indicates that a block contained more than the maximum
|
|
// allowable number of votes.
|
|
ErrTooManyVotes
|
|
|
|
// ErrFreshStakeMismatch indicates that a block's header contained a different
|
|
// number of SStx as compared to what was found in the block.
|
|
ErrFreshStakeMismatch
|
|
|
|
// ErrTooManySStxs indicates that more than the allowed number of SStx was
|
|
// found in a block.
|
|
ErrTooManySStxs
|
|
|
|
// ErrInvalidEarlyStakeTx indicates that a tx type other than SStx was found
|
|
// in the stake tx tree before the period when stake validation begins, or
|
|
// before the stake tx type could possibly be included in the block.
|
|
ErrInvalidEarlyStakeTx
|
|
|
|
// ErrTicketUnavailable indicates that a vote in the block spent a ticket
|
|
// that could not be found.
|
|
ErrTicketUnavailable
|
|
|
|
// ErrVotesOnWrongBlock indicates that an SSGen voted on a block not the
|
|
// block's parent, and so was ineligible for inclusion into that block.
|
|
ErrVotesOnWrongBlock
|
|
|
|
// ErrVotesMismatch indicates that the number of SSGen in the block was not
|
|
// equivalent to the number of votes provided in the block header.
|
|
ErrVotesMismatch
|
|
|
|
// ErrIncongruentVotebit indicates that the first votebit in votebits was not
|
|
// the same as that determined by the majority of voters in the SSGen tx
|
|
// included in the block.
|
|
ErrIncongruentVotebit
|
|
|
|
// ErrInvalidSSRtx indicates than an SSRtx in a block could not be found to
|
|
// have a valid missed sstx input as per the stake ticket database.
|
|
ErrInvalidSSRtx
|
|
|
|
// ErrInvalidRevNum indicates that the number of revocations from the
|
|
// header was not the same as the number of SSRtx included in the block.
|
|
ErrRevocationsMismatch
|
|
|
|
// ErrTooManyRevocations indicates more revocations were found in a block
|
|
// than were allowed.
|
|
ErrTooManyRevocations
|
|
|
|
// ErrTicketCommitment indicates that a ticket commitment contains an amount
|
|
// that does not coincide with the associated ticket input amount.
|
|
ErrTicketCommitment
|
|
|
|
// ErrInvalidVoteInput indicates that an input to a vote transaction is
|
|
// either not a stake ticket submission or is not a supported version.
|
|
ErrInvalidVoteInput
|
|
|
|
// ErrBadNumPayees indicates that either a vote or revocation transaction
|
|
// does not make the correct number of payments per the associated ticket
|
|
// commitments.
|
|
ErrBadNumPayees
|
|
|
|
// ErrBadPayeeScriptVersion indicates that either a vote or revocation
|
|
// transaction output that corresponds to a ticket commitment does not use
|
|
// a supported script version.
|
|
ErrBadPayeeScriptVersion
|
|
|
|
// ErrBadPayeeScriptType indicates that either a vote or revocation
|
|
// transaction output that corresponds to a ticket commitment does not pay
|
|
// to the same script type required by the commitment.
|
|
ErrBadPayeeScriptType
|
|
|
|
// ErrBadPayeeScriptType indicates that either a vote or revocation
|
|
// transaction output that corresponds to a ticket commitment does not pay
|
|
// to the hash required by the commitment.
|
|
ErrMismatchedPayeeHash
|
|
|
|
// ErrBadPayeeValue indicates that either a vote or revocation transaction
|
|
// output that corresponds to a ticket commitment does not pay the expected
|
|
// amount required by the commitment.
|
|
ErrBadPayeeValue
|
|
|
|
// ErrSSGenSubsidy indicates that there was an error in the amount of subsidy
|
|
// generated in the vote.
|
|
ErrSSGenSubsidy
|
|
|
|
// ErrImmatureTicketSpend indicates that a vote or revocation is attempting
|
|
// to spend a ticket submission output that has not yet reached the required
|
|
// maturity.
|
|
ErrImmatureTicketSpend
|
|
|
|
// ErrTicketInputScript indicates that a ticket input is not one of the
|
|
// supported script forms or versions.
|
|
ErrTicketInputScript
|
|
|
|
// ErrInvalidRevokeInput indicates that an input to a revocation transaction
|
|
// is either not a stake ticket submission or is not a supported version.
|
|
ErrInvalidRevokeInput
|
|
|
|
// ErrSSRtxPayees indicates that the SSRtx failed to pay out to the committed
|
|
// addresses or amounts from the originating SStx.
|
|
ErrSSRtxPayees
|
|
|
|
// ErrTxSStxOutSpend indicates that a non SSGen or SSRtx tx attempted to spend
|
|
// an OP_SSTX tagged output from an SStx.
|
|
ErrTxSStxOutSpend
|
|
|
|
// ErrRegTxCreateStakeOut indicates that a regular tx attempted to create
|
|
// a stake tagged output.
|
|
ErrRegTxCreateStakeOut
|
|
|
|
// ErrInvalidFinalState indicates that the final state of the PRNG included
|
|
// in the block differed from the calculated final state.
|
|
ErrInvalidFinalState
|
|
|
|
// ErrPoolSize indicates an error in the ticket pool size for this block.
|
|
ErrPoolSize
|
|
|
|
// ErrForceReorgWrongChain indicates that a reroganization was attempted
|
|
// to be forced, but the chain indicated was not mirrored by b.bestChain.
|
|
ErrForceReorgWrongChain
|
|
|
|
// ErrForceReorgMissingChild indicates that a reroganization was attempted
|
|
// to be forced, but the child node to reorganize to could not be found.
|
|
ErrForceReorgMissingChild
|
|
|
|
// ErrBadStakebaseValue indicates that a block's stake tx tree has spent
|
|
// more than it is allowed.
|
|
ErrBadStakebaseValue
|
|
|
|
// ErrDiscordantTxTree specifies that a given origin tx's content
|
|
// indicated that it should exist in a different tx tree than the
|
|
// one given in the TxIn outpoint.
|
|
ErrDiscordantTxTree
|
|
|
|
// ErrStakeFees indicates an error with the fees found in the stake
|
|
// transaction tree.
|
|
ErrStakeFees
|
|
|
|
// ErrNoStakeTx indicates there were no stake transactions found in a
|
|
// block after stake validation height.
|
|
ErrNoStakeTx
|
|
|
|
// ErrBadBlockHeight indicates that a block header's embedded block height
|
|
// was different from where it was actually embedded in the block chain.
|
|
ErrBadBlockHeight
|
|
|
|
// ErrBlockOneTx indicates that block height 1 failed to correct generate
|
|
// the block one initial payout transaction.
|
|
ErrBlockOneTx
|
|
|
|
// ErrBlockOneTx indicates that block height 1 coinbase transaction in
|
|
// zero was incorrect in some way.
|
|
ErrBlockOneInputs
|
|
|
|
// ErrBlockOneOutputs indicates that block height 1 failed to incorporate
|
|
// the ledger addresses correctly into the transaction's outputs.
|
|
ErrBlockOneOutputs
|
|
|
|
// ErrNoTax indicates that there was no tax present in the coinbase of a
|
|
// block after height 1.
|
|
ErrNoTax
|
|
|
|
// ErrExpiredTx indicates that the transaction is currently expired.
|
|
ErrExpiredTx
|
|
|
|
// ErrExpiryTxSpentEarly indicates that an output from a transaction
|
|
// that included an expiry field was spent before coinbase maturity
|
|
// many blocks had passed in the blockchain.
|
|
ErrExpiryTxSpentEarly
|
|
|
|
// ErrFraudAmountIn indicates the witness amount given was fraudulent.
|
|
ErrFraudAmountIn
|
|
|
|
// ErrFraudBlockHeight indicates the witness block height given was
|
|
// fraudulent.
|
|
ErrFraudBlockHeight
|
|
|
|
// ErrFraudBlockIndex indicates the witness block index given was
|
|
// fraudulent.
|
|
ErrFraudBlockIndex
|
|
|
|
// ErrZeroValueOutputSpend indicates that a transaction attempted to spend a
|
|
// zero value output.
|
|
ErrZeroValueOutputSpend
|
|
|
|
// ErrInvalidEarlyVoteBits indicates that a block before stake validation
|
|
// height had an unallowed vote bits value.
|
|
ErrInvalidEarlyVoteBits
|
|
|
|
// ErrInvalidEarlyFinalState indicates that a block before stake validation
|
|
// height had a non-zero final state.
|
|
ErrInvalidEarlyFinalState
|
|
|
|
// ErrKnownInvalidBlock indicates that this block has previously failed
|
|
// validation.
|
|
ErrKnownInvalidBlock
|
|
|
|
// ErrInvalidAncestorBlock indicates that an ancestor of this block has
|
|
// failed validation.
|
|
ErrInvalidAncestorBlock
|
|
|
|
// ErrInvalidTemplateParent indicates that a block template builds on a
|
|
// block that is either not the current best chain tip or its parent.
|
|
ErrInvalidTemplateParent
|
|
|
|
// ErrUnknownPiKey indicates that the provided public Pi Key is not
|
|
// a well known key.
|
|
ErrUnknownPiKey
|
|
|
|
// ErrInvalidPiSignature indicates that a treasury spend transaction
|
|
// was not properly signed.
|
|
ErrInvalidPiSignature
|
|
|
|
// ErrInvalidTVoteWindow indicates that a treasury spend transaction
|
|
// appeared in a block that is prior to a valid treasury vote window.
|
|
ErrInvalidTVoteWindow
|
|
|
|
// ErrNotTVI indicates that a treasury spend transaction appeared in a
|
|
// block that is not at a TVI interval.
|
|
ErrNotTVI
|
|
|
|
// ErrInvalidTSpendWindow indicates that this treasury spend
|
|
// transaction is outside of the allowed window.
|
|
ErrInvalidTSpendWindow
|
|
|
|
// ErrNotEnoughTSpendVotes indicates that a treasury spend transaction
|
|
// does not have enough votes to be included in block.
|
|
ErrNotEnoughTSpendVotes
|
|
|
|
// ErrInvalidTSpendValueIn indicates that a treasury spend transaction
|
|
// ValueIn does not match the encoded copy in the first TxOut.
|
|
ErrInvalidTSpendValueIn
|
|
|
|
// ErrTSpendExists indicates that a duplicate treasury spend
|
|
// transaction has been mined on a TVI in the current best chain.
|
|
ErrTSpendExists
|
|
|
|
// ErrInvalidExpenditure indicates that a treasury spend transaction
|
|
// expenditure is out of range.
|
|
ErrInvalidExpenditure
|
|
|
|
// ErrFirstTxNotTreasurybase indicates the first transaction in a block
|
|
// is not a treasurybase transaction.
|
|
ErrFirstTxNotTreasurybase
|
|
|
|
// ErrBadTreasurybaseOutpoint indicates that the outpoint used by a
|
|
// treasurybase as input was non-null.
|
|
ErrBadTreasurybaseOutpoint
|
|
|
|
// ErrBadTreasurybaseFraudProof indicates that the fraud proof for a
|
|
// treasurybase input was non-null.
|
|
ErrBadTreasurybaseFraudProof
|
|
|
|
// ErrBadTreasurybaseScriptLen indicates the length of the signature script
|
|
// for a treasurybase transaction is not within the valid range.
|
|
ErrBadTreasurybaseScriptLen
|
|
|
|
// ErrTreasurybaseTxNotOpReturn indicates the second ouptut of a
|
|
// treasury base transaction is not an OP_RETURN.
|
|
ErrTreasurybaseTxNotOpReturn
|
|
|
|
// ErrTreasurybaseHeight indicates that the encoded height in the
|
|
// treasurybase is incorrect.
|
|
ErrTreasurybaseHeight
|
|
|
|
// ErrInvalidTreasurybaseTxOutputs indicates that the transaction does
|
|
// not have the correct number of outputs.
|
|
ErrInvalidTreasurybaseTxOutputs
|
|
|
|
// ErrInvalidTreasurybaseVersion indicates that the transaction output
|
|
// has the wrong version.
|
|
ErrInvalidTreasurybaseVersion
|
|
|
|
// ErrInvalidTreasurybaseScript indicates that the transaction output
|
|
// script is invalid.
|
|
ErrInvalidTreasurybaseScript
|
|
|
|
// ErrTreasurybaseOutValue ensures that the OP_TADD value of a
|
|
// treasurybase is not the expected amount.
|
|
ErrTreasurybaseOutValue
|
|
|
|
// ErrMultipleTreasurybases indicates a block contains more than one
|
|
// treasurybase transaction.
|
|
ErrMultipleTreasurybases
|
|
|
|
// ErrBadTreasurybaseAmountIn indicates that a block contains an
|
|
// invalid treasury contribution.
|
|
ErrBadTreasurybaseAmountIn
|
|
|
|
// ErrBadTSpendOutpoint indicates that the outpoint used by a
|
|
// treasury spend as input was non-null.
|
|
ErrBadTSpendOutpoint
|
|
|
|
// ErrBadTSpendFraudProof indicates that the fraud proof for a treasury
|
|
// spend transaction input was non-null.
|
|
ErrBadTSpendFraudProof
|
|
|
|
// ErrBadTSpendScriptLen indicates the length of the signature script
|
|
// for a treasury spend transaction is not within the valid range.
|
|
ErrBadTSpendScriptLen
|
|
|
|
// ErrInvalidTAddChange indicates the change output of a TAdd is zero.
|
|
ErrInvalidTAddChange
|
|
|
|
// ErrTooManyTAdds indicates the number of treasury adds in a given
|
|
// block is larger than the maximum allowed.
|
|
ErrTooManyTAdds
|
|
|
|
// numErrorCodes is the maximum error code number used in tests.
|
|
numErrorCodes
|
|
)
|
|
|
|
// Map of ErrorCode values back to their constant names for pretty printing.
|
|
var errorCodeStrings = map[ErrorCode]string{
|
|
ErrDuplicateBlock: "ErrDuplicateBlock",
|
|
ErrMissingParent: "ErrMissingParent",
|
|
ErrBlockTooBig: "ErrBlockTooBig",
|
|
ErrWrongBlockSize: "ErrWrongBlockSize",
|
|
ErrBlockVersionTooOld: "ErrBlockVersionTooOld",
|
|
ErrBadStakeVersion: "ErrBadStakeVersion",
|
|
ErrInvalidTime: "ErrInvalidTime",
|
|
ErrTimeTooOld: "ErrTimeTooOld",
|
|
ErrTimeTooNew: "ErrTimeTooNew",
|
|
ErrDifficultyTooLow: "ErrDifficultyTooLow",
|
|
ErrUnexpectedDifficulty: "ErrUnexpectedDifficulty",
|
|
ErrHighHash: "ErrHighHash",
|
|
ErrBadMerkleRoot: "ErrBadMerkleRoot",
|
|
ErrBadCommitmentRoot: "ErrBadCommitmentRoot",
|
|
ErrBadCheckpoint: "ErrBadCheckpoint",
|
|
ErrForkTooOld: "ErrForkTooOld",
|
|
ErrCheckpointTimeTooOld: "ErrCheckpointTimeTooOld",
|
|
ErrNoTransactions: "ErrNoTransactions",
|
|
ErrTooManyTransactions: "ErrTooManyTransactions",
|
|
ErrNoTxInputs: "ErrNoTxInputs",
|
|
ErrNoTxOutputs: "ErrNoTxOutputs",
|
|
ErrInvalidTxOutputs: "ErrInvalidTxOutputs",
|
|
ErrTxTooBig: "ErrTxTooBig",
|
|
ErrBadTxOutValue: "ErrBadTxOutValue",
|
|
ErrDuplicateTxInputs: "ErrDuplicateTxInputs",
|
|
ErrBadTxInput: "ErrBadTxInput",
|
|
ErrMissingTxOut: "ErrMissingTxOut",
|
|
ErrUnfinalizedTx: "ErrUnfinalizedTx",
|
|
ErrDuplicateTx: "ErrDuplicateTx",
|
|
ErrOverwriteTx: "ErrOverwriteTx",
|
|
ErrImmatureSpend: "ErrImmatureSpend",
|
|
ErrSpendTooHigh: "ErrSpendTooHigh",
|
|
ErrBadFees: "ErrBadFees",
|
|
ErrTooManySigOps: "ErrTooManySigOps",
|
|
ErrFirstTxNotCoinbase: "ErrFirstTxNotCoinbase",
|
|
ErrFirstTxNotOpReturn: "ErrFirstTxNotOpReturn",
|
|
ErrCoinbaseHeight: "ErrCoinbaseHeight",
|
|
ErrMultipleCoinbases: "ErrMultipleCoinbases",
|
|
ErrStakeTxInRegularTree: "ErrStakeTxInRegularTree",
|
|
ErrRegTxInStakeTree: "ErrRegTxInStakeTree",
|
|
ErrBadCoinbaseScriptLen: "ErrBadCoinbaseScriptLen",
|
|
ErrBadCoinbaseValue: "ErrBadCoinbaseValue",
|
|
ErrBadCoinbaseOutpoint: "ErrBadCoinbaseOutpoint",
|
|
ErrBadCoinbaseFraudProof: "ErrBadCoinbaseFraudProof",
|
|
ErrBadCoinbaseAmountIn: "ErrBadCoinbaseAmountIn",
|
|
ErrBadStakebaseAmountIn: "ErrBadStakebaseAmountIn",
|
|
ErrBadStakebaseScriptLen: "ErrBadStakebaseScriptLen",
|
|
ErrBadStakebaseScrVal: "ErrBadStakebaseScrVal",
|
|
ErrScriptMalformed: "ErrScriptMalformed",
|
|
ErrScriptValidation: "ErrScriptValidation",
|
|
ErrNotEnoughStake: "ErrNotEnoughStake",
|
|
ErrStakeBelowMinimum: "ErrStakeBelowMinimum",
|
|
ErrNonstandardStakeTx: "ErrNonstandardStakeTx",
|
|
ErrNotEnoughVotes: "ErrNotEnoughVotes",
|
|
ErrTooManyVotes: "ErrTooManyVotes",
|
|
ErrFreshStakeMismatch: "ErrFreshStakeMismatch",
|
|
ErrTooManySStxs: "ErrTooManySStxs",
|
|
ErrInvalidEarlyStakeTx: "ErrInvalidEarlyStakeTx",
|
|
ErrTicketUnavailable: "ErrTicketUnavailable",
|
|
ErrVotesOnWrongBlock: "ErrVotesOnWrongBlock",
|
|
ErrVotesMismatch: "ErrVotesMismatch",
|
|
ErrIncongruentVotebit: "ErrIncongruentVotebit",
|
|
ErrInvalidSSRtx: "ErrInvalidSSRtx",
|
|
ErrRevocationsMismatch: "ErrRevocationsMismatch",
|
|
ErrTooManyRevocations: "ErrTooManyRevocations",
|
|
ErrTicketCommitment: "ErrTicketCommitment",
|
|
ErrInvalidVoteInput: "ErrInvalidVoteInput",
|
|
ErrBadNumPayees: "ErrBadNumPayees",
|
|
ErrBadPayeeScriptVersion: "ErrBadPayeeScriptVersion",
|
|
ErrBadPayeeScriptType: "ErrBadPayeeScriptType",
|
|
ErrMismatchedPayeeHash: "ErrMismatchedPayeeHash",
|
|
ErrBadPayeeValue: "ErrBadPayeeValue",
|
|
ErrSSGenSubsidy: "ErrSSGenSubsidy",
|
|
ErrImmatureTicketSpend: "ErrImmatureTicketSpend",
|
|
ErrTicketInputScript: "ErrTicketInputScript",
|
|
ErrInvalidRevokeInput: "ErrInvalidRevokeInput",
|
|
ErrSSRtxPayees: "ErrSSRtxPayees",
|
|
ErrTxSStxOutSpend: "ErrTxSStxOutSpend",
|
|
ErrRegTxCreateStakeOut: "ErrRegTxCreateStakeOut",
|
|
ErrInvalidFinalState: "ErrInvalidFinalState",
|
|
ErrPoolSize: "ErrPoolSize",
|
|
ErrForceReorgWrongChain: "ErrForceReorgWrongChain",
|
|
ErrForceReorgMissingChild: "ErrForceReorgMissingChild",
|
|
ErrBadStakebaseValue: "ErrBadStakebaseValue",
|
|
ErrDiscordantTxTree: "ErrDiscordantTxTree",
|
|
ErrStakeFees: "ErrStakeFees",
|
|
ErrNoStakeTx: "ErrNoStakeTx",
|
|
ErrBadBlockHeight: "ErrBadBlockHeight",
|
|
ErrBlockOneTx: "ErrBlockOneTx",
|
|
ErrBlockOneInputs: "ErrBlockOneInputs",
|
|
ErrBlockOneOutputs: "ErrBlockOneOutputs",
|
|
ErrNoTax: "ErrNoTax",
|
|
ErrExpiredTx: "ErrExpiredTx",
|
|
ErrExpiryTxSpentEarly: "ErrExpiryTxSpentEarly",
|
|
ErrFraudAmountIn: "ErrFraudAmountIn",
|
|
ErrFraudBlockHeight: "ErrFraudBlockHeight",
|
|
ErrFraudBlockIndex: "ErrFraudBlockIndex",
|
|
ErrZeroValueOutputSpend: "ErrZeroValueOutputSpend",
|
|
ErrInvalidEarlyVoteBits: "ErrInvalidEarlyVoteBits",
|
|
ErrInvalidEarlyFinalState: "ErrInvalidEarlyFinalState",
|
|
ErrKnownInvalidBlock: "ErrKnownInvalidBlock",
|
|
ErrInvalidAncestorBlock: "ErrInvalidAncestorBlock",
|
|
ErrUnknownPiKey: "ErrUnknownPiKey",
|
|
ErrInvalidPiSignature: "ErrInvalidPiSignature",
|
|
ErrInvalidTVoteWindow: "ErrInvalidTVoteWindow",
|
|
ErrNotTVI: "ErrNotTVI",
|
|
ErrInvalidTSpendWindow: "ErrInvalidTSpendWindow",
|
|
ErrNotEnoughTSpendVotes: "ErrNotEnoughTSpendVotes",
|
|
ErrInvalidTSpendValueIn: "ErrInvalidTSpendValueIn",
|
|
ErrTSpendExists: "ErrTSpendExists",
|
|
ErrInvalidExpenditure: "ErrInvalidExpenditure",
|
|
ErrFirstTxNotTreasurybase: "ErrFirstTxNotTreasurybase",
|
|
ErrBadTreasurybaseOutpoint: "ErrBadTreasurybaseOutpoint",
|
|
ErrBadTreasurybaseFraudProof: "ErrBadTreasurybaseFraudProof",
|
|
ErrBadTreasurybaseScriptLen: "ErrBadTreasurybaseScriptLen",
|
|
ErrTreasurybaseTxNotOpReturn: "ErrTreasurybaseTxNotOpReturn",
|
|
ErrTreasurybaseHeight: "ErrTreasurybaseHeight",
|
|
ErrTreasurybaseOutValue: "ErrTreasurybaseOutValue",
|
|
ErrInvalidTreasurybaseTxOutputs: "ErrInvalidTreasurybaseTxOutputs",
|
|
ErrInvalidTreasurybaseVersion: "ErrInvalidTreasurybaseVersion",
|
|
ErrInvalidTreasurybaseScript: "ErrInvalidTreasurybaseScript",
|
|
ErrMultipleTreasurybases: "ErrMultipleTreasurybases",
|
|
ErrBadTreasurybaseAmountIn: "ErrBadTreasurybaseAmountIn",
|
|
ErrBadTSpendOutpoint: "ErrBadTSpendOutpoint",
|
|
ErrBadTSpendFraudProof: "ErrBadTSpendFraudProof",
|
|
ErrBadTSpendScriptLen: "ErrBadTSpendScriptLen",
|
|
ErrInvalidTemplateParent: "ErrInvalidTemplateParent",
|
|
ErrInvalidTAddChange: "ErrInvalidTAddChange",
|
|
ErrTooManyTAdds: "ErrTooManyTAdds",
|
|
}
|
|
|
|
// String returns the ErrorCode as a human-readable name.
|
|
func (e ErrorCode) String() string {
|
|
if s := errorCodeStrings[e]; s != "" {
|
|
return s
|
|
}
|
|
return fmt.Sprintf("Unknown ErrorCode (%d)", int(e))
|
|
}
|
|
|
|
// 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 and access the ErrorCode field to
|
|
// ascertain the specific reason for the rule violation.
|
|
type RuleError struct {
|
|
ErrorCode ErrorCode // Describes the kind of error
|
|
Description string // Human readable description of the issue
|
|
}
|
|
|
|
// Error satisfies the error interface and prints human-readable errors.
|
|
func (e RuleError) Error() string {
|
|
return e.Description
|
|
}
|
|
|
|
// ruleError creates a RuleError given a set of arguments.
|
|
func ruleError(c ErrorCode, desc string) RuleError {
|
|
return RuleError{ErrorCode: c, Description: desc}
|
|
}
|
|
|
|
// IsErrorCode returns whether or not the provided error is a rule error with
|
|
// the provided error code.
|
|
func IsErrorCode(err error, c ErrorCode) bool {
|
|
var e RuleError
|
|
return errors.As(err, &e) && e.ErrorCode == c
|
|
}
|