mirror of
https://github.com/FlipsideCrypto/dcrd.git
synced 2026-02-06 10:56:47 +00:00
multi: Abstract standard verification flags.
This modifies the way standard verification flags are handled so that it is possible to selectively enable them based on the result of agenda votes. First, it moves the StandardVerifyFlags constant from the txscript package to the mempool/policy code and rename it to BaseStandardVerifyFlags. As the TODO in the comment of the moved constant indicated, these flags are policy related and thus really belong in policy. Ideally there would be a completely separate policy package, but since the policy code currently lives in mempool/policy.go, the constant has been moved there. Next, it introduces a new function named standardScriptVerifyFlags, which accepts the chain as an argument and, for now, just returns the BaseStandardVerifyFlags along with a nil error. This will allow additional flags to be selectively enabled depending on the result of an agenda vote. Finally, it updates the mempool policy struct to require a closure for obtaining the flags so it can remain decoupled from the chain which in turn allows easier and more robust unit testing of mempool functionality since it allows a mocks to be used.
This commit is contained in:
parent
11ae59977a
commit
1955bb1bf1
@ -171,6 +171,14 @@ type Policy struct {
|
||||
// AllowOldVotes defines whether or not votes on old blocks will be
|
||||
// admitted and relayed.
|
||||
AllowOldVotes bool
|
||||
|
||||
// StandardVerifyFlags defines the function to retrieve the flags to
|
||||
// use for verifying scripts for the block after the current best block.
|
||||
// It must set the verification flags properly depending on the result
|
||||
// of any agendas that affect them.
|
||||
//
|
||||
// This function must be safe for concurrent access.
|
||||
StandardVerifyFlags func() (txscript.ScriptFlags, error)
|
||||
}
|
||||
|
||||
// TxDesc is a descriptor containing a transaction in the mempool along with
|
||||
@ -1138,8 +1146,12 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, rateLimit, allow
|
||||
|
||||
// Verify crypto signatures for each input and reject the transaction if
|
||||
// any don't verify.
|
||||
err = blockchain.ValidateTransactionScripts(tx, utxoView,
|
||||
txscript.StandardVerifyFlags, mp.cfg.SigCache)
|
||||
flags, err := mp.cfg.Policy.StandardVerifyFlags()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = blockchain.ValidateTransactionScripts(tx, utxoView, flags,
|
||||
mp.cfg.SigCache)
|
||||
if err != nil {
|
||||
if cerr, ok := err.(blockchain.RuleError); ok {
|
||||
return nil, chainRuleError(cerr)
|
||||
|
||||
@ -32,6 +32,7 @@ type fakeChain struct {
|
||||
blocks map[chainhash.Hash]*dcrutil.Block
|
||||
currentHash chainhash.Hash
|
||||
currentHeight int64
|
||||
scriptFlags txscript.ScriptFlags
|
||||
}
|
||||
|
||||
// NextStakeDifficulty returns the next stake difficulty associated with the
|
||||
@ -132,6 +133,18 @@ func (s *fakeChain) SetHeight(height int64) {
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
// StandardVerifyFlags returns the standard verification script flags associated
|
||||
// with the fake chain instance.
|
||||
func (s *fakeChain) StandardVerifyFlags() (txscript.ScriptFlags, error) {
|
||||
return s.scriptFlags, nil
|
||||
}
|
||||
|
||||
// SetStandardVerifyFlags sets the standard verification script flags associated
|
||||
// with the fake chain instance.
|
||||
func (s *fakeChain) SetStandardVerifyFlags(flags txscript.ScriptFlags) {
|
||||
s.scriptFlags = flags
|
||||
}
|
||||
|
||||
// spendableOutput is a convenience type that houses a particular utxo and the
|
||||
// amount associated with it.
|
||||
type spendableOutput struct {
|
||||
@ -328,8 +341,9 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp
|
||||
// Create a new fake chain and harness bound to it.
|
||||
subsidyCache := blockchain.NewSubsidyCache(0, chainParams)
|
||||
chain := &fakeChain{
|
||||
utxos: blockchain.NewUtxoViewpoint(),
|
||||
blocks: make(map[chainhash.Hash]*dcrutil.Block),
|
||||
utxos: blockchain.NewUtxoViewpoint(),
|
||||
blocks: make(map[chainhash.Hash]*dcrutil.Block),
|
||||
scriptFlags: BaseStandardVerifyFlags,
|
||||
}
|
||||
harness := poolHarness{
|
||||
signKey: signKey,
|
||||
@ -347,6 +361,7 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp
|
||||
MaxOrphanTxSize: 1000,
|
||||
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
|
||||
MinRelayTxFee: 1000, // 1 Satoshi per byte
|
||||
StandardVerifyFlags: chain.StandardVerifyFlags,
|
||||
},
|
||||
ChainParams: chainParams,
|
||||
NextStakeDifficulty: chain.NextStakeDifficulty,
|
||||
|
||||
@ -55,6 +55,22 @@ const (
|
||||
// in a multi-signature transaction output script for it to be
|
||||
// considered standard.
|
||||
maxStandardMultiSigKeys = 3
|
||||
|
||||
// BaseStandardVerifyFlags defines the script flags that should be used
|
||||
// when executing transaction scripts to enforce additional checks which
|
||||
// are required for the script to be considered standard regardless of
|
||||
// the state of any agenda votes. The full set of standard verification
|
||||
// flags must include these flags as well as any additional flags that
|
||||
// are conditionally enabled depending on the result of agenda votes.
|
||||
BaseStandardVerifyFlags = txscript.ScriptBip16 |
|
||||
txscript.ScriptVerifyDERSignatures |
|
||||
txscript.ScriptVerifyStrictEncoding |
|
||||
txscript.ScriptVerifyMinimalData |
|
||||
txscript.ScriptDiscourageUpgradableNops |
|
||||
txscript.ScriptVerifyCleanStack |
|
||||
txscript.ScriptVerifyCheckLockTimeVerify |
|
||||
txscript.ScriptVerifyCheckSequenceVerify |
|
||||
txscript.ScriptVerifyLowS
|
||||
)
|
||||
|
||||
// calcMinRequiredTxRelayFee returns the minimum transaction fee required for a
|
||||
|
||||
@ -1149,6 +1149,13 @@ func NewBlockTemplate(policy *mining.Policy, server *server,
|
||||
chainState := &blockManager.chainState
|
||||
subsidyCache := blockManager.chain.FetchSubsidyCache()
|
||||
|
||||
// All transaction scripts are verified using the more strict standarad
|
||||
// flags.
|
||||
scriptFlags, err := standardScriptVerifyFlags(blockManager.chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extend the most recently known best block.
|
||||
// The most recently known best block is the top block that has the most
|
||||
// ssgen votes for it. We only need this after the height in which stake voting
|
||||
@ -1599,7 +1606,7 @@ mempoolLoop:
|
||||
continue
|
||||
}
|
||||
err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
|
||||
txscript.StandardVerifyFlags, server.sigCache)
|
||||
scriptFlags, server.sigCache)
|
||||
if err != nil {
|
||||
minrLog.Tracef("Skipping tx %s due to error in "+
|
||||
"ValidateTransactionScripts: %v", tx.Hash(), err)
|
||||
|
||||
11
server.go
11
server.go
@ -2213,6 +2213,14 @@ out:
|
||||
s.wg.Done()
|
||||
}
|
||||
|
||||
// standardScriptVerifyFlags returns the script flags that should be used when
|
||||
// executing transaction scripts to enforce additional checks which are required
|
||||
// for the script to be considered standard. Note these flags are different
|
||||
// than what is required for the consensus rules in that they are more strict.
|
||||
func standardScriptVerifyFlags(chain *blockchain.BlockChain) (txscript.ScriptFlags, error) {
|
||||
return mempool.BaseStandardVerifyFlags, nil
|
||||
}
|
||||
|
||||
// newServer returns a new dcrd server configured to listen on addr for the
|
||||
// decred network type specified by chainParams. Use start to begin accepting
|
||||
// connections from peers.
|
||||
@ -2421,6 +2429,9 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
|
||||
MaxSigOpsPerTx: blockchain.MaxSigOpsPerBlock / 5,
|
||||
MinRelayTxFee: cfg.minRelayTxFee,
|
||||
AllowOldVotes: cfg.AllowOldVotes,
|
||||
StandardVerifyFlags: func() (txscript.ScriptFlags, error) {
|
||||
return standardScriptVerifyFlags(bm.chain)
|
||||
},
|
||||
},
|
||||
ChainParams: chainParams,
|
||||
NextStakeDifficulty: func() (int64, error) {
|
||||
|
||||
@ -16,6 +16,21 @@ import (
|
||||
"github.com/decred/dcrd/wire"
|
||||
)
|
||||
|
||||
// testScriptFlags are the script flags which are used in the tests when
|
||||
// executing transaction scripts to enforce additional checks. Note these flags
|
||||
// are different than what is required for the consensus rules in that they are
|
||||
// more strict.
|
||||
const testScriptFlags = ScriptBip16 |
|
||||
ScriptVerifyDERSignatures |
|
||||
ScriptVerifyStrictEncoding |
|
||||
ScriptVerifyMinimalData |
|
||||
ScriptDiscourageUpgradableNops |
|
||||
ScriptVerifyCleanStack |
|
||||
ScriptVerifyCheckLockTimeVerify |
|
||||
ScriptVerifyCheckSequenceVerify |
|
||||
ScriptVerifyLowS |
|
||||
ScriptVerifySHA256
|
||||
|
||||
// TestOpcodeDisabled tests the opcodeDisabled function manually because all
|
||||
// disabled opcodes result in a script execution failure when executed normally,
|
||||
// so the function is not called under normal circumstances.
|
||||
@ -475,8 +490,8 @@ func TestNewlyEnabledOpCodes(t *testing.T) {
|
||||
Value: 0x00FFFFFF00000000,
|
||||
PkScript: []byte{0x01},
|
||||
})
|
||||
flags := StandardVerifyFlags
|
||||
engine, err := NewEngine(test.pkScript, msgTx, 0, flags, 0, nil)
|
||||
engine, err := NewEngine(test.pkScript, msgTx, 0,
|
||||
testScriptFlags, 0, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Bad script result for test %v because of error: %v",
|
||||
test.name, err.Error())
|
||||
@ -544,9 +559,8 @@ func TestForVMFailure(t *testing.T) {
|
||||
Value: 0x00FFFFFF00000000,
|
||||
PkScript: []byte{0x01},
|
||||
})
|
||||
flags := StandardVerifyFlags
|
||||
engine, err := NewEngine(tests[j], msgTx, 0, flags, 0,
|
||||
nil)
|
||||
engine, err := NewEngine(tests[j], msgTx, 0,
|
||||
testScriptFlags, 0, nil)
|
||||
|
||||
if err == nil {
|
||||
engine.Execute()
|
||||
|
||||
@ -19,26 +19,6 @@ const (
|
||||
// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
|
||||
// data to be considered a nulldata transaction.
|
||||
MaxDataCarrierSize = 256
|
||||
|
||||
// StandardVerifyFlags are the script flags which are used when
|
||||
// executing transaction scripts to enforce additional checks which
|
||||
// are required for the script to be considered standard. These checks
|
||||
// help reduce issues related to transaction malleability as well as
|
||||
// allow pay-to-script hash transactions. Note these flags are
|
||||
// different than what is required for the consensus rules in that they
|
||||
// are more strict.
|
||||
//
|
||||
// TODO: This definition does not belong here. It belongs in a policy
|
||||
// package.
|
||||
StandardVerifyFlags = ScriptBip16 |
|
||||
ScriptVerifyDERSignatures |
|
||||
ScriptVerifyStrictEncoding |
|
||||
ScriptVerifyMinimalData |
|
||||
ScriptDiscourageUpgradableNops |
|
||||
ScriptVerifyCleanStack |
|
||||
ScriptVerifyCheckLockTimeVerify |
|
||||
ScriptVerifyCheckSequenceVerify |
|
||||
ScriptVerifyLowS
|
||||
)
|
||||
|
||||
// ScriptClass is an enumeration for the list of standard types of script.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user