f084802fec
This began as a change to improve the fee calculation code and evolved into a much larger refactor which improves the readability and modularity of all of the transaction creation code. Transaction fee calculations have been switched from full increments of the relay fee to a proportion based on the transaction size. This means that for a relay fee of 1e3 satoshis/kB, a 500 byte transaction is only required to pay a 5e2 satoshi fee and a 1500 byte transaction only need pay a 1.5e3 fee. The previous code would end up estimating these fees to be 1e3 and 2e3 respectively. Because the previous code would add more fee than needed in almost every case, the transaction size estimations were optimistic (best/smallest case) and signing was done in a loop where the fee was incremented by the relay fee again each time the actual size of the signed transaction rendered the fee too low. This has switched to using worst case transaction size estimates rather than best case, and signing is only performed once. Transaction input signature creation has switched from using txscript.SignatureScript to txscript.SignTxOutput. The new API is able to redeem outputs other than just P2PKH, so the previous restrictions about P2SH outputs being unspendable (except through the signrawtransaction RPC) no longer hold. Several new public packages have been added: wallet/txauthor - transaction authoring and signing wallet/txfees - fee estimations and change output inclusion wallet/txrules - simple consensus and mempool policy rule checks Along with some internal packages: wallet/internal/txsizes - transaction size estimation internal/helpers - context free convenience functions The txsizes package is internal as the estimations it provides are specific for the algorithms used by these new packages.
92 lines
3.2 KiB
Go
92 lines
3.2 KiB
Go
// Copyright (c) 2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package txrules provides transaction rules that should be followed by
|
|
// transaction authors for wide mempool acceptance and quick mining.
|
|
package txrules
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btcutil"
|
|
)
|
|
|
|
// DefaultRelayFeePerKb is the default minimum relay fee policy for a mempool.
|
|
const DefaultRelayFeePerKb btcutil.Amount = 1e3
|
|
|
|
// IsDustAmount determines whether a transaction output value and script length would
|
|
// cause the output to be considered dust. Transactions with dust outputs are
|
|
// not standard and are rejected by mempools with default policies.
|
|
func IsDustAmount(amount btcutil.Amount, scriptSize int, relayFeePerKb btcutil.Amount) bool {
|
|
// Calculate the total (estimated) cost to the network. This is
|
|
// calculated using the serialize size of the output plus the serial
|
|
// size of a transaction input which redeems it. The output is assumed
|
|
// to be compressed P2PKH as this is the most common script type. Use
|
|
// the average size of a compressed P2PKH redeem input (148) rather than
|
|
// the largest possible (txsizes.RedeemP2PKHInputSize).
|
|
totalSize := 8 + wire.VarIntSerializeSize(uint64(scriptSize)) +
|
|
scriptSize + 148
|
|
|
|
// Dust is defined as an output value where the total cost to the network
|
|
// (output size + input size) is greater than 1/3 of the relay fee.
|
|
return int64(amount)*1000/(3*int64(totalSize)) < int64(relayFeePerKb)
|
|
}
|
|
|
|
// IsDustOutput determines whether a transaction output is considered dust.
|
|
// Transactions with dust outputs are not standard and are rejected by mempools
|
|
// with default policies.
|
|
func IsDustOutput(output *wire.TxOut, relayFeePerKb btcutil.Amount) bool {
|
|
// Unspendable outputs which solely carry data are not checked for dust.
|
|
if txscript.GetScriptClass(output.PkScript) == txscript.NullDataTy {
|
|
return false
|
|
}
|
|
|
|
// All other unspendable outputs are considered dust.
|
|
if txscript.IsUnspendable(output.PkScript) {
|
|
return true
|
|
}
|
|
|
|
return IsDustAmount(btcutil.Amount(output.Value), len(output.PkScript),
|
|
relayFeePerKb)
|
|
}
|
|
|
|
// Transaction rule violations
|
|
var (
|
|
ErrAmountNegative = errors.New("transaction output amount is negative")
|
|
ErrAmountExceedsMax = errors.New("transaction output amount exceeds maximum value")
|
|
ErrOutputIsDust = errors.New("transaction output is dust")
|
|
)
|
|
|
|
// CheckOutput performs simple consensus and policy tests on a transaction
|
|
// output.
|
|
func CheckOutput(output *wire.TxOut, relayFeePerKb btcutil.Amount) error {
|
|
if output.Value < 0 {
|
|
return ErrAmountNegative
|
|
}
|
|
if output.Value > btcutil.MaxSatoshi {
|
|
return ErrAmountExceedsMax
|
|
}
|
|
if IsDustOutput(output, relayFeePerKb) {
|
|
return ErrOutputIsDust
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FeeForSerializeSize calculates the required fee for a transaction of some
|
|
// arbitrary size given a mempool's relay fee policy.
|
|
func FeeForSerializeSize(relayFeePerKb btcutil.Amount, txSerializeSize int) btcutil.Amount {
|
|
fee := relayFeePerKb * btcutil.Amount(txSerializeSize) / 1000
|
|
|
|
if fee == 0 && relayFeePerKb > 0 {
|
|
fee = relayFeePerKb
|
|
}
|
|
|
|
if fee < 0 || fee > btcutil.MaxSatoshi {
|
|
fee = btcutil.MaxSatoshi
|
|
}
|
|
|
|
return fee
|
|
}
|