-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathdust-b-gone.py
executable file
·138 lines (105 loc) · 3.94 KB
/
dust-b-gone.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/python
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from __future__ import absolute_import, division, print_function, unicode_literals
import argparse
import binascii
import getpass
import socket
import socks
import sys
import bitcoin
import bitcoin.rpc
from bitcoin.core import COIN, b2x, str_money_value, CTxIn, CTxOut, CTransaction
from bitcoin.core.script import CScript, OP_RETURN
parser = argparse.ArgumentParser(description='Get rid of dust in your wallet')
parser.add_argument('--dust', type=float,
default=0.0001,
help='Value considered to be a dust output.')
parser.add_argument('--dry-run', action='store_true',
help='Stop before actually getting rid of any dust')
parser.add_argument('--connect', type=str,
default='dust-b-gone.bitcoin.petertodd.org:80',
help='address:port to connect to to send the dust')
parser.add_argument('--testnet', action='store_true',
help='Use testnet rather than mainnet')
parser.add_argument('--tor', action='store_true',
help='connect via local tor proxy (127.0.0.1:9050)')
args = parser.parse_args()
args.dust = int(args.dust * COIN)
addr, port = args.connect.split(':')
args.address = (str(addr), int(port))
if args.testnet:
bitcoin.SelectParams('testnet')
proxy = bitcoin.rpc.Proxy()
dust_txouts = [unspent for unspent in proxy.listunspent(0) if unspent['amount'] <= args.dust]
sum_dust_after_fees = 0
for dust_txout in dust_txouts:
sum_dust_after_fees += max(dust_txout['amount'] - 1480, 0)
if not dust_txouts:
print("Your wallet doesn't have any dust in it!")
sys.exit(0)
print('You have %d dust txouts, worth %s BTC after fees.' % (
(len(dust_txouts), str_money_value(sum_dust_after_fees))))
print()
print('Get rid of them? y/n: ', end='')
# Fix Python 2.x.
try: input = raw_input
except NameError: pass
choice = input().lower().strip()
if choice != 'y':
print('Canceled!')
sys.exit(1)
# User gave the ok, create a NONE|ANYONECANPAY tx spending those txouts
txins = [CTxIn(dust_txout['outpoint'], nSequence=0) for dust_txout in dust_txouts]
txouts = [CTxOut(0, CScript([OP_RETURN]))]
tx = CTransaction(txins, txouts)
r = None
try:
r = proxy.signrawtransaction(tx, [], None, 'NONE|ANYONECANPAY')
except bitcoin.rpc.JSONRPCException as exp:
if exp.error['code'] == -13:
pwd = getpass.getpass('Please enter the wallet passphrase with walletpassphrase first: ')
proxy.walletpassphrase(pwd, 10)
r = proxy.signrawtransaction(tx, [], None, 'NONE|ANYONECANPAY')
else:
raise exp
if not r['complete']:
print("Error! Couldn't sign transaction:")
print(b2x(r['tx'].serialize()))
sys.exit(1)
signed_tx = r['tx']
# Do a sanity check on the transaction
sum_value_discarded = 0
for txin in signed_tx.vin:
r = proxy.gettxout(txin.prevout)
sum_value_discarded += r['txout'].nValue
# Abort if the amount is excessively large
if sum_value_discarded > 0.01*COIN:
print('Aborting due to excessively large value being discarded. (>0.01 BTC)')
sys.exit(1)
if args.dry_run:
print('Done:\n')
print(b2x(signed_tx.serialize()))
sys.exit(0)
# Monkey-patch in socks proxy support if required for tor
if args.tor:
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, "127.0.0.1", 9050)
socket.socket = socks.socksocket
def create_connection(address, timeout=None, source_address=None):
sock = socks.socksocket()
sock.connect(address)
return sock
socket.create_connection = create_connection
try:
sock = socket.create_connection(args.address)
sock.send(binascii.hexlify(signed_tx.serialize()))
sock.send(b'\n')
sock.close()
except socket.error as err:
print()
print("Failed to connect to dust-b-gone server: %s" % err.strerror)
sys.exit(1)
# lock txouts discarded
proxy.lockunspent(False, [txin.prevout for txin in signed_tx.vin])
print('Done!')