mempool/wire: Don't make policy decisions in wire.

This removes the function IsSupportedMsgTxVersion function from wire
since that is a policy decision and does not belong in wire.

It also updates the mempool standard transaction checks to be more
inline with the upstream code such that the maximum supported
transaction version is specified via a field in the mempool policy
configuration struct.

Finally, it adds a new test to the standard transaction tests to ensure
transactions that are not serialized with the full seriaization type are
considered nonstandard.
This commit is contained in:
Dave Collins 2017-08-05 14:45:24 -05:00
parent 3adf306307
commit dee4231e01
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
6 changed files with 41 additions and 15 deletions

View File

@ -131,6 +131,11 @@ type Config struct {
// Policy houses the policy (configuration parameters) which is used to
// control the mempool.
type Policy struct {
// MaxTxVersion is the max transaction version that the mempool should
// accept. All transactions above this version are rejected as
// non-standard.
MaxTxVersion uint16
// DisableRelayPriority defines whether to relay free or low-fee
// transactions that do not have enough priority to be relayed.
DisableRelayPriority bool
@ -818,7 +823,8 @@ func (mp *TxPool) maybeAcceptTransaction(tx *dcrutil.Tx, isNew, rateLimit, allow
// forbid their relaying.
if !mp.cfg.Policy.RelayNonStd {
err := checkTransactionStandard(tx, txType, nextBlockHeight,
mp.cfg.TimeSource, mp.cfg.Policy.MinRelayTxFee)
mp.cfg.TimeSource, mp.cfg.Policy.MinRelayTxFee,
mp.cfg.Policy.MaxTxVersion)
if err != nil {
// Attempt to extract a reject code from the error so
// it can be retained. When not possible, fall back to

View File

@ -340,6 +340,7 @@ func newPoolHarness(chainParams *chaincfg.Params) (*poolHarness, []spendableOutp
chain: chain,
txPool: New(&Config{
Policy: Policy{
MaxTxVersion: wire.TxVersion,
DisableRelayPriority: true,
FreeTxRelayLimit: 15.0,
MaxOrphanTxs: 5,

View File

@ -347,15 +347,24 @@ func isDust(txOut *wire.TxOut, minRelayTxFee dcrutil.Amount) bool {
// of recognized forms, and not containing "dust" outputs (those that are
// so small it costs more to process them than they are worth).
func checkTransactionStandard(tx *dcrutil.Tx, txType stake.TxType, height int64,
timeSource blockchain.MedianTimeSource,
minRelayTxFee dcrutil.Amount) error {
timeSource blockchain.MedianTimeSource, minRelayTxFee dcrutil.Amount,
maxTxVersion uint16) error {
// The transaction must be a currently supported version.
//
// The version includes the real transaction version in the lower 16
// bits and the transaction serialize type as the upper 16 bits.
msgTx := tx.MsgTx()
if !wire.IsSupportedMsgTxVersion(msgTx) {
serType := wire.TxSerializeType(uint32(msgTx.Version) >> 16)
txVersion := uint16(uint32(msgTx.Version) & 0xffff)
if serType != wire.TxSerializeFull {
str := fmt.Sprintf("transaction is not serialized with all "+
"required data -- type %v", serType)
return txRuleError(wire.RejectNonstandard, str)
}
if txVersion > maxTxVersion || txVersion < 1 {
str := fmt.Sprintf("transaction version %d is not in the "+
"valid range of %d-%d", msgTx.Version, 1,
wire.TxVersion)
"valid range of %d-%d", txVersion, 1, maxTxVersion)
return txRuleError(wire.RejectNonstandard, str)
}

View File

@ -287,6 +287,10 @@ func TestDust(t *testing.T) {
// TestCheckTransactionStandard tests the checkTransactionStandard API.
func TestCheckTransactionStandard(t *testing.T) {
// maxTxVersion is used as the maximum support transaction version for
// the policy in these tests.
const maxTxVersion = 1
// Create some dummy, but otherwise standard, data for transactions.
prevOutHash, err := chainhash.NewHashFromStr("01")
if err != nil {
@ -336,10 +340,22 @@ func TestCheckTransactionStandard(t *testing.T) {
height: 300000,
isStandard: true,
},
{
name: "Transaction serialize type not full",
tx: wire.MsgTx{
Version: int32(uint32(wire.TxSerializeNoWitness)<<16 | 1),
TxIn: []*wire.TxIn{&dummyTxIn},
TxOut: []*wire.TxOut{&dummyTxOut},
LockTime: 0,
},
height: 300000,
isStandard: false,
code: wire.RejectNonstandard,
},
{
name: "Transaction version too high",
tx: wire.MsgTx{
Version: int32(wire.TxVersion + 1),
Version: maxTxVersion + 1,
TxIn: []*wire.TxIn{&dummyTxIn},
TxOut: []*wire.TxOut{&dummyTxOut},
LockTime: 0,
@ -492,7 +508,7 @@ func TestCheckTransactionStandard(t *testing.T) {
// Ensure standardness is as expected.
tx := dcrutil.NewTx(&test.tx)
err := checkTransactionStandard(tx, stake.DetermineTxType(&test.tx),
test.height, timeSource, DefaultMinRelayTxFee)
test.height, timeSource, DefaultMinRelayTxFee, maxTxVersion)
if err == nil && test.isStandard {
// Test passes since function returned standard for a
// transaction which is intended to be standard.

View File

@ -2412,6 +2412,7 @@ func newServer(listenAddrs []string, db database.DB, chainParams *chaincfg.Param
txC := mempool.Config{
Policy: mempool.Policy{
MaxTxVersion: 1,
DisableRelayPriority: cfg.NoRelayPriority,
RelayNonStd: cfg.RelayNonStd,
FreeTxRelayLimit: cfg.FreeTxRelayLimit,

View File

@ -1581,10 +1581,3 @@ func writeTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error {
return WriteVarBytes(w, pver, to.PkScript)
}
// IsSupportedMsgTxVersion returns if a transaction version is supported or not.
// Currently, inclusion into the memory pool (and thus blocks) only supports
// the DefaultMsgTxVersion.
func IsSupportedMsgTxVersion(msgTx *MsgTx) bool {
return msgTx.Version == DefaultMsgTxVersion()
}