txscript: New function IsUnspendable

IsUnspendable takes a public key script and returns whether it is
spendable.

Additionally, hook this into the mempool isDust function, since
unspendable outputs can't be spent.

This mimics Bitcoin Core commit 0aad1f13b2430165062bf9436036c1222a8724da
This commit is contained in:
David Hill 2015-08-01 10:43:06 -04:00
parent b448a2b6bc
commit 3331d6098b
3 changed files with 52 additions and 0 deletions

View file

@ -107,6 +107,11 @@ type txMemPool struct {
// relay fee. In particular, if the cost to the network to spend coins is more
// than 1/3 of the minimum transaction relay fee, it is considered dust.
func isDust(txOut *wire.TxOut) bool {
// Unspendable outputs are considered dust.
if txscript.IsUnspendable(txOut.PkScript) {
return true
}
// The total serialized size consists of the output and the associated
// input script to redeem it. Since there is no input script
// to redeem it yet, use the minimum size of a typical input script.

View file

@ -458,3 +458,15 @@ func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) int {
shPops, _ := parseScript(shScript)
return getSigOpCount(shPops, true)
}
// IsUnspendable returns whether the passed public key script is unspendable, or
// guaranteed to fail at execution. This allows inputs to be pruned instantly
// when entering the UTXO set.
func IsUnspendable(pkScript []byte) bool {
pops, err := parseScript(pkScript)
if err != nil {
return true
}
return len(pops) > 0 && pops[0].opcode.value == OP_RETURN
}

View file

@ -486,3 +486,38 @@ func TestIsPushOnlyScript(t *testing.T) {
"%v", test.name, true, test.expected)
}
}
// TestIsUnspendable ensures the IsUnspendable function returns the expected
// results.
func TestIsUnspendable(t *testing.T) {
t.Parallel()
tests := []struct {
name string
pkScript []byte
expected bool
}{
{
// Unspendable
pkScript: []byte{0x6a, 0x04, 0x74, 0x65, 0x73, 0x74},
expected: true,
},
{
// Spendable
pkScript: []byte{0x76, 0xa9, 0x14, 0x29, 0x95, 0xa0,
0xfe, 0x68, 0x43, 0xfa, 0x9b, 0x95, 0x45,
0x97, 0xf0, 0xdc, 0xa7, 0xa4, 0x4d, 0xf6,
0xfa, 0x0b, 0x5c, 0x88, 0xac},
expected: false,
},
}
for i, test := range tests {
res := txscript.IsUnspendable(test.pkScript)
if res != test.expected {
t.Errorf("TestIsUnspendable #%d failed: got %v want %v",
i, res, test.expected)
continue
}
}
}