// isDust returns whether or not the passed transaction output amount is // considered dust or not based on the passed minimum transaction relay fee. // Dust is defined in terms of the minimum transaction 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, minRelayTxFee dcrutil.Amount) 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. // // Pay-to-pubkey-hash bytes breakdown: // // Output to hash (38 bytes): // 2 script version, 8 value, 1 script len, 25 script // [1 OP_DUP, 1 OP_HASH_160, 1 OP_DATA_20, 20 hash, // 1 OP_EQUALVERIFY, 1 OP_CHECKSIG] // // Input with compressed pubkey (165 bytes): // 37 prev outpoint, 16 fraud proof, 1 script len, // 107 script [1 OP_DATA_72, 72 sig, 1 OP_DATA_33, // 33 compressed pubkey], 4 sequence // // Input with uncompressed pubkey (198 bytes): // 37 prev outpoint, 16 fraud proof, 1 script len, // 139 script [1 OP_DATA_72, 72 sig, 1 OP_DATA_65, // 65 compressed pubkey], 4 sequence, 1 witness // append // // Pay-to-pubkey bytes breakdown: // // Output to compressed pubkey (46 bytes): // 2 script version, 8 value, 1 script len, 35 script // [1 OP_DATA_33, 33 compressed pubkey, 1 OP_CHECKSIG] // // Output to uncompressed pubkey (76 bytes): // 2 script version, 8 value, 1 script len, 67 script // [1 OP_DATA_65, 65 pubkey, 1 OP_CHECKSIG] // // Input (133 bytes): // 37 prev outpoint, 16 fraud proof, 1 script len, 73 // script [1 OP_DATA_72, 72 sig], 4 sequence, 1 witness // append // // Theoretically this could examine the script type of the output script // and use a different size for the typical input script size for // pay-to-pubkey vs pay-to-pubkey-hash inputs per the above breakdowns, // but the only combinination which is less than the value chosen is // a pay-to-pubkey script with a compressed pubkey, which is not very // common. // // The most common scripts are pay-to-pubkey-hash, and as per the above // breakdown, the minimum size of a p2pkh input script is 165 bytes. So // that figure is used. totalSize := txOut.SerializeSize() + 165 // The output is considered dust if the cost to the network to spend the // coins is more than 1/3 of the minimum free transaction relay fee. // minFreeTxRelayFee is in Atom/KB, so multiply by 1000 to // convert to bytes. // // Using the typical values for a pay-to-pubkey-hash transaction from // the breakdown above and the default minimum free transaction relay // fee of 5000000, this equates to values less than 546 atoms being // considered dust. // // The following is equivalent to (value/totalSize) * (1/3) * 1000 // without needing to do floating point math. return txOut.Value*1000/(3*int64(totalSize)) < int64(minRelayTxFee) }
// TestCalcSignatureHash does some rudimentary testing of msg hash calculation. func TestCalcSignatureHash(t *testing.T) { tx := new(wire.MsgTx) for i := 0; i < 3; i++ { txIn := new(wire.TxIn) txIn.Sequence = 0xFFFFFFFF txIn.PreviousOutPoint.Hash = chainhash.HashFuncH([]byte{byte(i)}) txIn.PreviousOutPoint.Index = uint32(i) txIn.PreviousOutPoint.Tree = int8(0) tx.AddTxIn(txIn) } for i := 0; i < 2; i++ { txOut := new(wire.TxOut) txOut.PkScript = []byte{0x01, 0x01, 0x02, 0x03} txOut.Value = 0x0000FF00FF00FF00 tx.AddTxOut(txOut) } want, _ := hex.DecodeString("d09285b6f60c71329323bc2e76c48" + "a462cde4e1032aa8f59c55823f1722c7f4a") pops, _ := txscript.TstParseScript([]byte{0x01, 0x01, 0x02, 0x03}) // Test prefix caching. msg1, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 0, nil) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } prefixHash := tx.TxSha() msg2, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 0, &prefixHash) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } if !bytes.Equal(msg1, want) { t.Errorf("for sighash all sig noncached wrong msg %x given, want %x", msg1, want) } if !bytes.Equal(msg2, want) { t.Errorf("for sighash all sig cached wrong msg %x given, want %x", msg1, want) } if !bytes.Equal(msg1, msg2) { t.Errorf("for sighash all sig non-equivalent msgs %x and %x were "+ "returned when using a cached prefix", msg1, msg2) } // Move the index and make sure that we get a whole new hash, despite // using the same TxOuts. msg3, err := txscript.CalcSignatureHash(pops, txscript.SigHashAll, tx, 1, &prefixHash) if err != nil { t.Fatalf("unexpected error %v", err.Error()) } if bytes.Equal(msg1, msg3) { t.Errorf("for sighash all sig equivalent msgs %x and %x were "+ "returned when using a cached prefix but different indices", msg1, msg3) } }