[NOD-237] Implement transaction mass (#355)

* [NOD-237] Implemented transaction mass.

* [NOD-237] Added transaction mass validation to the mempool.

* [NOD-237] Made blockMaxMassMax not rely on MaxBlockPayload.

* [NOD-237] Added comments describing the new constants in validate.go.

* [NOD-237] Changed the default blockmaxmass to 10,000,000.

* [NOD-237] Fixed a comment that erroneously didn't refer to mass.

* [NOD-237] Added comments to ValidateTxMass and CalcTxMass.

* [NOD-237] Renamed "size" to "byte". Made validateBlockMass exit early if validation fails. Fixed unit names in comments. In CalcTxMass, moved summing of mass to the bottom of the function.

* [NOD-237] Instead of ErrMassTooHigh, renamed ErrBlockTooBig and ErrTxTooBig. Replaced wire.MaxBlockPayload with MaxMassPerBlock.

* [NOD-237] Fixed sanity checks related to block size in commands.

* [NOD-237] To use up less memory during testing, made the mass in the "too big" test come from pkScripts rather than input bytes.

* [NOD-237] Added an overflow check to validateBlockMass.
This commit is contained in:
stasatdaglabs 2019-08-05 16:04:24 +03:00 committed by Svarog
parent 54b681460d
commit bfdf7a2cf2
25 changed files with 218 additions and 132 deletions

View File

@ -37,9 +37,9 @@ const (
// exists. // exists.
ErrDuplicateBlock ErrorCode = iota ErrDuplicateBlock ErrorCode = iota
// ErrBlockTooBig indicates the serialized block size exceeds the // ErrBlockMassTooHigh indicates the mass of a block exceeds the maximum
// maximum allowed size. // allowed limits.
ErrBlockTooBig ErrBlockMassTooHigh
// ErrBlockVersionTooOld indicates the block version is too old and is // ErrBlockVersionTooOld indicates the block version is too old and is
// no longer accepted since the majority of the network has upgraded // no longer accepted since the majority of the network has upgraded
@ -105,9 +105,9 @@ const (
// valid transaction must have at least one input. // valid transaction must have at least one input.
ErrNoTxInputs ErrNoTxInputs
// ErrTxTooBig indicates a transaction exceeds the maximum allowed size // ErrTxMassTooHigh indicates the mass of a transaction exceeds the maximum
// when serialized. // allowed limits.
ErrTxTooBig ErrTxMassTooHigh
// ErrBadTxOutValue indicates an output value for a transaction is // ErrBadTxOutValue indicates an output value for a transaction is
// invalid in some way such as being out of range. // invalid in some way such as being out of range.
@ -227,7 +227,7 @@ const (
// Map of ErrorCode values back to their constant names for pretty printing. // Map of ErrorCode values back to their constant names for pretty printing.
var errorCodeStrings = map[ErrorCode]string{ var errorCodeStrings = map[ErrorCode]string{
ErrDuplicateBlock: "ErrDuplicateBlock", ErrDuplicateBlock: "ErrDuplicateBlock",
ErrBlockTooBig: "ErrBlockTooBig", ErrBlockMassTooHigh: "ErrBlockMassTooHigh",
ErrBlockVersionTooOld: "ErrBlockVersionTooOld", ErrBlockVersionTooOld: "ErrBlockVersionTooOld",
ErrInvalidTime: "ErrInvalidTime", ErrInvalidTime: "ErrInvalidTime",
ErrTimeTooOld: "ErrTimeTooOld", ErrTimeTooOld: "ErrTimeTooOld",
@ -242,7 +242,7 @@ var errorCodeStrings = map[ErrorCode]string{
ErrFinalityPointTimeTooOld: "ErrFinalityPointTimeTooOld", ErrFinalityPointTimeTooOld: "ErrFinalityPointTimeTooOld",
ErrNoTransactions: "ErrNoTransactions", ErrNoTransactions: "ErrNoTransactions",
ErrNoTxInputs: "ErrNoTxInputs", ErrNoTxInputs: "ErrNoTxInputs",
ErrTxTooBig: "ErrTxTooBig", ErrTxMassTooHigh: "ErrTxMassTooHigh",
ErrBadTxOutValue: "ErrBadTxOutValue", ErrBadTxOutValue: "ErrBadTxOutValue",
ErrDuplicateTxInputs: "ErrDuplicateTxInputs", ErrDuplicateTxInputs: "ErrDuplicateTxInputs",
ErrBadTxInput: "ErrBadTxInput", ErrBadTxInput: "ErrBadTxInput",

View File

@ -16,7 +16,7 @@ func TestErrorCodeStringer(t *testing.T) {
want string want string
}{ }{
{ErrDuplicateBlock, "ErrDuplicateBlock"}, {ErrDuplicateBlock, "ErrDuplicateBlock"},
{ErrBlockTooBig, "ErrBlockTooBig"}, {ErrBlockMassTooHigh, "ErrBlockMassTooHigh"},
{ErrBlockVersionTooOld, "ErrBlockVersionTooOld"}, {ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
{ErrInvalidTime, "ErrInvalidTime"}, {ErrInvalidTime, "ErrInvalidTime"},
{ErrTimeTooOld, "ErrTimeTooOld"}, {ErrTimeTooOld, "ErrTimeTooOld"},
@ -31,7 +31,7 @@ func TestErrorCodeStringer(t *testing.T) {
{ErrFinalityPointTimeTooOld, "ErrFinalityPointTimeTooOld"}, {ErrFinalityPointTimeTooOld, "ErrFinalityPointTimeTooOld"},
{ErrNoTransactions, "ErrNoTransactions"}, {ErrNoTransactions, "ErrNoTransactions"},
{ErrNoTxInputs, "ErrNoTxInputs"}, {ErrNoTxInputs, "ErrNoTxInputs"},
{ErrTxTooBig, "ErrTxTooBig"}, {ErrTxMassTooHigh, "ErrTxMassTooHigh"},
{ErrBadTxOutValue, "ErrBadTxOutValue"}, {ErrBadTxOutValue, "ErrBadTxOutValue"},
{ErrDuplicateTxInputs, "ErrDuplicateTxInputs"}, {ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
{ErrBadTxInput, "ErrBadTxInput"}, {ErrBadTxInput, "ErrBadTxInput"},

View File

@ -1106,7 +1106,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
replaceSpendScript(sizePadScript)(b) replaceSpendScript(sizePadScript)(b)
}) })
g.assertTipBlockSize(maxBlockSize + 1) g.assertTipBlockSize(maxBlockSize + 1)
rejected(blockdag.ErrBlockTooBig) rejected(blockdag.ErrBlockMassTooHigh)
// Parent was rejected, so this block must either be an orphan or // Parent was rejected, so this block must either be an orphan or
// outright rejected due to an invalid parent. // outright rejected due to an invalid parent.

View File

@ -20,8 +20,8 @@ import (
const ( const (
// MaxSigOpsPerBlock is the maximum number of signature operations // MaxSigOpsPerBlock is the maximum number of signature operations
// allowed for a block. It is a fraction of the max block payload size. // allowed for a block. It is a fraction of the max block transaction mass.
MaxSigOpsPerBlock = wire.MaxBlockPayload / 50 MaxSigOpsPerBlock = wire.MaxMassPerBlock / 50
// MaxCoinbasePayloadLen is the maximum length a coinbase payload can be. // MaxCoinbasePayloadLen is the maximum length a coinbase payload can be.
MaxCoinbasePayloadLen = 150 MaxCoinbasePayloadLen = 150
@ -29,6 +29,11 @@ const (
// baseSubsidy is the starting subsidy amount for mined blocks. This // baseSubsidy is the starting subsidy amount for mined blocks. This
// value is halved every SubsidyHalvingInterval blocks. // value is halved every SubsidyHalvingInterval blocks.
baseSubsidy = 50 * util.SatoshiPerBitcoin baseSubsidy = 50 * util.SatoshiPerBitcoin
// the following are used when calculating a transaction's mass
massPerTxByte = 1
massPerPKScriptByte = 10
massPerSigOp = 10000
) )
// isNullOutpoint determines whether or not a previous transaction outpoint // isNullOutpoint determines whether or not a previous transaction outpoint
@ -121,13 +126,13 @@ func CheckTransactionSanity(tx *util.Tx, subnetworkID *subnetworkid.SubnetworkID
return ruleError(ErrNoTxInputs, "transaction has no inputs") return ruleError(ErrNoTxInputs, "transaction has no inputs")
} }
// A transaction must not exceed the maximum allowed block payload when // A transaction must not exceed the maximum allowed block mass when
// serialized. // serialized.
serializedTxSize := msgTx.SerializeSize() serializedTxSize := msgTx.SerializeSize()
if serializedTxSize > wire.MaxBlockPayload { if serializedTxSize > wire.MaxMassPerBlock {
str := fmt.Sprintf("serialized transaction is too big - got "+ str := fmt.Sprintf("serialized transaction is too big - got "+
"%d, max %d", serializedTxSize, wire.MaxBlockPayload) "%d, max %d", serializedTxSize, wire.MaxMassPerBlock)
return ruleError(ErrTxTooBig, str) return ruleError(ErrTxMassTooHigh, str)
} }
// Ensure the transaction amounts are in range. Each transaction // Ensure the transaction amounts are in range. Each transaction
@ -361,6 +366,86 @@ func CountP2SHSigOps(tx *util.Tx, isCoinbase bool, utxoSet UTXOSet) (int, error)
return totalSigOps, nil return totalSigOps, nil
} }
// ValidateTxMass makes sure that the given transaction's mass does not exceed
// the maximum allowed limit. Currently, it is equivalent to the block mass limit.
// See CalcTxMass for further details.
func ValidateTxMass(tx *util.Tx, utxoSet UTXOSet) error {
txMass, err := CalcTxMass(tx, utxoSet)
if err != nil {
return err
}
if txMass > wire.MaxMassPerBlock {
str := fmt.Sprintf("tx %s has mass %d, which is above the "+
"allowed limit of %d", tx.ID(), txMass, wire.MaxMassPerBlock)
return ruleError(ErrTxMassTooHigh, str)
}
return nil
}
func validateBlockMass(pastUTXO UTXOSet, transactions []*util.Tx) error {
totalMass := uint64(0)
for _, tx := range transactions {
txMass, err := CalcTxMass(tx, pastUTXO)
if err != nil {
return err
}
totalMass += txMass
// We could potentially overflow the accumulator so check for
// overflow as well.
if totalMass < txMass || totalMass > wire.MaxMassPerBlock {
str := fmt.Sprintf("block has total mass %d, which is "+
"above the allowed limit of %d", totalMass, wire.MaxMassPerBlock)
return ruleError(ErrBlockMassTooHigh, str)
}
}
return nil
}
// CalcTxMass sums up and returns the "mass" of a transaction. This number
// is an approximation of how many resources (CPU, RAM, etc.) it would take
// to process the transaction.
// The following properties are considered in the calculation:
// * The transaction length in bytes
// * The length of all output scripts in bytes
// * The count of all input sigOps
func CalcTxMass(tx *util.Tx, utxoSet UTXOSet) (uint64, error) {
txSize := tx.MsgTx().SerializeSize()
if tx.IsCoinBase() {
return uint64(txSize * massPerTxByte), nil
}
pkScriptSize := 0
for _, txOut := range tx.MsgTx().TxOut {
pkScriptSize += len(txOut.PkScript)
}
sigOpsCount := 0
for txInIndex, txIn := range tx.MsgTx().TxIn {
// Ensure the referenced input transaction is available.
entry, ok := utxoSet.Get(txIn.PreviousOutpoint)
if !ok {
str := fmt.Sprintf("output %s referenced from "+
"transaction %s:%d either does not exist or "+
"has already been spent", txIn.PreviousOutpoint,
tx.ID(), txInIndex)
return 0, ruleError(ErrMissingTxOut, str)
}
// Count the precise number of signature operations in the
// referenced public key script.
pkScript := entry.PkScript()
sigScript := txIn.SignatureScript
isP2SH := txscript.IsPayToScriptHash(pkScript)
sigOpsCount += txscript.GetPreciseSigOpCount(sigScript, pkScript, isP2SH)
}
return uint64(txSize*massPerTxByte +
pkScriptSize*massPerPKScriptByte +
sigOpsCount*massPerSigOp), nil
}
// checkBlockHeaderSanity performs some preliminary checks on a block header to // checkBlockHeaderSanity performs some preliminary checks on a block header to
// ensure it is sane before continuing with processing. These checks are // ensure it is sane before continuing with processing. These checks are
// context free. // context free.
@ -444,21 +529,12 @@ func (dag *BlockDAG) checkBlockSanity(block *util.Block, flags BehaviorFlags) (t
"any transactions") "any transactions")
} }
// A block must not have more transactions than the max block payload or // A block must not have more transactions than the max block mass or
// else it is certainly over the block size limit. // else it is certainly over the block mass limit.
if numTx > wire.MaxBlockPayload { if numTx > wire.MaxMassPerBlock {
str := fmt.Sprintf("block contains too many transactions - "+ str := fmt.Sprintf("block contains too many transactions - "+
"got %d, max %d", numTx, wire.MaxBlockPayload) "got %d, max %d", numTx, wire.MaxMassPerBlock)
return 0, ruleError(ErrBlockTooBig, str) return 0, ruleError(ErrBlockMassTooHigh, str)
}
// A block must not exceed the maximum allowed block payload when
// serialized.
serializedSize := msgBlock.SerializeSize()
if serializedSize > wire.MaxBlockPayload {
str := fmt.Sprintf("serialized block is too big - got %d, "+
"max %d", serializedSize, wire.MaxBlockPayload)
return 0, ruleError(ErrBlockTooBig, str)
} }
// The first transaction in a block must be a coinbase. // The first transaction in a block must be a coinbase.
@ -861,6 +937,10 @@ func (dag *BlockDAG) checkConnectToPastUTXO(block *blockNode, pastUTXO UTXOSet,
if err := validateSigopsCount(pastUTXO, transactions); err != nil { if err := validateSigopsCount(pastUTXO, transactions); err != nil {
return nil, err return nil, err
} }
if err := validateBlockMass(pastUTXO, transactions); err != nil {
return nil, err
}
} }
// Perform several checks on the inputs for each transaction. Also // Perform several checks on the inputs for each transaction. Also

View File

@ -633,7 +633,7 @@ func TestCheckTransactionSanity(t *testing.T) {
{"good one", 1, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil}, {"good one", 1, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil},
{"no inputs", 0, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrNoTxInputs, "")}, {"no inputs", 0, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrNoTxInputs, "")},
{"no outputs", 1, 0, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil}, {"no outputs", 1, 0, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil},
{"too big", 100000, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrTxTooBig, "")}, {"too massive", 1, 1000000, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrTxMassTooHigh, "")},
{"too much satoshi in one output", 1, 1, util.MaxSatoshi + 1, {"too much satoshi in one output", 1, 1, util.MaxSatoshi + 1,
*subnetworkid.SubnetworkIDNative, *subnetworkid.SubnetworkIDNative,
nil, nil,

View File

@ -222,10 +222,10 @@ type TemplateRequest struct {
// Optional long polling. // Optional long polling.
LongPollID string `json:"longPollId,omitempty"` LongPollID string `json:"longPollId,omitempty"`
// Optional template tweaking. SigOpLimit and SizeLimit can be int64 // Optional template tweaking. SigOpLimit and MassLimit can be int64
// or bool. // or bool.
SigOpLimit interface{} `json:"sigOpLimit,omitempty"` SigOpLimit interface{} `json:"sigOpLimit,omitempty"`
SizeLimit interface{} `json:"sizeLimit,omitempty"` MassLimit interface{} `json:"massLimit,omitempty"`
MaxVersion uint32 `json:"maxVersion,omitempty"` MaxVersion uint32 `json:"maxVersion,omitempty"`
// Basic pool extension from BIP 0023. // Basic pool extension from BIP 0023.
@ -257,7 +257,7 @@ func convertTemplateRequestField(fieldName string, iface interface{}) (interface
} }
// UnmarshalJSON provides a custom Unmarshal method for TemplateRequest. This // UnmarshalJSON provides a custom Unmarshal method for TemplateRequest. This
// is necessary because the SigOpLimit and SizeLimit fields can only be specific // is necessary because the SigOpLimit and MassLimit fields can only be specific
// types. // types.
func (t *TemplateRequest) UnmarshalJSON(data []byte) error { func (t *TemplateRequest) UnmarshalJSON(data []byte) error {
type templateRequest TemplateRequest type templateRequest TemplateRequest
@ -274,12 +274,12 @@ func (t *TemplateRequest) UnmarshalJSON(data []byte) error {
} }
request.SigOpLimit = val request.SigOpLimit = val
// The SizeLimit field can only be nil, bool, or int64. // The MassLimit field can only be nil, bool, or int64.
val, err = convertTemplateRequestField("sizeLimit", request.SizeLimit) val, err = convertTemplateRequestField("massLimit", request.MassLimit)
if err != nil { if err != nil {
return err return err
} }
request.SizeLimit = val request.MassLimit = val
return nil return nil
} }

View File

@ -271,25 +271,25 @@ func TestDAGSvrCmds(t *testing.T) {
{ {
name: "getBlockTemplate optional - template request with tweaks", name: "getBlockTemplate optional - template request with tweaks",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getBlockTemplate", `{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":500,"sizeLimit":100000000,"maxVersion":1}`) return btcjson.NewCmd("getBlockTemplate", `{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":500,"massLimit":100000000,"maxVersion":1}`)
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
template := btcjson.TemplateRequest{ template := btcjson.TemplateRequest{
Mode: "template", Mode: "template",
Capabilities: []string{"longPoll", "coinbaseTxn"}, Capabilities: []string{"longPoll", "coinbaseTxn"},
SigOpLimit: 500, SigOpLimit: 500,
SizeLimit: 100000000, MassLimit: 100000000,
MaxVersion: 1, MaxVersion: 1,
} }
return btcjson.NewGetBlockTemplateCmd(&template) return btcjson.NewGetBlockTemplateCmd(&template)
}, },
marshalled: `{"jsonrpc":"1.0","method":"getBlockTemplate","params":[{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":500,"sizeLimit":100000000,"maxVersion":1}],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getBlockTemplate","params":[{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":500,"massLimit":100000000,"maxVersion":1}],"id":1}`,
unmarshalled: &btcjson.GetBlockTemplateCmd{ unmarshalled: &btcjson.GetBlockTemplateCmd{
Request: &btcjson.TemplateRequest{ Request: &btcjson.TemplateRequest{
Mode: "template", Mode: "template",
Capabilities: []string{"longPoll", "coinbaseTxn"}, Capabilities: []string{"longPoll", "coinbaseTxn"},
SigOpLimit: int64(500), SigOpLimit: int64(500),
SizeLimit: int64(100000000), MassLimit: int64(100000000),
MaxVersion: 1, MaxVersion: 1,
}, },
}, },
@ -297,25 +297,25 @@ func TestDAGSvrCmds(t *testing.T) {
{ {
name: "getBlockTemplate optional - template request with tweaks 2", name: "getBlockTemplate optional - template request with tweaks 2",
newCmd: func() (interface{}, error) { newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getBlockTemplate", `{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":true,"sizeLimit":100000000,"maxVersion":1}`) return btcjson.NewCmd("getBlockTemplate", `{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":true,"massLimit":100000000,"maxVersion":1}`)
}, },
staticCmd: func() interface{} { staticCmd: func() interface{} {
template := btcjson.TemplateRequest{ template := btcjson.TemplateRequest{
Mode: "template", Mode: "template",
Capabilities: []string{"longPoll", "coinbaseTxn"}, Capabilities: []string{"longPoll", "coinbaseTxn"},
SigOpLimit: true, SigOpLimit: true,
SizeLimit: 100000000, MassLimit: 100000000,
MaxVersion: 1, MaxVersion: 1,
} }
return btcjson.NewGetBlockTemplateCmd(&template) return btcjson.NewGetBlockTemplateCmd(&template)
}, },
marshalled: `{"jsonrpc":"1.0","method":"getBlockTemplate","params":[{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":true,"sizeLimit":100000000,"maxVersion":1}],"id":1}`, marshalled: `{"jsonrpc":"1.0","method":"getBlockTemplate","params":[{"mode":"template","capabilities":["longPoll","coinbaseTxn"],"sigOpLimit":true,"massLimit":100000000,"maxVersion":1}],"id":1}`,
unmarshalled: &btcjson.GetBlockTemplateCmd{ unmarshalled: &btcjson.GetBlockTemplateCmd{
Request: &btcjson.TemplateRequest{ Request: &btcjson.TemplateRequest{
Mode: "template", Mode: "template",
Capabilities: []string{"longPoll", "coinbaseTxn"}, Capabilities: []string{"longPoll", "coinbaseTxn"},
SigOpLimit: true, SigOpLimit: true,
SizeLimit: int64(100000000), MassLimit: int64(100000000),
MaxVersion: 1, MaxVersion: 1,
}, },
}, },
@ -1152,9 +1152,9 @@ func TestDAGSvrCmdErrors(t *testing.T) {
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType}, err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
}, },
{ {
name: "invalid template request sizelimit field", name: "invalid template request masslimit field",
result: &btcjson.TemplateRequest{}, result: &btcjson.TemplateRequest{},
marshalled: `{"sizelimit":"invalid"}`, marshalled: `{"masslimit":"invalid"}`,
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType}, err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
}, },
} }

View File

@ -121,6 +121,7 @@ type GetBlockTemplateResultTx struct {
Data string `json:"data"` Data string `json:"data"`
ID string `json:"id"` ID string `json:"id"`
Depends []int64 `json:"depends"` Depends []int64 `json:"depends"`
Mass uint64 `json:"mass"`
Fee uint64 `json:"fee"` Fee uint64 `json:"fee"`
SigOps int64 `json:"sigOps"` SigOps int64 `json:"sigOps"`
} }
@ -141,7 +142,7 @@ type GetBlockTemplateResult struct {
Height uint64 `json:"height"` Height uint64 `json:"height"`
ParentHashes []string `json:"parentHashes"` ParentHashes []string `json:"parentHashes"`
SigOpLimit int64 `json:"sigOpLimit,omitempty"` SigOpLimit int64 `json:"sigOpLimit,omitempty"`
SizeLimit int64 `json:"sizeLimit,omitempty"` MassLimit int64 `json:"massLimit,omitempty"`
Transactions []GetBlockTemplateResultTx `json:"transactions"` Transactions []GetBlockTemplateResultTx `json:"transactions"`
AcceptedIDMerkleRoot string `json:"acceptedIdMerkleRoot"` AcceptedIDMerkleRoot string `json:"acceptedIdMerkleRoot"`
UTXOCommitment string `json:"utxoCommitment"` UTXOCommitment string `json:"utxoCommitment"`

View File

@ -69,10 +69,10 @@ func (bi *blockImporter) readBlock() ([]byte, error) {
if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil { if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil {
return nil, err return nil, err
} }
if blockLen > wire.MaxBlockPayload { if blockLen > wire.MaxMessagePayload {
return nil, fmt.Errorf("block payload of %d bytes is larger "+ return nil, fmt.Errorf("block payload of %d bytes is larger "+
"than the max allowed %d bytes", blockLen, "than the max allowed %d bytes", blockLen,
wire.MaxBlockPayload) wire.MaxMessagePayload)
} }
serializedBlock := make([]byte, blockLen) serializedBlock := make([]byte, blockLen)

View File

@ -28,7 +28,6 @@ import (
"github.com/daglabs/btcd/util/network" "github.com/daglabs/btcd/util/network"
"github.com/daglabs/btcd/util/subnetworkid" "github.com/daglabs/btcd/util/subnetworkid"
"github.com/daglabs/btcd/version" "github.com/daglabs/btcd/version"
"github.com/daglabs/btcd/wire"
"github.com/jessevdk/go-flags" "github.com/jessevdk/go-flags"
) )
@ -47,10 +46,9 @@ const (
defaultMaxRPCWebsockets = 25 defaultMaxRPCWebsockets = 25
defaultMaxRPCConcurrentReqs = 20 defaultMaxRPCConcurrentReqs = 20
defaultDbType = "ffldb" defaultDbType = "ffldb"
defaultBlockMinSize = 0 defaultBlockMaxMass = 10000000
defaultBlockMaxSize = 750000 blockMaxMassMin = 1000
blockMaxSizeMin = 1000 blockMaxMassMax = 10000000
blockMaxSizeMax = wire.MaxBlockPayload - 1000
defaultGenerate = false defaultGenerate = false
defaultMaxOrphanTransactions = 100 defaultMaxOrphanTransactions = 100
//DefaultMaxOrphanTxSize is the default maximum size for an orphan transaction //DefaultMaxOrphanTxSize is the default maximum size for an orphan transaction
@ -148,8 +146,7 @@ type configFlags struct {
MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"` MaxOrphanTxs int `long:"maxorphantx" description:"Max number of orphan transactions to keep in memory"`
Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"` Generate bool `long:"generate" description:"Generate (mine) bitcoins using the CPU"`
MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"` MiningAddrs []string `long:"miningaddr" description:"Add the specified payment address to the list of addresses to use for generated blocks -- At least one address is required if the generate option is set"`
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"` BlockMaxMass uint64 `long:"blockmaxmass" description:"Maximum transaction mass to be used when creating a block"`
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum block size in bytes to be used when creating a block"`
UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."` UserAgentComments []string `long:"uacomment" description:"Comment to add to the user agent -- See BIP 14 for more information."`
NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"` NoPeerBloomFilters bool `long:"nopeerbloomfilters" description:"Disable bloom filtering support"`
EnableCFilters bool `long:"enablecfilters" description:"Enable committed filtering (CF) support"` EnableCFilters bool `long:"enablecfilters" description:"Enable committed filtering (CF) support"`
@ -312,8 +309,7 @@ func loadConfig() (*Config, []string, error) {
DbType: defaultDbType, DbType: defaultDbType,
RPCKey: defaultRPCKeyFile, RPCKey: defaultRPCKeyFile,
RPCCert: defaultRPCCertFile, RPCCert: defaultRPCCertFile,
BlockMinSize: defaultBlockMinSize, BlockMaxMass: defaultBlockMaxMass,
BlockMaxSize: defaultBlockMaxSize,
MaxOrphanTxs: defaultMaxOrphanTransactions, MaxOrphanTxs: defaultMaxOrphanTransactions,
SigCacheMaxSize: defaultSigCacheMaxSize, SigCacheMaxSize: defaultSigCacheMaxSize,
Generate: defaultGenerate, Generate: defaultGenerate,
@ -659,14 +655,14 @@ func loadConfig() (*Config, []string, error) {
return nil, nil, err return nil, nil, err
} }
// Limit the max block size to a sane value. // Limit the max block mass to a sane value.
if cfg.BlockMaxSize < blockMaxSizeMin || cfg.BlockMaxSize > if cfg.BlockMaxMass < blockMaxMassMin || cfg.BlockMaxMass >
blockMaxSizeMax { blockMaxMassMax {
str := "%s: The blockmaxsize option must be in between %d " + str := "%s: The blockmaxmass option must be in between %d " +
"and %d -- parsed [%d]" "and %d -- parsed [%d]"
err := fmt.Errorf(str, funcName, blockMaxSizeMin, err := fmt.Errorf(str, funcName, blockMaxMassMin,
blockMaxSizeMax, cfg.BlockMaxSize) blockMaxMassMax, cfg.BlockMaxMass)
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
fmt.Fprintln(os.Stderr, usageMessage) fmt.Fprintln(os.Stderr, usageMessage)
return nil, nil, err return nil, nil, err
@ -682,9 +678,6 @@ func loadConfig() (*Config, []string, error) {
return nil, nil, err return nil, nil, err
} }
// Limit minimum block sizes to max block size.
cfg.BlockMinSize = minUint32(cfg.BlockMinSize, cfg.BlockMaxSize)
// Look for illegal characters in the user agent comments. // Look for illegal characters in the user agent comments.
for _, uaComment := range cfg.UserAgentComments { for _, uaComment := range cfg.UserAgentComments {
if strings.ContainsAny(uaComment, "/:()") { if strings.ContainsAny(uaComment, "/:()") {

View File

@ -81,10 +81,10 @@ func (bi *blockImporter) readBlock() ([]byte, error) {
if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil { if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil {
return nil, err return nil, err
} }
if blockLen > wire.MaxBlockPayload { if blockLen > wire.MaxMessagePayload {
return nil, fmt.Errorf("block payload of %d bytes is larger "+ return nil, fmt.Errorf("block payload of %d bytes is larger "+
"than the max allowed %d bytes", blockLen, "than the max allowed %d bytes", blockLen,
wire.MaxBlockPayload) wire.MaxMessagePayload)
} }
serializedBlock := make([]byte, blockLen) serializedBlock := make([]byte, blockLen)

View File

@ -938,6 +938,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rejectDupOrphans bo
"transaction's sequence locks on inputs not met") "transaction's sequence locks on inputs not met")
} }
// Don't allow transactions that exceed the maximum allowed
// transaction mass.
err = blockdag.ValidateTxMass(tx, mp.mpUTXOSet)
if err != nil {
if ruleError, ok := err.(blockdag.RuleError); ok {
return nil, nil, dagRuleError(ruleError)
}
return nil, nil, err
}
// Perform several checks on the transaction inputs using the invariant // Perform several checks on the transaction inputs using the invariant
// rules in blockchain for what transactions are allowed into blocks. // rules in blockchain for what transactions are allowed into blocks.
// Also returns the fees associated with the transaction which will be // Also returns the fees associated with the transaction which will be

View File

@ -162,6 +162,10 @@ type BlockTemplate struct {
// requirement. // requirement.
Block *wire.MsgBlock Block *wire.MsgBlock
// TxMasses contains the mass of each transaction in the generated
// template performs.
TxMasses []uint64
// Fees contains the amount of fees each transaction in the generated // Fees contains the amount of fees each transaction in the generated
// template pays in base units. Since the first transaction is the // template pays in base units. Since the first transaction is the
// coinbase, the first entry (offset 0) will contain the negative of the // coinbase, the first entry (offset 0) will contain the negative of the
@ -279,7 +283,7 @@ func NewBlkTmplGenerator(policy *Policy, params *dagconfig.Params,
// nonzero, in which case the block will be filled with the low-fee/free // nonzero, in which case the block will be filled with the low-fee/free
// transactions until the block size reaches that minimum size. // transactions until the block size reaches that minimum size.
// //
// Any transactions which would cause the block to exceed the BlockMaxSize // Any transactions which would cause the block to exceed the BlockMaxMass
// policy setting, exceed the maximum allowed signature operations per block, or // policy setting, exceed the maximum allowed signature operations per block, or
// otherwise cause the block to be invalid are skipped. // otherwise cause the block to be invalid are skipped.
// //
@ -294,7 +298,7 @@ func NewBlkTmplGenerator(policy *Policy, params *dagconfig.Params,
// |-----------------------------------| | -- // |-----------------------------------| | --
// | | | // | | |
// | | | // | | |
// | | |--- policy.BlockMaxSize // | | |--- policy.BlockMaxMass
// | Transactions prioritized by fee | | // | Transactions prioritized by fee | |
// | until <= policy.TxMinFreeFee | | // | until <= policy.TxMinFreeFee | |
// | | | // | | |
@ -310,6 +314,8 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
defer g.dag.RUnlock() defer g.dag.RUnlock()
nextBlockBlueScore := g.dag.VirtualBlueScore() nextBlockBlueScore := g.dag.VirtualBlueScore()
nextBlockUTXO := g.dag.UTXOSet()
coinbasePayloadPkScript, err := txscript.PayToAddrScript(payToAddress) coinbasePayloadPkScript, err := txscript.PayToAddrScript(payToAddress)
if err != nil { if err != nil {
return nil, err return nil, err
@ -328,6 +334,10 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
if err != nil { if err != nil {
return nil, err return nil, err
} }
coinbaseTxMass, err := blockdag.CalcTxMass(coinbaseTx, nextBlockUTXO)
if err != nil {
return nil, err
}
numCoinbaseSigOps := int64(blockdag.CountSigOps(coinbaseTx)) numCoinbaseSigOps := int64(blockdag.CountSigOps(coinbaseTx))
// Get the current source transactions and create a priority queue to // Get the current source transactions and create a priority queue to
@ -346,21 +356,20 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
blockTxns := make([]*util.Tx, 0, len(sourceTxns)+1) blockTxns := make([]*util.Tx, 0, len(sourceTxns)+1)
blockTxns = append(blockTxns, coinbaseTx) blockTxns = append(blockTxns, coinbaseTx)
// The starting block size is the size of the block header plus the max blockMass := coinbaseTxMass
// possible transaction count size, plus the size of the coinbase
// transaction.
blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
blockSigOps := numCoinbaseSigOps blockSigOps := numCoinbaseSigOps
totalFees := uint64(0) totalFees := uint64(0)
// Create slices to hold the fees and number of signature operations // Create slices to hold the mass, the fees, and number of signature
// for each of the selected transactions and add an entry for the // operations for each of the selected transactions and add an entry for
// coinbase. This allows the code below to simply append details about // the coinbase. This allows the code below to simply append details
// a transaction as it is selected for inclusion in the final block. // about a transaction as it is selected for inclusion in the final block.
// However, since the total fees aren't known yet, use a dummy value for // However, since the total fees aren't known yet, use a dummy value for
// the coinbase fee which will be updated later. // the coinbase fee which will be updated later.
txMasses := make([]uint64, 0, len(sourceTxns)+1)
txFees := make([]uint64, 0, len(sourceTxns)+1) txFees := make([]uint64, 0, len(sourceTxns)+1)
txSigOpCounts := make([]int64, 0, len(sourceTxns)+1) txSigOpCounts := make([]int64, 0, len(sourceTxns)+1)
txMasses = append(txMasses, coinbaseTxMass)
txFees = append(txFees, 0) // For coinbase tx txFees = append(txFees, 0) // For coinbase tx
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps) txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
@ -423,14 +432,18 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
gasUsageMap[subnetworkID] = gasUsage + txGas gasUsageMap[subnetworkID] = gasUsage + txGas
} }
// Enforce maximum block size. Also check for overflow. // Enforce maximum transaction mass per block. Also check
txSize := uint32(tx.MsgTx().SerializeSize()) // for overflow.
blockPlusTxSize := blockSize + txSize txMass, err := blockdag.CalcTxMass(tx, g.dag.UTXOSet())
if blockPlusTxSize < blockSize || if err != nil {
blockPlusTxSize >= g.policy.BlockMaxSize { log.Tracef("Skipping tx %s due to error in "+
"CalcTxMass: %s", tx.ID(), err)
continue
}
if blockMass+txMass < blockMass ||
blockMass >= g.policy.BlockMaxMass {
log.Tracef("Skipping tx %s because it would exceed "+ log.Tracef("Skipping tx %s because it would exceed "+
"the max block size", tx.ID()) "the max block mass", tx.ID())
continue continue
} }
@ -476,12 +489,13 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
} }
// Add the transaction to the block, increment counters, and // Add the transaction to the block, increment counters, and
// save the fees and signature operation counts to the block // save the masses, fees, and signature operation counts to the block
// template. // template.
blockTxns = append(blockTxns, tx) blockTxns = append(blockTxns, tx)
blockSize += txSize blockMass += txMass
blockSigOps += int64(numSigOps) blockSigOps += numSigOps
totalFees += prioItem.fee totalFees += prioItem.fee
txMasses = append(txMasses, txMass)
txFees = append(txFees, prioItem.fee) txFees = append(txFees, prioItem.fee)
txSigOpCounts = append(txSigOpCounts, numSigOps) txSigOpCounts = append(txSigOpCounts, numSigOps)
@ -489,12 +503,6 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
prioItem.tx.ID(), prioItem.feePerKB) prioItem.tx.ID(), prioItem.feePerKB)
} }
// Now that the actual transactions have been selected, update the
// block size for the real transaction count and coinbase value with
// the total fees accordingly.
blockSize -= wire.MaxVarIntPayload -
uint32(wire.VarIntSerializeSize(uint64(len(blockTxns))))
// Calculate the required difficulty for the block. The timestamp // Calculate the required difficulty for the block. The timestamp
// is potentially adjusted to ensure it comes after the median time of // is potentially adjusted to ensure it comes after the median time of
// the last several blocks per the chain consensus rules. // the last several blocks per the chain consensus rules.
@ -553,12 +561,13 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
} }
log.Debugf("Created new block template (%d transactions, %d in fees, "+ log.Debugf("Created new block template (%d transactions, %d in fees, "+
"%d signature operations, %d bytes, target difficulty %064x)", "%d signature operations, %d mass, target difficulty %064x)",
len(msgBlock.Transactions), totalFees, blockSigOps, blockSize, len(msgBlock.Transactions), totalFees, blockSigOps, blockMass,
util.CompactToBig(msgBlock.Header.Bits)) util.CompactToBig(msgBlock.Header.Bits))
return &BlockTemplate{ return &BlockTemplate{
Block: &msgBlock, Block: &msgBlock,
TxMasses: txMasses,
Fees: txFees, Fees: txFees,
SigOpCounts: txSigOpCounts, SigOpCounts: txSigOpCounts,
ValidPayAddress: payToAddress != nil, ValidPayAddress: payToAddress != nil,

View File

@ -89,7 +89,7 @@ func TestNewBlockTemplate(t *testing.T) {
} }
policy := Policy{ policy := Policy{
BlockMaxSize: 50000, BlockMaxMass: 50000,
} }
// First we create a block to have coinbase funds for the rest of the test. // First we create a block to have coinbase funds for the rest of the test.

View File

@ -8,11 +8,7 @@ package mining
// the generation of block templates. See the documentation for // the generation of block templates. See the documentation for
// NewBlockTemplate for more details on each of these parameters are used. // NewBlockTemplate for more details on each of these parameters are used.
type Policy struct { type Policy struct {
// BlockMinSize is the minimum block size to be used when generating // BlockMaxMass is the maximum block mass to be used when generating a
// a block template.
BlockMinSize uint32
// BlockMaxSize is the maximum block size to be used when generating a
// block template. // block template.
BlockMaxSize uint32 BlockMaxMass uint64
} }

View File

@ -46,7 +46,7 @@ func PrepareBlockForTest(dag *blockdag.BlockDAG, params *dagconfig.Params, paren
oldVirtual := blockdag.SetVirtualForTest(dag, newVirtual) oldVirtual := blockdag.SetVirtualForTest(dag, newVirtual)
defer blockdag.SetVirtualForTest(dag, oldVirtual) defer blockdag.SetVirtualForTest(dag, oldVirtual)
policy := Policy{ policy := Policy{
BlockMaxSize: 50000, BlockMaxMass: 50000,
} }
txSource := &fakeTxSource{ txSource := &fakeTxSource{

View File

@ -1761,6 +1761,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
Data: hex.EncodeToString(txBuf.Bytes()), Data: hex.EncodeToString(txBuf.Bytes()),
ID: txID.String(), ID: txID.String(),
Depends: depends, Depends: depends,
Mass: template.TxMasses[i],
Fee: template.Fees[i], Fee: template.Fees[i],
SigOps: template.SigOpCounts[i], SigOps: template.SigOpCounts[i],
} }
@ -1779,7 +1780,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
Height: template.Height, Height: template.Height,
ParentHashes: daghash.Strings(header.ParentHashes), ParentHashes: daghash.Strings(header.ParentHashes),
SigOpLimit: blockdag.MaxSigOpsPerBlock, SigOpLimit: blockdag.MaxSigOpsPerBlock,
SizeLimit: wire.MaxBlockPayload, MassLimit: wire.MaxMassPerBlock,
Transactions: transactions, Transactions: transactions,
AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot.String(), AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot.String(),
UTXOCommitment: header.UTXOCommitment.String(), UTXOCommitment: header.UTXOCommitment.String(),
@ -1822,6 +1823,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
Data: hex.EncodeToString(txBuf.Bytes()), Data: hex.EncodeToString(txBuf.Bytes()),
ID: tx.TxID().String(), ID: tx.TxID().String(),
Depends: []int64{}, Depends: []int64{},
Mass: template.TxMasses[0],
Fee: template.Fees[0], Fee: template.Fees[0],
SigOps: template.SigOpCounts[0], SigOps: template.SigOpCounts[0],
} }
@ -2028,8 +2030,8 @@ func chainErrToGBTErrString(err error) string {
switch ruleErr.ErrorCode { switch ruleErr.ErrorCode {
case blockdag.ErrDuplicateBlock: case blockdag.ErrDuplicateBlock:
return "duplicate" return "duplicate"
case blockdag.ErrBlockTooBig: case blockdag.ErrBlockMassTooHigh:
return "bad-blk-length" return "bad-blk-mass"
case blockdag.ErrBlockVersionTooOld: case blockdag.ErrBlockVersionTooOld:
return "bad-version" return "bad-version"
case blockdag.ErrInvalidTime: case blockdag.ErrInvalidTime:
@ -2054,8 +2056,8 @@ func chainErrToGBTErrString(err error) string {
return "bad-txns-none" return "bad-txns-none"
case blockdag.ErrNoTxInputs: case blockdag.ErrNoTxInputs:
return "bad-txns-noinputs" return "bad-txns-noinputs"
case blockdag.ErrTxTooBig: case blockdag.ErrTxMassTooHigh:
return "bad-txns-size" return "bad-txns-mass"
case blockdag.ErrBadTxOutValue: case blockdag.ErrBadTxOutValue:
return "bad-txns-outputvalue" return "bad-txns-outputvalue"
case blockdag.ErrDuplicateTxInputs: case blockdag.ErrDuplicateTxInputs:

View File

@ -283,7 +283,7 @@ var helpDescsEnUS = map[string]string{
"templateRequest-capabilities": "List of capabilities", "templateRequest-capabilities": "List of capabilities",
"templateRequest-longPollId": "The long poll ID of a job to monitor for expiration; required and valid only for long poll requests ", "templateRequest-longPollId": "The long poll ID of a job to monitor for expiration; required and valid only for long poll requests ",
"templateRequest-sigOpLimit": "Number of signature operations allowed in blocks (this parameter is ignored)", "templateRequest-sigOpLimit": "Number of signature operations allowed in blocks (this parameter is ignored)",
"templateRequest-sizeLimit": "Number of bytes allowed in blocks (this parameter is ignored)", "templateRequest-massLimit": "Max transaction mass allowed in blocks (this parameter is ignored)",
"templateRequest-maxVersion": "Highest supported block version number (this parameter is ignored)", "templateRequest-maxVersion": "Highest supported block version number (this parameter is ignored)",
"templateRequest-target": "The desired target for the block template (this parameter is ignored)", "templateRequest-target": "The desired target for the block template (this parameter is ignored)",
"templateRequest-data": "Hex-encoded block data (only for mode=proposal)", "templateRequest-data": "Hex-encoded block data (only for mode=proposal)",
@ -294,6 +294,7 @@ var helpDescsEnUS = map[string]string{
"getBlockTemplateResultTx-hash": "Hex-encoded transaction hash (little endian if treated as a 256-bit number)", "getBlockTemplateResultTx-hash": "Hex-encoded transaction hash (little endian if treated as a 256-bit number)",
"getBlockTemplateResultTx-id": "Hex-encoded transaction ID (little endian if treated as a 256-bit number)", "getBlockTemplateResultTx-id": "Hex-encoded transaction ID (little endian if treated as a 256-bit number)",
"getBlockTemplateResultTx-depends": "Other transactions before this one (by 1-based index in the 'transactions' list) that must be present in the final block if this one is", "getBlockTemplateResultTx-depends": "Other transactions before this one (by 1-based index in the 'transactions' list) that must be present in the final block if this one is",
"getBlockTemplateResultTx-mass": "Total mass of all transactions in the block",
"getBlockTemplateResultTx-fee": "Difference in value between transaction inputs and outputs (in Satoshi)", "getBlockTemplateResultTx-fee": "Difference in value between transaction inputs and outputs (in Satoshi)",
"getBlockTemplateResultTx-sigOps": "Total number of signature operations as counted for purposes of block limits", "getBlockTemplateResultTx-sigOps": "Total number of signature operations as counted for purposes of block limits",
@ -305,8 +306,8 @@ var helpDescsEnUS = map[string]string{
"getBlockTemplateResult-curTime": "Current time as seen by the server (recommended for block time); must fall within mintime/maxtime rules", "getBlockTemplateResult-curTime": "Current time as seen by the server (recommended for block time); must fall within mintime/maxtime rules",
"getBlockTemplateResult-height": "Height of the block to be solved", "getBlockTemplateResult-height": "Height of the block to be solved",
"getBlockTemplateResult-parentHashes": "Hex-encoded big-endian hashes of the parent blocks", "getBlockTemplateResult-parentHashes": "Hex-encoded big-endian hashes of the parent blocks",
"getBlockTemplateResult-sigOpLimit": "Number of sigops allowed in blocks ", "getBlockTemplateResult-sigOpLimit": "Number of sigops allowed in blocks",
"getBlockTemplateResult-sizeLimit": "Number of bytes allowed in blocks", "getBlockTemplateResult-massLimit": "Max transaction mass allowed in blocks",
"getBlockTemplateResult-transactions": "Array of transactions as JSON objects", "getBlockTemplateResult-transactions": "Array of transactions as JSON objects",
"getBlockTemplateResult-acceptedIdMerkleRoot": "The root of the merkle tree of transaction IDs accepted by this block", "getBlockTemplateResult-acceptedIdMerkleRoot": "The root of the merkle tree of transaction IDs accepted by this block",
"getBlockTemplateResult-utxoCommitment": "An ECMH UTXO commitment of this block", "getBlockTemplateResult-utxoCommitment": "An ECMH UTXO commitment of this block",

View File

@ -101,8 +101,7 @@ func NewServer(listenAddrs []string, db database.DB, dagParams *dagconfig.Params
// NOTE: The CPU miner relies on the mempool, so the mempool has to be // NOTE: The CPU miner relies on the mempool, so the mempool has to be
// created before calling the function to create the CPU miner. // created before calling the function to create the CPU miner.
policy := mining.Policy{ policy := mining.Policy{
BlockMinSize: cfg.BlockMinSize, BlockMaxMass: cfg.BlockMaxMass,
BlockMaxSize: cfg.BlockMaxSize,
} }
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy, blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
s.p2pServer.DAGParams, s.p2pServer.TxMemPool, s.p2pServer.DAG, s.p2pServer.TimeSource, s.p2pServer.SigCache) s.p2pServer.DAGParams, s.p2pServer.TxMemPool, s.p2pServer.DAG, s.p2pServer.TimeSource, s.p2pServer.SigCache)

View File

@ -21,12 +21,12 @@ import (
// backing array multiple times. // backing array multiple times.
const defaultTransactionAlloc = 2048 const defaultTransactionAlloc = 2048
// MaxBlockPayload is the maximum bytes a block message can be in bytes. // maxMassPerBlock is the maximum total transaction mass a block may contain.
const MaxBlockPayload = 1000000 const MaxMassPerBlock = 10000000
// maxTxPerBlock is the maximum number of transactions that could // maxTxPerBlock is the maximum number of transactions that could
// possibly fit into a block. // possibly fit into a block.
const maxTxPerBlock = (MaxBlockPayload / minTxPayload) + 1 const maxTxPerBlock = (MaxMassPerBlock / minTxPayload) + 1
// TxLoc holds locator data for the offset and length of where a transaction is // TxLoc holds locator data for the offset and length of where a transaction is
// located within a MsgBlock data buffer. // located within a MsgBlock data buffer.
@ -217,10 +217,7 @@ func (msg *MsgBlock) Command() string {
// MaxPayloadLength returns the maximum length the payload can be for the // MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation. // receiver. This is part of the Message interface implementation.
func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 { func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
// Block header at 80 bytes + transaction count + max transactions return MaxMessagePayload
// which can vary up to the MaxBlockPayload (including the block header
// and transaction count).
return MaxBlockPayload
} }
// BlockHash computes the block identifier hash for this block. // BlockHash computes the block identifier hash for this block.

View File

@ -40,8 +40,7 @@ func TestBlock(t *testing.T) {
} }
// Ensure max payload is expected value for latest protocol version. // Ensure max payload is expected value for latest protocol version.
// Num addresses (varInt) + max allowed addresses. wantPayload := uint32(1024 * 1024 * 32)
wantPayload := uint32(1000000)
maxPayload := msg.MaxPayloadLength(pver) maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload { if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+ t.Errorf("MaxPayloadLength: wrong max payload length for "+

View File

@ -133,7 +133,7 @@ func (msg *MsgMerkleBlock) Command() string {
// MaxPayloadLength returns the maximum length the payload can be for the // MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation. // receiver. This is part of the Message interface implementation.
func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 { func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
return MaxBlockPayload return MaxMessagePayload
} }
// NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to // NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to

View File

@ -38,8 +38,7 @@ func TestMerkleBlock(t *testing.T) {
} }
// Ensure max payload is expected value for latest protocol version. // Ensure max payload is expected value for latest protocol version.
// Num addresses (varInt) + max allowed addresses. wantPayload := uint32(1024 * 1024 * 32)
wantPayload := uint32(1000000)
maxPayload := msg.MaxPayloadLength(pver) maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload { if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+ t.Errorf("MaxPayloadLength: wrong max payload length for "+

View File

@ -765,7 +765,7 @@ func (msg *MsgTx) Command() string {
// MaxPayloadLength returns the maximum length the payload can be for the // MaxPayloadLength returns the maximum length the payload can be for the
// receiver. This is part of the Message interface implementation. // receiver. This is part of the Message interface implementation.
func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 {
return MaxBlockPayload return MaxMessagePayload
} }
// PkScriptLocs returns a slice containing the start of each public key script // PkScriptLocs returns a slice containing the start of each public key script

View File

@ -37,7 +37,7 @@ func TestTx(t *testing.T) {
} }
// Ensure max payload is expected value for latest protocol version. // Ensure max payload is expected value for latest protocol version.
wantPayload := uint32(1000 * 1000) wantPayload := uint32(1024 * 1024 * 32)
maxPayload := msg.MaxPayloadLength(pver) maxPayload := msg.MaxPayloadLength(pver)
if maxPayload != wantPayload { if maxPayload != wantPayload {
t.Errorf("MaxPayloadLength: wrong max payload length for "+ t.Errorf("MaxPayloadLength: wrong max payload length for "+