mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-04 13:16:43 +00:00
[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:
parent
54b681460d
commit
bfdf7a2cf2
@ -37,9 +37,9 @@ const (
|
||||
// exists.
|
||||
ErrDuplicateBlock ErrorCode = iota
|
||||
|
||||
// ErrBlockTooBig indicates the serialized block size exceeds the
|
||||
// maximum allowed size.
|
||||
ErrBlockTooBig
|
||||
// ErrBlockMassTooHigh indicates the mass of a block exceeds the maximum
|
||||
// allowed limits.
|
||||
ErrBlockMassTooHigh
|
||||
|
||||
// ErrBlockVersionTooOld indicates the block version is too old and is
|
||||
// no longer accepted since the majority of the network has upgraded
|
||||
@ -105,9 +105,9 @@ const (
|
||||
// valid transaction must have at least one input.
|
||||
ErrNoTxInputs
|
||||
|
||||
// ErrTxTooBig indicates a transaction exceeds the maximum allowed size
|
||||
// when serialized.
|
||||
ErrTxTooBig
|
||||
// ErrTxMassTooHigh indicates the mass of a transaction exceeds the maximum
|
||||
// allowed limits.
|
||||
ErrTxMassTooHigh
|
||||
|
||||
// ErrBadTxOutValue indicates an output value for a transaction is
|
||||
// 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.
|
||||
var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrDuplicateBlock: "ErrDuplicateBlock",
|
||||
ErrBlockTooBig: "ErrBlockTooBig",
|
||||
ErrBlockMassTooHigh: "ErrBlockMassTooHigh",
|
||||
ErrBlockVersionTooOld: "ErrBlockVersionTooOld",
|
||||
ErrInvalidTime: "ErrInvalidTime",
|
||||
ErrTimeTooOld: "ErrTimeTooOld",
|
||||
@ -242,7 +242,7 @@ var errorCodeStrings = map[ErrorCode]string{
|
||||
ErrFinalityPointTimeTooOld: "ErrFinalityPointTimeTooOld",
|
||||
ErrNoTransactions: "ErrNoTransactions",
|
||||
ErrNoTxInputs: "ErrNoTxInputs",
|
||||
ErrTxTooBig: "ErrTxTooBig",
|
||||
ErrTxMassTooHigh: "ErrTxMassTooHigh",
|
||||
ErrBadTxOutValue: "ErrBadTxOutValue",
|
||||
ErrDuplicateTxInputs: "ErrDuplicateTxInputs",
|
||||
ErrBadTxInput: "ErrBadTxInput",
|
||||
|
@ -16,7 +16,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||
want string
|
||||
}{
|
||||
{ErrDuplicateBlock, "ErrDuplicateBlock"},
|
||||
{ErrBlockTooBig, "ErrBlockTooBig"},
|
||||
{ErrBlockMassTooHigh, "ErrBlockMassTooHigh"},
|
||||
{ErrBlockVersionTooOld, "ErrBlockVersionTooOld"},
|
||||
{ErrInvalidTime, "ErrInvalidTime"},
|
||||
{ErrTimeTooOld, "ErrTimeTooOld"},
|
||||
@ -31,7 +31,7 @@ func TestErrorCodeStringer(t *testing.T) {
|
||||
{ErrFinalityPointTimeTooOld, "ErrFinalityPointTimeTooOld"},
|
||||
{ErrNoTransactions, "ErrNoTransactions"},
|
||||
{ErrNoTxInputs, "ErrNoTxInputs"},
|
||||
{ErrTxTooBig, "ErrTxTooBig"},
|
||||
{ErrTxMassTooHigh, "ErrTxMassTooHigh"},
|
||||
{ErrBadTxOutValue, "ErrBadTxOutValue"},
|
||||
{ErrDuplicateTxInputs, "ErrDuplicateTxInputs"},
|
||||
{ErrBadTxInput, "ErrBadTxInput"},
|
||||
|
@ -1106,7 +1106,7 @@ func Generate(includeLargeReorg bool) (tests [][]TestInstance, err error) {
|
||||
replaceSpendScript(sizePadScript)(b)
|
||||
})
|
||||
g.assertTipBlockSize(maxBlockSize + 1)
|
||||
rejected(blockdag.ErrBlockTooBig)
|
||||
rejected(blockdag.ErrBlockMassTooHigh)
|
||||
|
||||
// Parent was rejected, so this block must either be an orphan or
|
||||
// outright rejected due to an invalid parent.
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
|
||||
const (
|
||||
// MaxSigOpsPerBlock is the maximum number of signature operations
|
||||
// allowed for a block. It is a fraction of the max block payload size.
|
||||
MaxSigOpsPerBlock = wire.MaxBlockPayload / 50
|
||||
// allowed for a block. It is a fraction of the max block transaction mass.
|
||||
MaxSigOpsPerBlock = wire.MaxMassPerBlock / 50
|
||||
|
||||
// MaxCoinbasePayloadLen is the maximum length a coinbase payload can be.
|
||||
MaxCoinbasePayloadLen = 150
|
||||
@ -29,6 +29,11 @@ const (
|
||||
// baseSubsidy is the starting subsidy amount for mined blocks. This
|
||||
// value is halved every SubsidyHalvingInterval blocks.
|
||||
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
|
||||
@ -121,13 +126,13 @@ func CheckTransactionSanity(tx *util.Tx, subnetworkID *subnetworkid.SubnetworkID
|
||||
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.
|
||||
serializedTxSize := msgTx.SerializeSize()
|
||||
if serializedTxSize > wire.MaxBlockPayload {
|
||||
if serializedTxSize > wire.MaxMassPerBlock {
|
||||
str := fmt.Sprintf("serialized transaction is too big - got "+
|
||||
"%d, max %d", serializedTxSize, wire.MaxBlockPayload)
|
||||
return ruleError(ErrTxTooBig, str)
|
||||
"%d, max %d", serializedTxSize, wire.MaxMassPerBlock)
|
||||
return ruleError(ErrTxMassTooHigh, str)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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
|
||||
// ensure it is sane before continuing with processing. These checks are
|
||||
// context free.
|
||||
@ -444,21 +529,12 @@ func (dag *BlockDAG) checkBlockSanity(block *util.Block, flags BehaviorFlags) (t
|
||||
"any transactions")
|
||||
}
|
||||
|
||||
// A block must not have more transactions than the max block payload or
|
||||
// else it is certainly over the block size limit.
|
||||
if numTx > wire.MaxBlockPayload {
|
||||
// A block must not have more transactions than the max block mass or
|
||||
// else it is certainly over the block mass limit.
|
||||
if numTx > wire.MaxMassPerBlock {
|
||||
str := fmt.Sprintf("block contains too many transactions - "+
|
||||
"got %d, max %d", numTx, wire.MaxBlockPayload)
|
||||
return 0, ruleError(ErrBlockTooBig, 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)
|
||||
"got %d, max %d", numTx, wire.MaxMassPerBlock)
|
||||
return 0, ruleError(ErrBlockMassTooHigh, str)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := validateBlockMass(pastUTXO, transactions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Perform several checks on the inputs for each transaction. Also
|
||||
|
@ -633,7 +633,7 @@ func TestCheckTransactionSanity(t *testing.T) {
|
||||
{"good one", 1, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, nil},
|
||||
{"no inputs", 0, 1, 1, *subnetworkid.SubnetworkIDNative, nil, nil, ruleError(ErrNoTxInputs, "")},
|
||||
{"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,
|
||||
*subnetworkid.SubnetworkIDNative,
|
||||
nil,
|
||||
|
@ -222,10 +222,10 @@ type TemplateRequest struct {
|
||||
// Optional long polling.
|
||||
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.
|
||||
SigOpLimit interface{} `json:"sigOpLimit,omitempty"`
|
||||
SizeLimit interface{} `json:"sizeLimit,omitempty"`
|
||||
MassLimit interface{} `json:"massLimit,omitempty"`
|
||||
MaxVersion uint32 `json:"maxVersion,omitempty"`
|
||||
|
||||
// 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
|
||||
// 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.
|
||||
func (t *TemplateRequest) UnmarshalJSON(data []byte) error {
|
||||
type templateRequest TemplateRequest
|
||||
@ -274,12 +274,12 @@ func (t *TemplateRequest) UnmarshalJSON(data []byte) error {
|
||||
}
|
||||
request.SigOpLimit = val
|
||||
|
||||
// The SizeLimit field can only be nil, bool, or int64.
|
||||
val, err = convertTemplateRequestField("sizeLimit", request.SizeLimit)
|
||||
// The MassLimit field can only be nil, bool, or int64.
|
||||
val, err = convertTemplateRequestField("massLimit", request.MassLimit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SizeLimit = val
|
||||
request.MassLimit = val
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -271,25 +271,25 @@ func TestDAGSvrCmds(t *testing.T) {
|
||||
{
|
||||
name: "getBlockTemplate optional - template request with tweaks",
|
||||
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{} {
|
||||
template := btcjson.TemplateRequest{
|
||||
Mode: "template",
|
||||
Capabilities: []string{"longPoll", "coinbaseTxn"},
|
||||
SigOpLimit: 500,
|
||||
SizeLimit: 100000000,
|
||||
MassLimit: 100000000,
|
||||
MaxVersion: 1,
|
||||
}
|
||||
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{
|
||||
Request: &btcjson.TemplateRequest{
|
||||
Mode: "template",
|
||||
Capabilities: []string{"longPoll", "coinbaseTxn"},
|
||||
SigOpLimit: int64(500),
|
||||
SizeLimit: int64(100000000),
|
||||
MassLimit: int64(100000000),
|
||||
MaxVersion: 1,
|
||||
},
|
||||
},
|
||||
@ -297,25 +297,25 @@ func TestDAGSvrCmds(t *testing.T) {
|
||||
{
|
||||
name: "getBlockTemplate optional - template request with tweaks 2",
|
||||
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{} {
|
||||
template := btcjson.TemplateRequest{
|
||||
Mode: "template",
|
||||
Capabilities: []string{"longPoll", "coinbaseTxn"},
|
||||
SigOpLimit: true,
|
||||
SizeLimit: 100000000,
|
||||
MassLimit: 100000000,
|
||||
MaxVersion: 1,
|
||||
}
|
||||
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{
|
||||
Request: &btcjson.TemplateRequest{
|
||||
Mode: "template",
|
||||
Capabilities: []string{"longPoll", "coinbaseTxn"},
|
||||
SigOpLimit: true,
|
||||
SizeLimit: int64(100000000),
|
||||
MassLimit: int64(100000000),
|
||||
MaxVersion: 1,
|
||||
},
|
||||
},
|
||||
@ -1152,9 +1152,9 @@ func TestDAGSvrCmdErrors(t *testing.T) {
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
{
|
||||
name: "invalid template request sizelimit field",
|
||||
name: "invalid template request masslimit field",
|
||||
result: &btcjson.TemplateRequest{},
|
||||
marshalled: `{"sizelimit":"invalid"}`,
|
||||
marshalled: `{"masslimit":"invalid"}`,
|
||||
err: btcjson.Error{ErrorCode: btcjson.ErrInvalidType},
|
||||
},
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ type GetBlockTemplateResultTx struct {
|
||||
Data string `json:"data"`
|
||||
ID string `json:"id"`
|
||||
Depends []int64 `json:"depends"`
|
||||
Mass uint64 `json:"mass"`
|
||||
Fee uint64 `json:"fee"`
|
||||
SigOps int64 `json:"sigOps"`
|
||||
}
|
||||
@ -141,7 +142,7 @@ type GetBlockTemplateResult struct {
|
||||
Height uint64 `json:"height"`
|
||||
ParentHashes []string `json:"parentHashes"`
|
||||
SigOpLimit int64 `json:"sigOpLimit,omitempty"`
|
||||
SizeLimit int64 `json:"sizeLimit,omitempty"`
|
||||
MassLimit int64 `json:"massLimit,omitempty"`
|
||||
Transactions []GetBlockTemplateResultTx `json:"transactions"`
|
||||
AcceptedIDMerkleRoot string `json:"acceptedIdMerkleRoot"`
|
||||
UTXOCommitment string `json:"utxoCommitment"`
|
||||
|
@ -69,10 +69,10 @@ func (bi *blockImporter) readBlock() ([]byte, error) {
|
||||
if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if blockLen > wire.MaxBlockPayload {
|
||||
if blockLen > wire.MaxMessagePayload {
|
||||
return nil, fmt.Errorf("block payload of %d bytes is larger "+
|
||||
"than the max allowed %d bytes", blockLen,
|
||||
wire.MaxBlockPayload)
|
||||
wire.MaxMessagePayload)
|
||||
}
|
||||
|
||||
serializedBlock := make([]byte, blockLen)
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"github.com/daglabs/btcd/util/network"
|
||||
"github.com/daglabs/btcd/util/subnetworkid"
|
||||
"github.com/daglabs/btcd/version"
|
||||
"github.com/daglabs/btcd/wire"
|
||||
"github.com/jessevdk/go-flags"
|
||||
)
|
||||
|
||||
@ -47,10 +46,9 @@ const (
|
||||
defaultMaxRPCWebsockets = 25
|
||||
defaultMaxRPCConcurrentReqs = 20
|
||||
defaultDbType = "ffldb"
|
||||
defaultBlockMinSize = 0
|
||||
defaultBlockMaxSize = 750000
|
||||
blockMaxSizeMin = 1000
|
||||
blockMaxSizeMax = wire.MaxBlockPayload - 1000
|
||||
defaultBlockMaxMass = 10000000
|
||||
blockMaxMassMin = 1000
|
||||
blockMaxMassMax = 10000000
|
||||
defaultGenerate = false
|
||||
defaultMaxOrphanTransactions = 100
|
||||
//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"`
|
||||
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"`
|
||||
BlockMinSize uint32 `long:"blockminsize" description:"Mininum block size in bytes to be used when creating a block"`
|
||||
BlockMaxSize uint32 `long:"blockmaxsize" description:"Maximum 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"`
|
||||
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"`
|
||||
EnableCFilters bool `long:"enablecfilters" description:"Enable committed filtering (CF) support"`
|
||||
@ -312,8 +309,7 @@ func loadConfig() (*Config, []string, error) {
|
||||
DbType: defaultDbType,
|
||||
RPCKey: defaultRPCKeyFile,
|
||||
RPCCert: defaultRPCCertFile,
|
||||
BlockMinSize: defaultBlockMinSize,
|
||||
BlockMaxSize: defaultBlockMaxSize,
|
||||
BlockMaxMass: defaultBlockMaxMass,
|
||||
MaxOrphanTxs: defaultMaxOrphanTransactions,
|
||||
SigCacheMaxSize: defaultSigCacheMaxSize,
|
||||
Generate: defaultGenerate,
|
||||
@ -659,14 +655,14 @@ func loadConfig() (*Config, []string, error) {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Limit the max block size to a sane value.
|
||||
if cfg.BlockMaxSize < blockMaxSizeMin || cfg.BlockMaxSize >
|
||||
blockMaxSizeMax {
|
||||
// Limit the max block mass to a sane value.
|
||||
if cfg.BlockMaxMass < blockMaxMassMin || cfg.BlockMaxMass >
|
||||
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]"
|
||||
err := fmt.Errorf(str, funcName, blockMaxSizeMin,
|
||||
blockMaxSizeMax, cfg.BlockMaxSize)
|
||||
err := fmt.Errorf(str, funcName, blockMaxMassMin,
|
||||
blockMaxMassMax, cfg.BlockMaxMass)
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
fmt.Fprintln(os.Stderr, usageMessage)
|
||||
return nil, nil, err
|
||||
@ -682,9 +678,6 @@ func loadConfig() (*Config, []string, error) {
|
||||
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.
|
||||
for _, uaComment := range cfg.UserAgentComments {
|
||||
if strings.ContainsAny(uaComment, "/:()") {
|
||||
|
@ -81,10 +81,10 @@ func (bi *blockImporter) readBlock() ([]byte, error) {
|
||||
if err := binary.Read(bi.r, binary.LittleEndian, &blockLen); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if blockLen > wire.MaxBlockPayload {
|
||||
if blockLen > wire.MaxMessagePayload {
|
||||
return nil, fmt.Errorf("block payload of %d bytes is larger "+
|
||||
"than the max allowed %d bytes", blockLen,
|
||||
wire.MaxBlockPayload)
|
||||
wire.MaxMessagePayload)
|
||||
}
|
||||
|
||||
serializedBlock := make([]byte, blockLen)
|
||||
|
@ -938,6 +938,16 @@ func (mp *TxPool) maybeAcceptTransaction(tx *util.Tx, isNew, rejectDupOrphans bo
|
||||
"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
|
||||
// rules in blockchain for what transactions are allowed into blocks.
|
||||
// Also returns the fees associated with the transaction which will be
|
||||
|
@ -162,6 +162,10 @@ type BlockTemplate struct {
|
||||
// requirement.
|
||||
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
|
||||
// template pays in base units. Since the first transaction is 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
|
||||
// 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
|
||||
// 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 | |
|
||||
// | until <= policy.TxMinFreeFee | |
|
||||
// | | |
|
||||
@ -310,6 +314,8 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
||||
defer g.dag.RUnlock()
|
||||
|
||||
nextBlockBlueScore := g.dag.VirtualBlueScore()
|
||||
nextBlockUTXO := g.dag.UTXOSet()
|
||||
|
||||
coinbasePayloadPkScript, err := txscript.PayToAddrScript(payToAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -328,6 +334,10 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
coinbaseTxMass, err := blockdag.CalcTxMass(coinbaseTx, nextBlockUTXO)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numCoinbaseSigOps := int64(blockdag.CountSigOps(coinbaseTx))
|
||||
|
||||
// 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 = append(blockTxns, coinbaseTx)
|
||||
|
||||
// The starting block size is the size of the block header plus the max
|
||||
// possible transaction count size, plus the size of the coinbase
|
||||
// transaction.
|
||||
blockSize := blockHeaderOverhead + uint32(coinbaseTx.MsgTx().SerializeSize())
|
||||
blockMass := coinbaseTxMass
|
||||
blockSigOps := numCoinbaseSigOps
|
||||
totalFees := uint64(0)
|
||||
|
||||
// Create slices to hold the fees and number of signature operations
|
||||
// for each of the selected transactions and add an entry for the
|
||||
// coinbase. This allows the code below to simply append details about
|
||||
// a transaction as it is selected for inclusion in the final block.
|
||||
// Create slices to hold the mass, the fees, and number of signature
|
||||
// operations for each of the selected transactions and add an entry for
|
||||
// the coinbase. This allows the code below to simply append details
|
||||
// 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
|
||||
// the coinbase fee which will be updated later.
|
||||
txMasses := make([]uint64, 0, len(sourceTxns)+1)
|
||||
txFees := make([]uint64, 0, len(sourceTxns)+1)
|
||||
txSigOpCounts := make([]int64, 0, len(sourceTxns)+1)
|
||||
txMasses = append(txMasses, coinbaseTxMass)
|
||||
txFees = append(txFees, 0) // For coinbase tx
|
||||
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
|
||||
|
||||
@ -423,18 +432,22 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
||||
gasUsageMap[subnetworkID] = gasUsage + txGas
|
||||
}
|
||||
|
||||
// Enforce maximum block size. Also check for overflow.
|
||||
txSize := uint32(tx.MsgTx().SerializeSize())
|
||||
blockPlusTxSize := blockSize + txSize
|
||||
if blockPlusTxSize < blockSize ||
|
||||
blockPlusTxSize >= g.policy.BlockMaxSize {
|
||||
|
||||
// Enforce maximum transaction mass per block. Also check
|
||||
// for overflow.
|
||||
txMass, err := blockdag.CalcTxMass(tx, g.dag.UTXOSet())
|
||||
if err != nil {
|
||||
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 "+
|
||||
"the max block size", tx.ID())
|
||||
"the max block mass", tx.ID())
|
||||
continue
|
||||
}
|
||||
|
||||
// Enforce maximum signature operations per block. Also check
|
||||
// Enforce maximum signature operations per block. Also check
|
||||
// for overflow.
|
||||
numSigOps := int64(blockdag.CountSigOps(tx))
|
||||
if blockSigOps+numSigOps < blockSigOps ||
|
||||
@ -476,12 +489,13 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
||||
}
|
||||
|
||||
// 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.
|
||||
blockTxns = append(blockTxns, tx)
|
||||
blockSize += txSize
|
||||
blockSigOps += int64(numSigOps)
|
||||
blockMass += txMass
|
||||
blockSigOps += numSigOps
|
||||
totalFees += prioItem.fee
|
||||
txMasses = append(txMasses, txMass)
|
||||
txFees = append(txFees, prioItem.fee)
|
||||
txSigOpCounts = append(txSigOpCounts, numSigOps)
|
||||
|
||||
@ -489,12 +503,6 @@ func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress util.Address) (*BlockTe
|
||||
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
|
||||
// is potentially adjusted to ensure it comes after the median time of
|
||||
// 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, "+
|
||||
"%d signature operations, %d bytes, target difficulty %064x)",
|
||||
len(msgBlock.Transactions), totalFees, blockSigOps, blockSize,
|
||||
"%d signature operations, %d mass, target difficulty %064x)",
|
||||
len(msgBlock.Transactions), totalFees, blockSigOps, blockMass,
|
||||
util.CompactToBig(msgBlock.Header.Bits))
|
||||
|
||||
return &BlockTemplate{
|
||||
Block: &msgBlock,
|
||||
TxMasses: txMasses,
|
||||
Fees: txFees,
|
||||
SigOpCounts: txSigOpCounts,
|
||||
ValidPayAddress: payToAddress != nil,
|
||||
|
@ -89,7 +89,7 @@ func TestNewBlockTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
policy := Policy{
|
||||
BlockMaxSize: 50000,
|
||||
BlockMaxMass: 50000,
|
||||
}
|
||||
|
||||
// First we create a block to have coinbase funds for the rest of the test.
|
||||
|
@ -8,11 +8,7 @@ package mining
|
||||
// the generation of block templates. See the documentation for
|
||||
// NewBlockTemplate for more details on each of these parameters are used.
|
||||
type Policy struct {
|
||||
// BlockMinSize is the minimum block size to be used when generating
|
||||
// a block template.
|
||||
BlockMinSize uint32
|
||||
|
||||
// BlockMaxSize is the maximum block size to be used when generating a
|
||||
// BlockMaxMass is the maximum block mass to be used when generating a
|
||||
// block template.
|
||||
BlockMaxSize uint32
|
||||
BlockMaxMass uint64
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func PrepareBlockForTest(dag *blockdag.BlockDAG, params *dagconfig.Params, paren
|
||||
oldVirtual := blockdag.SetVirtualForTest(dag, newVirtual)
|
||||
defer blockdag.SetVirtualForTest(dag, oldVirtual)
|
||||
policy := Policy{
|
||||
BlockMaxSize: 50000,
|
||||
BlockMaxMass: 50000,
|
||||
}
|
||||
|
||||
txSource := &fakeTxSource{
|
||||
|
@ -1761,6 +1761,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
|
||||
Data: hex.EncodeToString(txBuf.Bytes()),
|
||||
ID: txID.String(),
|
||||
Depends: depends,
|
||||
Mass: template.TxMasses[i],
|
||||
Fee: template.Fees[i],
|
||||
SigOps: template.SigOpCounts[i],
|
||||
}
|
||||
@ -1779,7 +1780,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
|
||||
Height: template.Height,
|
||||
ParentHashes: daghash.Strings(header.ParentHashes),
|
||||
SigOpLimit: blockdag.MaxSigOpsPerBlock,
|
||||
SizeLimit: wire.MaxBlockPayload,
|
||||
MassLimit: wire.MaxMassPerBlock,
|
||||
Transactions: transactions,
|
||||
AcceptedIDMerkleRoot: header.AcceptedIDMerkleRoot.String(),
|
||||
UTXOCommitment: header.UTXOCommitment.String(),
|
||||
@ -1822,6 +1823,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
|
||||
Data: hex.EncodeToString(txBuf.Bytes()),
|
||||
ID: tx.TxID().String(),
|
||||
Depends: []int64{},
|
||||
Mass: template.TxMasses[0],
|
||||
Fee: template.Fees[0],
|
||||
SigOps: template.SigOpCounts[0],
|
||||
}
|
||||
@ -2028,8 +2030,8 @@ func chainErrToGBTErrString(err error) string {
|
||||
switch ruleErr.ErrorCode {
|
||||
case blockdag.ErrDuplicateBlock:
|
||||
return "duplicate"
|
||||
case blockdag.ErrBlockTooBig:
|
||||
return "bad-blk-length"
|
||||
case blockdag.ErrBlockMassTooHigh:
|
||||
return "bad-blk-mass"
|
||||
case blockdag.ErrBlockVersionTooOld:
|
||||
return "bad-version"
|
||||
case blockdag.ErrInvalidTime:
|
||||
@ -2054,8 +2056,8 @@ func chainErrToGBTErrString(err error) string {
|
||||
return "bad-txns-none"
|
||||
case blockdag.ErrNoTxInputs:
|
||||
return "bad-txns-noinputs"
|
||||
case blockdag.ErrTxTooBig:
|
||||
return "bad-txns-size"
|
||||
case blockdag.ErrTxMassTooHigh:
|
||||
return "bad-txns-mass"
|
||||
case blockdag.ErrBadTxOutValue:
|
||||
return "bad-txns-outputvalue"
|
||||
case blockdag.ErrDuplicateTxInputs:
|
||||
|
@ -283,7 +283,7 @@ var helpDescsEnUS = map[string]string{
|
||||
"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-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-target": "The desired target for the block template (this parameter is ignored)",
|
||||
"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-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-mass": "Total mass of all transactions in the block",
|
||||
"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",
|
||||
|
||||
@ -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-height": "Height of the block to be solved",
|
||||
"getBlockTemplateResult-parentHashes": "Hex-encoded big-endian hashes of the parent blocks",
|
||||
"getBlockTemplateResult-sigOpLimit": "Number of sigops allowed in blocks ",
|
||||
"getBlockTemplateResult-sizeLimit": "Number of bytes allowed in blocks",
|
||||
"getBlockTemplateResult-sigOpLimit": "Number of sigops allowed in blocks",
|
||||
"getBlockTemplateResult-massLimit": "Max transaction mass allowed in blocks",
|
||||
"getBlockTemplateResult-transactions": "Array of transactions as JSON objects",
|
||||
"getBlockTemplateResult-acceptedIdMerkleRoot": "The root of the merkle tree of transaction IDs accepted by this block",
|
||||
"getBlockTemplateResult-utxoCommitment": "An ECMH UTXO commitment of this block",
|
||||
|
@ -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
|
||||
// created before calling the function to create the CPU miner.
|
||||
policy := mining.Policy{
|
||||
BlockMinSize: cfg.BlockMinSize,
|
||||
BlockMaxSize: cfg.BlockMaxSize,
|
||||
BlockMaxMass: cfg.BlockMaxMass,
|
||||
}
|
||||
blockTemplateGenerator := mining.NewBlkTmplGenerator(&policy,
|
||||
s.p2pServer.DAGParams, s.p2pServer.TxMemPool, s.p2pServer.DAG, s.p2pServer.TimeSource, s.p2pServer.SigCache)
|
||||
|
@ -21,12 +21,12 @@ import (
|
||||
// backing array multiple times.
|
||||
const defaultTransactionAlloc = 2048
|
||||
|
||||
// MaxBlockPayload is the maximum bytes a block message can be in bytes.
|
||||
const MaxBlockPayload = 1000000
|
||||
// maxMassPerBlock is the maximum total transaction mass a block may contain.
|
||||
const MaxMassPerBlock = 10000000
|
||||
|
||||
// maxTxPerBlock is the maximum number of transactions that could
|
||||
// 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
|
||||
// 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
|
||||
// receiver. This is part of the Message interface implementation.
|
||||
func (msg *MsgBlock) MaxPayloadLength(pver uint32) uint32 {
|
||||
// Block header at 80 bytes + transaction count + max transactions
|
||||
// which can vary up to the MaxBlockPayload (including the block header
|
||||
// and transaction count).
|
||||
return MaxBlockPayload
|
||||
return MaxMessagePayload
|
||||
}
|
||||
|
||||
// BlockHash computes the block identifier hash for this block.
|
||||
|
@ -40,8 +40,7 @@ func TestBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure max payload is expected value for latest protocol version.
|
||||
// Num addresses (varInt) + max allowed addresses.
|
||||
wantPayload := uint32(1000000)
|
||||
wantPayload := uint32(1024 * 1024 * 32)
|
||||
maxPayload := msg.MaxPayloadLength(pver)
|
||||
if maxPayload != wantPayload {
|
||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||
|
@ -133,7 +133,7 @@ func (msg *MsgMerkleBlock) Command() string {
|
||||
// MaxPayloadLength returns the maximum length the payload can be for the
|
||||
// receiver. This is part of the Message interface implementation.
|
||||
func (msg *MsgMerkleBlock) MaxPayloadLength(pver uint32) uint32 {
|
||||
return MaxBlockPayload
|
||||
return MaxMessagePayload
|
||||
}
|
||||
|
||||
// NewMsgMerkleBlock returns a new bitcoin merkleblock message that conforms to
|
||||
|
@ -38,8 +38,7 @@ func TestMerkleBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure max payload is expected value for latest protocol version.
|
||||
// Num addresses (varInt) + max allowed addresses.
|
||||
wantPayload := uint32(1000000)
|
||||
wantPayload := uint32(1024 * 1024 * 32)
|
||||
maxPayload := msg.MaxPayloadLength(pver)
|
||||
if maxPayload != wantPayload {
|
||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||
|
@ -765,7 +765,7 @@ func (msg *MsgTx) Command() string {
|
||||
// MaxPayloadLength returns the maximum length the payload can be for the
|
||||
// receiver. This is part of the Message interface implementation.
|
||||
func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 {
|
||||
return MaxBlockPayload
|
||||
return MaxMessagePayload
|
||||
}
|
||||
|
||||
// PkScriptLocs returns a slice containing the start of each public key script
|
||||
|
@ -37,7 +37,7 @@ func TestTx(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure max payload is expected value for latest protocol version.
|
||||
wantPayload := uint32(1000 * 1000)
|
||||
wantPayload := uint32(1024 * 1024 * 32)
|
||||
maxPayload := msg.MaxPayloadLength(pver)
|
||||
if maxPayload != wantPayload {
|
||||
t.Errorf("MaxPayloadLength: wrong max payload length for "+
|
||||
|
Loading…
x
Reference in New Issue
Block a user