wallet/size: add EstimateVirtualSize
This commit adds a new method EstimateVirtualSize that calculates the worst case estimate vsize for a transaction with a given set of inputs and outputs. This method is aware of P2PKH, P2WPKH and P2SH-P2WPKH inputs, and caulculates the transaction vsize with the witness data included.
This commit is contained in:
parent
2bd4130581
commit
f782f9dc68
1 changed files with 109 additions and 1 deletions
|
@ -5,6 +5,7 @@
|
|||
package txsizes
|
||||
|
||||
import (
|
||||
"github.com/roasbeef/btcd/blockchain"
|
||||
"github.com/roasbeef/btcd/wire"
|
||||
|
||||
h "github.com/roasbeef/btcwallet/internal/helpers"
|
||||
|
@ -52,7 +53,69 @@ const (
|
|||
// - 25 bytes P2PKH output script
|
||||
P2PKHOutputSize = 8 + 1 + P2PKHPkScriptSize
|
||||
|
||||
// TODO(roasbeef): add estimates for nested p2wkh and p2pkh
|
||||
// P2WPKHPkScriptSize is the size of a transaction output script that
|
||||
// pays to a witness pubkey hash. It is calculated as:
|
||||
//
|
||||
// - OP_0
|
||||
// - OP_DATA_20
|
||||
// - 20 bytes pubkey hash
|
||||
P2WPKHPkScriptSize = 1 + 1 + 20
|
||||
|
||||
// P2WPKHOutputSize is the serialize size of a transaction output with a
|
||||
// P2WPKH output script. It is calculated as:
|
||||
//
|
||||
// - 8 bytes output value
|
||||
// - 1 byte compact int encoding value 22
|
||||
// - 22 bytes P2PKH output script
|
||||
P2WPKHOutputSize = 8 + 1 + P2WPKHPkScriptSize
|
||||
|
||||
// RedeemP2WPKHScriptSize is the size of a transaction input script
|
||||
// that spends a pay-to-witness-public-key hash (P2WPKH). The redeem
|
||||
// script for P2WPKH spends MUST be empty.
|
||||
RedeemP2WPKHScriptSize = 0
|
||||
|
||||
// RedeemP2WPKHInputSize is the worst case size of a transaction
|
||||
// input redeeming a P2WPKH output. It is calculated as:
|
||||
//
|
||||
// - 32 bytes previous tx
|
||||
// - 4 bytes output index
|
||||
// - 1 byte encoding empty redeem script
|
||||
// - 0 bytes redeem script
|
||||
// - 4 bytes sequence
|
||||
RedeemP2WPKHInputSize = 32 + 4 + 1 + RedeemP2WPKHScriptSize + 4
|
||||
|
||||
// RedeemNestedP2WPKHScriptSize is the worst case size of a transaction
|
||||
// input script that redeems a pay-to-witness-key hash nested in P2SH
|
||||
// (P2SH-P2WPKH). It is calculated as:
|
||||
//
|
||||
// - 1 byte compact int encoding value 22
|
||||
// - OP_0
|
||||
// - 1 byte compact int encoding value 20
|
||||
// - 20 byte key hash
|
||||
RedeemNestedP2WPKHScriptSize = 1 + 1 + 1 + 20
|
||||
|
||||
// RedeemNestedP2WPKHInputSize is the worst case size of a
|
||||
// transaction input redeeming a P2SH-P2WPKH output. It is
|
||||
// calculated as:
|
||||
//
|
||||
// - 32 bytes previous tx
|
||||
// - 4 bytes output index
|
||||
// - 1 byte compact int encoding value 23
|
||||
// - 23 bytes redeem script (scriptSig)
|
||||
// - 4 bytes sequence
|
||||
RedeemNestedP2WPKHInputSize = 32 + 4 + 1 +
|
||||
RedeemNestedP2WPKHScriptSize + 4
|
||||
|
||||
// RedeemP2WPKHInputWitnessWeight is the worst case weight of
|
||||
// a witness for spending P2WPKH and nested P2WPKH outputs. It
|
||||
// is calculated as:
|
||||
//
|
||||
// - 1 wu compact int encoding value 2 (number of items)
|
||||
// - 1 wu compact int encoding value 73
|
||||
// - 72 wu DER signature + 1 wu sighash
|
||||
// - 1 wu compact int encoding value 33
|
||||
// - 33 wu serialized compressed pubkey
|
||||
RedeemP2WPKHInputWitnessWeight = 1 + 1 + 73 + 1 + 33
|
||||
)
|
||||
|
||||
// EstimateSerializeSize returns a worst case serialize size estimate for a
|
||||
|
@ -74,3 +137,48 @@ func EstimateSerializeSize(inputCount int, txOuts []*wire.TxOut, addChangeOutput
|
|||
h.SumOutputSerializeSizes(txOuts) +
|
||||
changeSize
|
||||
}
|
||||
|
||||
// EstimateVirtualSize returns a worst case virtual size estimate for a
|
||||
// signed transaction that spends the given number of P2PKH, P2WPKH and
|
||||
// (nested) P2SH-P2WPKH outputs, and contains each transaction output
|
||||
// from txOuts. The estimate is incremented for an additional P2PKH
|
||||
// change output if addChangeOutput is true.
|
||||
func EstimateVirtualSize(numP2PKHIns, numP2WPKHIns, numNestedP2WPKHIns int,
|
||||
txOuts []*wire.TxOut, addChangeOutput bool) int {
|
||||
changeSize := 0
|
||||
outputCount := len(txOuts)
|
||||
if addChangeOutput {
|
||||
// We are always using P2WPKH as change output.
|
||||
changeSize = P2WPKHOutputSize
|
||||
outputCount++
|
||||
}
|
||||
|
||||
// Version 4 bytes + LockTime 4 bytes + Serialized var int size for the
|
||||
// number of transaction inputs and outputs + size of redeem scripts +
|
||||
// the size out the serialized outputs and change.
|
||||
baseSize := 8 +
|
||||
wire.VarIntSerializeSize(
|
||||
uint64(numP2PKHIns+numP2WPKHIns+numNestedP2WPKHIns)) +
|
||||
wire.VarIntSerializeSize(uint64(len(txOuts))) +
|
||||
numP2PKHIns*RedeemP2PKHInputSize +
|
||||
numP2WPKHIns*RedeemP2WPKHInputSize +
|
||||
numNestedP2WPKHIns*RedeemNestedP2WPKHInputSize +
|
||||
h.SumOutputSerializeSizes(txOuts) +
|
||||
changeSize
|
||||
|
||||
// If this transaction has any witness inputs, we must count the
|
||||
// witness data.
|
||||
witnessWeight := 0
|
||||
if numP2WPKHIns+numNestedP2WPKHIns > 0 {
|
||||
// Additional 2 weight units for segwit marker + flag.
|
||||
witnessWeight = 2 +
|
||||
wire.VarIntSerializeSize(
|
||||
uint64(numP2WPKHIns+numNestedP2WPKHIns)) +
|
||||
numP2WPKHIns*RedeemP2WPKHInputWitnessWeight +
|
||||
numNestedP2WPKHIns*RedeemP2WPKHInputWitnessWeight
|
||||
}
|
||||
|
||||
// We add 3 to the witness weight to make sure the result is
|
||||
// always rounded up.
|
||||
return baseSize + (witnessWeight+3)/blockchain.WitnessScaleFactor
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue