Created
April 25, 2014 01:36
-
-
Save dexX7/11275285 to your computer and use it in GitHub Desktop.
Display transactions which send Bitcoin to a specific address
We can make this file beautiful and searchable if this error is corrected: No commas found in this CSV file in line 0.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
blocktime;blockheight;position;txid;vout;amount;sender | |
1398115251;297047;94;70ddc412ccae8c8c1659e71597f3971240b0e03d195799ed83235e2f52a3cf25;0;0.007;13KQXZwHFk3DCqDZG45qqaJzn6uuJPGAZS | |
1398155998;297117;1;b8ef7515dd6d29243f544766876934216e302e78732f44df9e5fef4cbc0739bc;1;15;186y2sHKTzmTaAvbM543Vqw9zw9dtaneiN | |
1398155998;297117;18;a165174f5876eb43bf5ef0c6961d99420979fc7919eda9863dea9745ae33fac9;0;118;1DjAmmS6iSg5Xe6wYz37CAMAdvGTQoijiK | |
1398155998;297117;24;e489cad48a8473f496bbcb17a503118a682804a90a11a06304e9b004d8b66310;0;6.3;1EB6Nm4JmS7mbeJ8Yv7bycbMDvgpWq9uvN | |
1398155998;297117;36;cf54e2b39f28e2cf12bce49db8de81c32584ab5aab00a14f39f5580eccf65409;0;1;1KJwKxZ4U8PnaoGgGBTBZZ4GkM3ACyL3oq | |
... | |
Full data: | |
http://www.bitwatch.co/msc/1KHfLixa2idRnZXMUfEisBati1vpywaH6E.csv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{ | |
"sender": "13KQXZwHFk3DCqDZG45qqaJzn6uuJPGAZS", | |
"vout": 0, | |
"txid": "70ddc412ccae8c8c1659e71597f3971240b0e03d195799ed83235e2f52a3cf25", | |
"blocktime": 1398115251, | |
"amount": 0.007, | |
"blockheight": 297047, | |
"position": 94 | |
}, { | |
"sender": "186y2sHKTzmTaAvbM543Vqw9zw9dtaneiN", | |
"vout": 1, | |
"txid": "b8ef7515dd6d29243f544766876934216e302e78732f44df9e5fef4cbc0739bc", | |
"blocktime": 1398155998, | |
"amount": 15, | |
"blockheight": 297117, | |
"position": 1 | |
}, { | |
"sender": "1DjAmmS6iSg5Xe6wYz37CAMAdvGTQoijiK", | |
"vout": 0, | |
"txid": "a165174f5876eb43bf5ef0c6961d99420979fc7919eda9863dea9745ae33fac9", | |
"blocktime": 1398155998, | |
"amount": 118, | |
"blockheight": 297117, | |
"position": 18 | |
}, {... | |
}] | |
Full data: | |
http://www.bitwatch.co/msc/1KHfLixa2idRnZXMUfEisBati1vpywaH6E.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import hashlib | |
import json | |
import requests | |
import sys | |
from bitcoinrpc.authproxy import AuthServiceProxy | |
from decimal import Decimal | |
###################################################### | |
# | |
# this tool can be used to fetch all relevant | |
# transaction data related to a specific address, | |
# e.g. show bitcoin nominated maidsafecoin sales | |
# | |
# a valid rpc connection to bitcoind is required | |
# | |
# rpc options: | |
# - rpc username and password needs to be set | |
# | |
# user options: | |
# - define the address to look up | |
# - set output mode: csv or json | |
# - use rpc call "listtransactions" or | |
# http://api.bitwatch.co/listtransactions to | |
# fetch transaction data | |
# | |
## | |
# rpc connection options - action required | |
## | |
RPC_USERNAME = 'rpcusername' | |
RPC_PASSWORD = 'rpcpassword' | |
RPC_CONNECT = '127.0.0.1' | |
RPC_PORT = 8332 | |
## | |
# user options - action required | |
## | |
OPT_ADDRESS = '1KHfLixa2idRnZXMUfEisBati1vpywaH6E' | |
OPT_OUTPUT = 'CSV' # 'JSON' | |
OPT_MODE = 'API' # 'RPC' | |
# | |
###################################################### | |
## | |
# rpc connection related | |
## | |
rpc_client = AuthServiceProxy('http://%s:%s@%s:%s' \ | |
% (RPC_USERNAME, RPC_PASSWORD, RPC_CONNECT, RPC_PORT)) | |
def check_rpc_connection(): | |
try: | |
test = rpc_client.getinfo() | |
return True | |
except: | |
return False | |
def get_raw_transaction(txid): | |
try: | |
txinfo = rpc_client.getrawtransaction(txid, 1) | |
return txinfo | |
except Exception: | |
print 'could not get raw transaction for '+txid | |
return None | |
def get_received_transactions_rpc(address): | |
received = [] | |
try: | |
received = rpc_client.listreceivedbyaddress() | |
except Exception: | |
print 'could not get received transactions' | |
return [] | |
for tx_block in received: | |
if 'address' in tx_block \ | |
and 'txids' in tx_block \ | |
and tx_block['address'] == address: | |
for txid in tx_block['txids']: | |
tx = get_raw_transaction(txid) | |
if tx <> None: | |
received.append(tx) | |
return received | |
## | |
# web api related | |
## | |
def get_all_transactions(address, count = 99999): | |
response = requests.get('http://api.bitwatch.co/listtransactions/' \ | |
+address+'?verbose=1&count='+str(count)).json() | |
if 'status' in response and response['status'] == 200: | |
return response['result'] | |
else: | |
return [] | |
## | |
# convert public key to public key hash | |
## | |
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' | |
__b58base = len(__b58chars) | |
def base58_encode(v): | |
v = v.decode('hex') | |
long_value = 0L | |
for (i, c) in enumerate(v[::-1]): | |
long_value += (256**i) * ord(c) | |
result = '' | |
while long_value >= __b58base: | |
div, mod = divmod(long_value, __b58base) | |
result = __b58chars[mod] + result | |
long_value = div | |
result = __b58chars[long_value] + result | |
nPad = 0 | |
for c in v: | |
if c == '\0': | |
nPad += 1 | |
else: | |
break | |
return (__b58chars[0] * nPad) + result | |
def get_sha256(string): | |
return hashlib.sha256(string.decode('hex')).hexdigest() | |
def get_hash160(string): | |
h = hashlib.new('ripemd160') | |
h.update(string.decode('hex')) | |
return h.hexdigest() | |
def hash_160_to_bc_address(h160): | |
vh160 = '00' + h160 | |
h3 = get_sha256(get_sha256(vh160)) | |
checksum = h3[0:8] | |
addr = vh160 + checksum | |
b58 = base58_encode(addr) | |
return b58 | |
def get_pubkeyhash(pubkey): | |
sha = get_sha256(pubkey) | |
hash160 = get_hash160(sha) | |
b58 = hash_160_to_bc_address(hash160) | |
return b58 | |
## | |
# core transaction processing | |
## | |
def get_transactions_to(tx, address): | |
outputs = [] | |
amount = 0.0 | |
if 'txid' in tx \ | |
and 'vout' in tx: | |
for vout in tx['vout']: | |
if 'value' in vout \ | |
and 'scriptPubKey' in vout \ | |
and 'type' in vout['scriptPubKey'] \ | |
and 'addresses' in vout['scriptPubKey'] \ | |
and vout['scriptPubKey']['type'] == 'pubkeyhash' \ | |
and address in vout['scriptPubKey']['addresses']: | |
spend = { 'txid': tx['txid'], \ | |
'vout': vout['n'], \ | |
'amount': vout['value'] } | |
if 'blocktime' in tx: | |
spend['blocktime'] = tx['blocktime'] | |
if 'blockheight' in tx: | |
spend['blockheight'] = tx['blockheight'] | |
if 'position' in tx: | |
spend['position'] = tx['position'] | |
outputs.append(spend) | |
if len(outputs) > 0: | |
sender = get_input(tx) | |
for output in outputs: | |
output['sender'] = sender | |
return outputs | |
def extract_input_pubkey(vin): | |
if 'scriptSig' in vin \ | |
and 'asm' in vin['scriptSig']: | |
asm = vin['scriptSig']['asm'].split(' ') | |
if len(asm) == 2 and asm[0].startswith('304'): | |
return asm[1] | |
return None | |
def extract_highest_input(tx): | |
pubkey = None | |
if 'vin' in tx: | |
for vin in tx['vin']: | |
pk = extract_input_pubkey(vin) | |
if pk <> None: | |
if pubkey is None: | |
pubkey = pk | |
if pk <> pubkey: | |
return None | |
if pubkey is None: | |
return None | |
return get_pubkeyhash(pubkey) | |
def fetch_output(txid, n): | |
tx = get_raw_transaction(txid) | |
if 'vout' in tx \ | |
and len(tx['vout']) >= n: | |
return tx['vout'][n] | |
return None | |
def fetch_input_amount(vin): | |
if 'txid' in vin \ | |
and 'vout' in vin: | |
prev_output = fetch_output(vin['txid'], vin['vout']) | |
if prev_output <> None \ | |
and 'value' in prev_output: | |
return prev_output['value'] | |
return Decimal() | |
def get_input(tx): | |
pubkeyhash = extract_highest_input(tx) | |
if pubkeyhash <> None: | |
return pubkeyhash | |
pubkeys = {} | |
highest_pubkey = None | |
highest_amount = Decimal() | |
if 'vin' in tx: | |
for vin in tx['vin']: | |
pk = extract_input_pubkey(vin) | |
if pk is None: | |
continue | |
if not pubkeys.has_key(pk): | |
pubkeys[pk] = Decimal() | |
amount = fetch_input_amount(vin) | |
pubkeys[pk] += amount | |
if pubkeys[pk] > highest_amount: | |
highest_amount = pubkeys[pk] | |
highest_pubkey = pk | |
if highest_pubkey <> None: | |
pubkeyhash = get_pubkeyhash(highest_pubkey) | |
return pubkeyhash | |
def get_relevant_transactions(address): | |
if OPT_MODE == 'RPC': | |
txs = get_received_transactions_rpc(address) | |
else: | |
txs = get_all_transactions(address) | |
all_outputs = [] | |
for tx in txs: | |
all_outputs += get_transactions_to(tx, address) | |
return all_outputs | |
## | |
# output related | |
## | |
def get_relevant_transactions_csv(address): | |
all_outputs = get_relevant_transactions(address) | |
for output in all_outputs: | |
line = '' | |
if 'blocktime' in output: | |
line += str(output['blocktime']) + ';' | |
if 'blockheight' in output: | |
line += str(output['blockheight']) + ';' | |
if 'position' in output: | |
line += str(output['position']) + ';' | |
if 'txid' in output: | |
line += str(output['txid']) + ';' | |
if 'vout' in output: | |
line += str(output['vout']) + ';' | |
if 'amount' in output: | |
line += str(output['amount']) + ';' | |
if 'sender' in output: | |
line += str(output['sender']) | |
print line | |
def get_relevant_transactions_json(address): | |
all_outputs = get_relevant_transactions(address) | |
print json.dumps(all_outputs) | |
## | |
# start program | |
## | |
if __name__ == '__main__': | |
if not check_rpc_connection(): | |
print 'rpc connection to bitcoind can not be established' | |
exit() | |
if OPT_OUTPUT == 'JSON': | |
get_relevant_transactions_json(OPT_ADDRESS) | |
else: | |
get_relevant_transactions_csv(OPT_ADDRESS) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment