-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathgenerate-tx.py
116 lines (89 loc) · 3.33 KB
/
generate-tx.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
# Note - to use this script you need Jeff Garzik's python-bitcoinrpc
# https://github.com/jgarzik/python-bitcoinrpc
import os
import sys;
import json;
from bitcoinrpc.authproxy import AuthServiceProxy;
# SET THESE VALUES
rpc_user = "bitcoinrpc";
rpc_pass = "A7Xr149i7F6GxkhDbxWDTbmXooz1UZGhhyUYvaajA13Z";
rpc_host = "localhost";
rpc_port = 8332;
donation_minimum = 0;
donation_per_input = 3000;
donation_address = "1ForFeesAndDonationsSpendHerdtWbWy";
# http://stackoverflow.com/questions/626796/how-do-i-find-the-windows-common-application-data-folder-using-python
try:
from win32com.shell import shellcon, shell
config_file = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) + "/Bitcoin/bitcoin.conf"
except ImportError: # quick semi-nasty fallback for non-windows/win32com case
config_file = os.path.expanduser("~") + "/.bitcoin/bitcoin.conf"
# thanks ryan-c for this function
def asp_from_config(filename):
rpcport = '8332'
rpcconn = '127.0.0.1'
rpcuser = None
rpcpass = None
with open(filename, 'r') as f:
for line in f:
try:
(key, val) = line.rstrip().replace(' ', '').split('=')
except:
(key, val) = ("", "");
if key == 'rpcuser':
rpcuser = val
elif key == 'rpcpassword':
rpcpass = val
elif key == 'rpcport':
rpcport = val
elif key == 'rpcconnect':
rpcconn = val
f.close()
if rpcuser is not None and rpcpass is not None:
rpcurl = 'http://%s:%s@%s:%s' % (rpcuser, rpcpass, rpcconn, rpcport)
print('RPC server: %s' % rpcurl)
return AuthServiceProxy(rpcurl)
def to_satoshi(s):
return int (100000000 * float (s));
def from_satoshi(s):
return float (s) / 100000000;
if len(sys.argv) < 3:
print ("Usage: %s <input size> <target output size in BTC>" % sys.argv[0]);
exit (0);
#service = AuthServiceProxy ("http://%s:%s@%s:%d" % (rpc_user, rpc_pass, rpc_host, rpc_port));
service = asp_from_config (config_file);
balance = to_satoshi (service.getbalance());
unspent = service.listunspent();
target_in = to_satoshi (sys.argv[1]);
target_out = to_satoshi (sys.argv[2]);
if balance < target_in:
print ("Cannot spend %f; only have %f in wallet." % (from_satoshi (target_in), from_satoshi (balance)));
exit (0);
if target_out > target_in:
print ("Please have a smaller target output than input value.");
exit (0);
# FIND INPUTS
# TODO: have a smarter coin selection algo
# For now we just sort the coins by increasing abs(value - target output), then select in order
inputs = [];
donation = 0;
total_in = 0;
unspent.sort (key=lambda coin: abs(to_satoshi (coin['amount']) - target_in));
for coin in unspent:
total_in += to_satoshi (coin['amount']);
donation += donation_per_input;
inputs.append (dict (txid = coin['txid'], vout = coin['vout']));
if total_in > target_in:
break;
if donation < donation_minimum:
donation = donation_minimum;
# FIND OUTPUTS
outputs = dict ();
outputs[donation_address] = from_satoshi (donation);
total_in -= donation;
while total_in > target_out:
outputs[service.getnewaddress()] = from_satoshi (target_out);
total_in -= target_out;
outputs[service.getnewaddress()] = from_satoshi (total_in);
# Make the transaction
print service.createrawtransaction (inputs, outputs);