multi: Check tx inputs auto revocations flag.
This adds an isAutoRevocationsEnabled boolean to checkTicketRedeemerCommitments and updates all callers accordingly. This is necessary because additional validation rules will be added in subsequent commits based on whether the automatic ticket revocations agenda is active. Note that this is intentionally not using blockchain.AgendaFlags, and is instead adding an additional boolean parameter, since we should be able to retroactively update the transaction checks to be based on just the transaction version if the agenda passes and there are no legacy violations (i.e., version 2 revocation transactions prior to the agenda passing), in which case this boolean parameter could be removed.
This commit is contained in:
parent
170ba4fc99
commit
70edb35d0d
@ -2245,7 +2245,10 @@ func checkTicketSubmissionInput(ticketUtxo *UtxoEntry) error {
|
||||
//
|
||||
// NOTE: This is only intended to be a helper to refactor out common code from
|
||||
// checkVoteInputs and checkRevocationInputs.
|
||||
func checkTicketRedeemerCommitments(ticketHash *chainhash.Hash, ticketOuts []*stake.MinimalOutput, msgTx *wire.MsgTx, isVote bool, voteSubsidy int64, isTreasuryEnabled bool) error {
|
||||
func checkTicketRedeemerCommitments(ticketHash *chainhash.Hash,
|
||||
ticketOuts []*stake.MinimalOutput, msgTx *wire.MsgTx, isVote bool,
|
||||
voteSubsidy int64, isTreasuryEnabled, isAutoRevocationsEnabled bool) error {
|
||||
|
||||
// Make an initial pass over the ticket commitments to calculate the overall
|
||||
// contribution sum. This is necessary because the output amounts are
|
||||
// required to be scaled to maintain the same proportions as the original
|
||||
@ -2414,7 +2417,10 @@ func checkTicketRedeemerCommitments(ticketHash *chainhash.Hash, ticketOuts []*st
|
||||
//
|
||||
// NOTE: The caller MUST have already determined that the provided transaction
|
||||
// is a vote.
|
||||
func checkVoteInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint, params *chaincfg.Params, isTreasuryEnabled bool) error {
|
||||
func checkVoteInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx,
|
||||
txHeight int64, view *UtxoViewpoint, params *chaincfg.Params,
|
||||
isTreasuryEnabled, isAutoRevocationsEnabled bool) error {
|
||||
|
||||
ticketMaturity := int64(params.TicketMaturity)
|
||||
voteHash := tx.Hash()
|
||||
msgTx := tx.MsgTx()
|
||||
@ -2523,7 +2529,7 @@ func checkVoteInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx, txHe
|
||||
|
||||
// Ensure the outputs adhere to the ticket commitments.
|
||||
return checkTicketRedeemerCommitments(ticketHash, ticketOuts, msgTx,
|
||||
true, voteSubsidy, isTreasuryEnabled)
|
||||
true, voteSubsidy, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
}
|
||||
|
||||
// checkRevocationInputs performs a series of checks on the inputs to a
|
||||
@ -2533,7 +2539,10 @@ func checkVoteInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx, txHe
|
||||
//
|
||||
// NOTE: The caller MUST have already determined that the provided transaction
|
||||
// is a revocation.
|
||||
func checkRevocationInputs(tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint, params *chaincfg.Params, isTreasuryEnabled bool) error {
|
||||
func checkRevocationInputs(tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint,
|
||||
params *chaincfg.Params, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled bool) error {
|
||||
|
||||
ticketMaturity := int64(params.TicketMaturity)
|
||||
revokeHash := tx.Hash()
|
||||
msgTx := tx.MsgTx()
|
||||
@ -2615,7 +2624,7 @@ func checkRevocationInputs(tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint,
|
||||
// Ensure the outputs adhere to the ticket commitments. Zero is passed for
|
||||
// the vote subsidy since revocations do not produce any subsidy.
|
||||
return checkTicketRedeemerCommitments(ticketHash, ticketOuts, msgTx,
|
||||
false, 0, isTreasuryEnabled)
|
||||
false, 0, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
}
|
||||
|
||||
// CheckTransactionInputs performs a series of checks on the inputs to a
|
||||
@ -2630,7 +2639,11 @@ func checkRevocationInputs(tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint,
|
||||
//
|
||||
// NOTE: The transaction MUST have already been sanity checked with the
|
||||
// CheckTransactionSanity function prior to calling this function.
|
||||
func CheckTransactionInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint, checkFraudProof bool, chainParams *chaincfg.Params, isTreasuryEnabled bool) (int64, error) {
|
||||
func CheckTransactionInputs(subsidyCache *standalone.SubsidyCache,
|
||||
tx *dcrutil.Tx, txHeight int64, view *UtxoViewpoint, checkFraudProof bool,
|
||||
chainParams *chaincfg.Params, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled bool) (int64, error) {
|
||||
|
||||
// Coinbase transactions have no inputs.
|
||||
msgTx := tx.MsgTx()
|
||||
if standalone.IsCoinBaseTx(msgTx, isTreasuryEnabled) {
|
||||
@ -2666,7 +2679,7 @@ func CheckTransactionInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.T
|
||||
isVote := stake.IsSSGen(msgTx, isTreasuryEnabled)
|
||||
if isVote {
|
||||
err := checkVoteInputs(subsidyCache, tx, txHeight, view,
|
||||
chainParams, isTreasuryEnabled)
|
||||
chainParams, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -2681,7 +2694,7 @@ func CheckTransactionInputs(subsidyCache *standalone.SubsidyCache, tx *dcrutil.T
|
||||
isRevocation := stake.IsSSRtx(msgTx)
|
||||
if isRevocation {
|
||||
err := checkRevocationInputs(tx, txHeight, view, chainParams,
|
||||
isTreasuryEnabled)
|
||||
isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -3257,6 +3270,13 @@ func (b *BlockChain) checkTransactionsAndConnect(inputFees dcrutil.Amount, node
|
||||
return err
|
||||
}
|
||||
|
||||
// Determine if the automatic ticket revocations agenda is active as of the
|
||||
// block being checked.
|
||||
isAutoRevocationsEnabled, err := b.isAutoRevocationsAgendaActive(node.parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform several checks on the inputs for each transaction. Also
|
||||
// accumulate the total fees. This could technically be combined with
|
||||
// the loop above instead of running another loop over the
|
||||
@ -3280,7 +3300,7 @@ func (b *BlockChain) checkTransactionsAndConnect(inputFees dcrutil.Amount, node
|
||||
// spent, so be aware of this.
|
||||
txFee, err := CheckTransactionInputs(b.subsidyCache, tx,
|
||||
node.height, view, true, /* check fraud proofs */
|
||||
b.chainParams, isTreasuryEnabled)
|
||||
b.chainParams, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
log.Tracef("CheckTransactionInputs failed; error "+
|
||||
"returned: %v", err)
|
||||
|
||||
@ -1244,6 +1244,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, rateLimit,
|
||||
|
||||
// Determine active agendas based on flags.
|
||||
isTreasuryEnabled := checkTxFlags.IsTreasuryEnabled()
|
||||
isAutoRevocationsEnabled := checkTxFlags.IsAutoRevocationsEnabled()
|
||||
|
||||
// A standalone transaction must not be a coinbase transaction.
|
||||
if standalone.IsCoinBaseTx(msgTx, isTreasuryEnabled) {
|
||||
@ -1490,7 +1491,7 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, rateLimit,
|
||||
// filled in by the miner.
|
||||
txFee, err := blockchain.CheckTransactionInputs(mp.cfg.SubsidyCache,
|
||||
tx, nextBlockHeight, utxoView, false, mp.cfg.ChainParams,
|
||||
isTreasuryEnabled)
|
||||
isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
var cerr blockchain.RuleError
|
||||
if errors.As(err, &cerr) {
|
||||
|
||||
@ -104,7 +104,9 @@ type Config struct {
|
||||
|
||||
// CheckTransactionInputs defines the function to use to perform a series of
|
||||
// checks on the inputs to a transaction to ensure they are valid.
|
||||
CheckTransactionInputs func(tx *dcrutil.Tx, txHeight int64, view *blockchain.UtxoViewpoint, checkFraudProof bool, isTreasuryEnabled bool) (int64, error)
|
||||
CheckTransactionInputs func(tx *dcrutil.Tx, txHeight int64,
|
||||
view *blockchain.UtxoViewpoint, checkFraudProof, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled bool) (int64, error)
|
||||
|
||||
// CheckTSpendHasVotes defines the function to use to check whether the given
|
||||
// tspend has enough votes to be included in a block AFTER the specified block.
|
||||
@ -163,6 +165,11 @@ type Config struct {
|
||||
// treasury agenda is active or not for the block AFTER the given block.
|
||||
IsTreasuryAgendaActive func(prevHash *chainhash.Hash) (bool, error)
|
||||
|
||||
// IsAutoRevocationsAgendaActive defines the function to use to determine if
|
||||
// the automatic ticket revocations agenda is active or not for the block
|
||||
// AFTER the given block.
|
||||
IsAutoRevocationsAgendaActive func(prevHash *chainhash.Hash) (bool, error)
|
||||
|
||||
// MaxTreasuryExpenditure defines the function to use to get the maximum amount
|
||||
// of funds that can be spent from the treasury by a set of TSpends for a block
|
||||
// that extends the given block hash. The function should return 0 if it is
|
||||
@ -1062,6 +1069,11 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress stdaddr.Address) (*Bloc
|
||||
return nil, err
|
||||
}
|
||||
|
||||
isAutoRevocationsEnabled, err := g.cfg.IsAutoRevocationsAgendaActive(&prevHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
isTVI bool
|
||||
maxTreasurySpend int64
|
||||
@ -1551,7 +1563,7 @@ nextPriorityQueueItem:
|
||||
// The fraud proof is not checked because it will be filled in
|
||||
// by the miner.
|
||||
_, err = g.cfg.CheckTransactionInputs(bundledTx.Tx, nextBlockHeight,
|
||||
blockUtxos, false, isTreasuryEnabled)
|
||||
blockUtxos, false, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
log.Tracef("Skipping tx %s due to error in "+
|
||||
"CheckTransactionInputs: %v", bundledTx.Tx.Hash(), err)
|
||||
|
||||
@ -69,6 +69,8 @@ type fakeChain struct {
|
||||
isHeaderCommitmentsAgendaActiveErr error
|
||||
isTreasuryAgendaActive bool
|
||||
isTreasuryAgendaActiveErr error
|
||||
isAutoRevocationsAgendaActive bool
|
||||
isAutoRevocationsAgendaActiveErr error
|
||||
maxTreasuryExpenditure int64
|
||||
maxTreasuryExpenditureErr error
|
||||
parentUtxos *blockchain.UtxoViewpoint
|
||||
@ -194,6 +196,13 @@ func (c *fakeChain) IsTreasuryAgendaActive(prevHash *chainhash.Hash) (bool, erro
|
||||
return c.isTreasuryAgendaActive, c.isTreasuryAgendaActiveErr
|
||||
}
|
||||
|
||||
// IsAutoRevocationsAgendaActive returns a mocked bool representing whether the
|
||||
// automatic ticket revocations agenda is active or not for the block AFTER the
|
||||
// given block.
|
||||
func (c *fakeChain) IsAutoRevocationsAgendaActive(prevHash *chainhash.Hash) (bool, error) {
|
||||
return c.isAutoRevocationsAgendaActive, c.isAutoRevocationsAgendaActiveErr
|
||||
}
|
||||
|
||||
// MaxTreasuryExpenditure returns a mocked maximum amount of funds that can be
|
||||
// spent from the treasury by a set of TSpends for a block that extends the
|
||||
// given block hash.
|
||||
@ -635,6 +644,7 @@ func (p *fakeTxSource) maybeAcceptTransaction(tx *dcrutil.Tx, isNew bool) ([]*ch
|
||||
height := p.chain.BestSnapshot().Height
|
||||
nextHeight := height + 1
|
||||
isTreasuryEnabled := p.chain.isTreasuryAgendaActive
|
||||
isAutoRevocationsEnabled := p.chain.isAutoRevocationsAgendaActive
|
||||
|
||||
// Determine what type of transaction we're dealing with (regular or stake).
|
||||
// Then, be sure to set the tx tree correctly as it's possible a user submitted
|
||||
@ -698,7 +708,7 @@ func (p *fakeTxSource) maybeAcceptTransaction(tx *dcrutil.Tx, isNew bool) ([]*ch
|
||||
}
|
||||
|
||||
txFee, err := blockchain.CheckTransactionInputs(p.subsidyCache, tx, nextHeight,
|
||||
utxoView, false, p.chainParams, isTreasuryEnabled)
|
||||
utxoView, false, p.chainParams, isTreasuryEnabled, isAutoRevocationsEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1388,11 +1398,12 @@ func newMiningHarness(chainParams *chaincfg.Params) (*miningHarness, []spendable
|
||||
CheckConnectBlockTemplate: chain.CheckConnectBlockTemplate,
|
||||
CheckTicketExhaustion: chain.CheckTicketExhaustion,
|
||||
CheckTransactionInputs: func(tx *dcrutil.Tx, txHeight int64,
|
||||
view *blockchain.UtxoViewpoint, checkFraudProof bool,
|
||||
isTreasuryEnabled bool) (int64, error) {
|
||||
view *blockchain.UtxoViewpoint, checkFraudProof, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled bool) (int64, error) {
|
||||
|
||||
return blockchain.CheckTransactionInputs(subsidyCache, tx, txHeight,
|
||||
view, checkFraudProof, chainParams, isTreasuryEnabled)
|
||||
view, checkFraudProof, chainParams, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled)
|
||||
},
|
||||
CheckTSpendHasVotes: chain.CheckTSpendHasVotes,
|
||||
CountSigOps: blockchain.CountSigOps,
|
||||
@ -1403,6 +1414,7 @@ func newMiningHarness(chainParams *chaincfg.Params) (*miningHarness, []spendable
|
||||
IsFinalizedTransaction: blockchain.IsFinalizedTransaction,
|
||||
IsHeaderCommitmentsAgendaActive: chain.IsHeaderCommitmentsAgendaActive,
|
||||
IsTreasuryAgendaActive: chain.IsTreasuryAgendaActive,
|
||||
IsAutoRevocationsAgendaActive: chain.IsAutoRevocationsAgendaActive,
|
||||
MaxTreasuryExpenditure: chain.MaxTreasuryExpenditure,
|
||||
NewUtxoViewpoint: chain.NewUtxoViewpoint,
|
||||
TipGeneration: chain.TipGeneration,
|
||||
|
||||
@ -3560,11 +3560,12 @@ func newServer(ctx context.Context, listenAddrs []string, db database.DB,
|
||||
CheckConnectBlockTemplate: s.chain.CheckConnectBlockTemplate,
|
||||
CheckTicketExhaustion: s.chain.CheckTicketExhaustion,
|
||||
CheckTransactionInputs: func(tx *dcrutil.Tx, txHeight int64,
|
||||
view *blockchain.UtxoViewpoint, checkFraudProof bool,
|
||||
isTreasuryEnabled bool) (int64, error) {
|
||||
view *blockchain.UtxoViewpoint, checkFraudProof, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled bool) (int64, error) {
|
||||
|
||||
return blockchain.CheckTransactionInputs(s.subsidyCache, tx, txHeight,
|
||||
view, checkFraudProof, s.chainParams, isTreasuryEnabled)
|
||||
view, checkFraudProof, s.chainParams, isTreasuryEnabled,
|
||||
isAutoRevocationsEnabled)
|
||||
},
|
||||
CheckTSpendHasVotes: s.chain.CheckTSpendHasVotes,
|
||||
CountSigOps: blockchain.CountSigOps,
|
||||
@ -3575,6 +3576,7 @@ func newServer(ctx context.Context, listenAddrs []string, db database.DB,
|
||||
IsFinalizedTransaction: blockchain.IsFinalizedTransaction,
|
||||
IsHeaderCommitmentsAgendaActive: s.chain.IsHeaderCommitmentsAgendaActive,
|
||||
IsTreasuryAgendaActive: s.chain.IsTreasuryAgendaActive,
|
||||
IsAutoRevocationsAgendaActive: s.chain.IsAutoRevocationsAgendaActive,
|
||||
MaxTreasuryExpenditure: s.chain.MaxTreasuryExpenditure,
|
||||
NewUtxoViewpoint: func() *blockchain.UtxoViewpoint {
|
||||
return blockchain.NewUtxoViewpoint(utxoCache)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user