lnwallet: Add TxWeightEstimator support for nested pay-to-witness.

This commit is contained in:
Jim Posen 2017-10-02 19:57:22 -07:00 committed by Olaoluwa Osuntokun
parent c94130328a
commit 3232fd71c2
2 changed files with 117 additions and 19 deletions

View File

@ -19,6 +19,12 @@ const (
// WitnessSize - witness size (bytes).
// Weight - the metric for determining the weight of the transaction.
// P2WPKHSize 22 bytes
// - OP_0: 1 byte
// - OP_DATA: 1 byte (PublicKeyHASH160 length)
// - PublicKeyHASH160: 20 bytes
P2WPKHSize = 1 + 1 + 20
// P2WSHSize 34 bytes
// - OP_0: 1 byte
// - OP_DATA: 1 byte (WitnessScriptSHA256 length)
@ -35,19 +41,19 @@ const (
// - value: 8 bytes
// - var_int: 1 byte (pkscript_length)
// - pkscript (p2wpkh): 22 bytes
P2WKHOutputSize = 8 + 1 + 22
P2WKHOutputSize = 8 + 1 + P2WPKHSize
// P2WSHOutputSize 43 bytes
// - value: 8 bytes
// - var_int: 1 byte (pkscript_length)
// - pkscript (p2wsh): 34 bytes
P2WSHOutputSize = 8 + 1 + 34
P2WSHOutputSize = 8 + 1 + P2WSHSize
// P2WPKHSize 22 bytes
// - OP_0: 1 byte
// - OP_DATA: 1 byte (PublicKeyHASH160 length)
// - PublicKeyHASH160: 20 bytes
P2WPKHSize = 1 + 1 + 20
// P2SHOutputSize 32 bytes
// - value: 8 bytes
// - var_int: 1 byte (pkscript_length)
// - pkscript (p2sh): 23 bytes
P2SHOutputSize = 8 + 1 + 23
// P2PKHScriptSigSize 108 bytes
// - OP_DATA: 1 byte (signature length)
@ -337,14 +343,14 @@ func (twe *TxWeightEstimator) AddP2PKHInput() {
}
// AddP2WKHInput updates the weight estimate to account for an additional input
// spending a P2PWKH output.
// spending a native P2PWKH output.
func (twe *TxWeightEstimator) AddP2WKHInput() {
twe.AddWitnessInput(P2WKHWitnessSize)
}
// AddWitnessInput updates the weight estimate to account for an additional
// input spending a pay-to-witness output. This accepts the total size of the
// witness as a parameter.
// input spending a native pay-to-witness output. This accepts the total size
// of the witness as a parameter.
func (twe *TxWeightEstimator) AddWitnessInput(witnessSize int) {
twe.inputSize += InputSize
twe.inputWitnessSize += witnessSize
@ -352,6 +358,24 @@ func (twe *TxWeightEstimator) AddWitnessInput(witnessSize int) {
twe.hasWitness = true
}
// AddNestedP2WKHInput updates the weight estimate to account for an additional
// input spending a P2SH output with a nested P2WKH redeem script.
func (twe *TxWeightEstimator) AddNestedP2WKHInput() {
twe.inputSize += InputSize + P2WPKHSize
twe.inputWitnessSize += P2WKHWitnessSize
twe.inputSize++
twe.hasWitness = true
}
// AddNestedP2WSHInput updates the weight estimate to account for an additional
// input spending a P2SH output with a nested P2WSH redeem script.
func (twe *TxWeightEstimator) AddNestedP2WSHInput(witnessSize int) {
twe.inputSize += InputSize + P2WSHSize
twe.inputWitnessSize += witnessSize
twe.inputSize++
twe.hasWitness = true
}
// AddP2PKHOutput updates the weight estimate to account for an additional P2PKH
// output.
func (twe *TxWeightEstimator) AddP2PKHOutput() {
@ -359,20 +383,27 @@ func (twe *TxWeightEstimator) AddP2PKHOutput() {
twe.outputCount++
}
// AddP2WKHOutput updates the weight estimate to account for an additional P2WKH
// output.
// AddP2WKHOutput updates the weight estimate to account for an additional
// native P2WKH output.
func (twe *TxWeightEstimator) AddP2WKHOutput() {
twe.outputSize += P2WKHOutputSize
twe.outputCount++
}
// AddP2WSHOutput updates the weight estimate to account for an additional P2WSH
// output.
// AddP2WSHOutput updates the weight estimate to account for an additional
// native P2WSH output.
func (twe *TxWeightEstimator) AddP2WSHOutput() {
twe.outputSize += P2WSHOutputSize
twe.outputCount++
}
// AddP2SHOutput updates the weight estimate to account for an additional P2SH
// output.
func (twe *TxWeightEstimator) AddP2SHOutput() {
twe.outputSize += P2SHOutputSize
twe.outputCount++
}
// Weight gets the estimated weight of the transaction.
func (twe *TxWeightEstimator) Weight() int {
txSizeStripped := BaseTxSize +

View File

@ -47,12 +47,25 @@ func TestTxWeightEstimator(t *testing.T) {
t.Fatalf("Failed to generate scriptPubKey: %v", err)
}
p2shAddr, err := btcutil.NewAddressScriptHash([]byte{0}, netParams)
if err != nil {
t.Fatalf("Failed to generate address: %v", err)
}
p2shScript, err := txscript.PayToAddrScript(p2shAddr)
if err != nil {
t.Fatalf("Failed to generate scriptPubKey: %v", err)
}
testCases := []struct {
numP2PKHInputs int
numP2WKHInputs int
numP2PKHOutputs int
numP2WKHOutputs int
numP2WSHOutputs int
numP2PKHInputs int
numP2WKHInputs int
numP2WSHInputs int
numNestedP2WKHInputs int
numNestedP2WSHInputs int
numP2PKHOutputs int
numP2WKHOutputs int
numP2WSHOutputs int
numP2SHOutputs int
}{
{
numP2PKHInputs: 1,
@ -74,6 +87,22 @@ func TestTxWeightEstimator(t *testing.T) {
numP2WKHOutputs: 1,
numP2WSHOutputs: 1,
},
{
numP2WSHInputs: 1,
numP2WKHOutputs: 1,
},
{
numP2PKHInputs: 1,
numP2SHOutputs: 1,
},
{
numNestedP2WKHInputs: 1,
numP2WKHOutputs: 1,
},
{
numNestedP2WSHInputs: 1,
numP2WKHOutputs: 1,
},
}
for i, test := range testCases {
@ -101,6 +130,40 @@ func TestTxWeightEstimator(t *testing.T) {
witness := wire.TxWitness{signature, compressedPubKey}
tx.AddTxIn(&wire.TxIn{Witness: witness})
}
for j := 0; j < test.numP2WSHInputs; j++ {
weightEstimate.AddWitnessInput(42)
witnessScript := make([]byte, 40)
witness := wire.TxWitness{witnessScript}
tx.AddTxIn(&wire.TxIn{Witness: witness})
}
for j := 0; j < test.numNestedP2WKHInputs; j++ {
weightEstimate.AddNestedP2WKHInput()
signature := make([]byte, 73)
compressedPubKey := make([]byte, 33)
witness := wire.TxWitness{signature, compressedPubKey}
scriptSig, err := txscript.NewScriptBuilder().AddData(p2wkhScript).
Script()
if err != nil {
t.Fatalf("Failed to generate scriptSig: %v", err)
}
tx.AddTxIn(&wire.TxIn{SignatureScript: scriptSig, Witness: witness})
}
for j := 0; j < test.numNestedP2WSHInputs; j++ {
weightEstimate.AddNestedP2WSHInput(42)
witnessScript := make([]byte, 40)
witness := wire.TxWitness{witnessScript}
scriptSig, err := txscript.NewScriptBuilder().AddData(p2wshScript).
Script()
if err != nil {
t.Fatalf("Failed to generate scriptSig: %v", err)
}
tx.AddTxIn(&wire.TxIn{SignatureScript: scriptSig, Witness: witness})
}
for j := 0; j < test.numP2PKHOutputs; j++ {
weightEstimate.AddP2PKHOutput()
tx.AddTxOut(&wire.TxOut{PkScript: p2pkhScript})
@ -113,6 +176,10 @@ func TestTxWeightEstimator(t *testing.T) {
weightEstimate.AddP2WSHOutput()
tx.AddTxOut(&wire.TxOut{PkScript: p2wshScript})
}
for j := 0; j < test.numP2SHOutputs; j++ {
weightEstimate.AddP2SHOutput()
tx.AddTxOut(&wire.TxOut{PkScript: p2shScript})
}
expectedWeight := blockchain.GetTransactionWeight(btcutil.NewTx(tx))
if weightEstimate.Weight() != int(expectedWeight) {