Last active
January 26, 2018 06:54
-
-
Save h4x3rotab/fc5e16f98429f7eebe39de904977aa5b to your computer and use it in GitHub Desktop.
Analysis of stolen coins from a miner's wallet
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
import decimal | |
import requests | |
# load all related transactions | |
target = 'GRTi7YMuJvMFJbcbp8a4YnjKTZ6UJBpGJA' | |
rsps = [requests.get('http://explorer.bitcoingold.org/insight-api/txs/?address=%s&pageNum=%d' | |
% (target, i)) for i in range(8)] # 8 pages in total. got it manually | |
all_data = [resp.json() for resp in rsps] | |
txes = [tx for data in all_data for tx in data['txs']] | |
# check the delta for transactions | |
def outputs(tx): | |
send = [vin for vin in tx['vin'] if vin['addr'] == target] | |
recv = [vout for vout in tx['vout'] if vout['scriptPubKey']['addresses'][0] == target] | |
return send, recv | |
btc_sat = decimal.Decimal('1e8') | |
for tx in txes: | |
send, recv = outputs(tx) | |
total_send = sum(decimal.Decimal(vout['valueSat']) / btc_sat for vout in send) | |
total_recv = sum(decimal.Decimal(vout['value']) for vout in recv) | |
balance = total_recv - total_send | |
print(tx['blockheight'], tx['txid'], total_recv, total_send) | |
if balance > 0: | |
print('recv:', balance) | |
elif balance < 0: | |
print('send:', -balance) | |
else: | |
print('nothing happens') | |
''' | |
Finding 1 | |
Sometimes a set of addresses received the exact same amount of money from somebody twice in a single | |
block: | |
- 505858 5c3cb806a19a679777140faa5b4e71a5da00799ab366f07db5deb7cef4c8be0d 0.01746099 0 | |
- 505858 6250d96c346fcf735e929076ae060df756672fd81d204522b7f085a2b6e8b7a3 0.01746099 0 | |
- 505828 574bc146fdf74c51672fbfdff208fc9b72f866e834ccc1388f42ec28e3313645 0.01230015 0 | |
- 505828 fd96c2fb9517471019013b6f6f54df68a55e1c9deaf864eda1b17e90f4192a22 0.01230015 0 | |
- 505099 e11db19d7ac936dc18244774512431b68c0e731ff24aa41f52848204f9559d29 0.01813379 0 | |
- 505099 7613baaa46490a75703cb46dae46e1066e3809b1fb34fa0609fe9531e54e0977 0.01813379 0 | |
- 505025 46fbde2b7f0704b7275ec60205833ff50112cb94f12d6a04eb0aa10e30289089 0.01224912 0 | |
- 505025 8810880d79e8bdf589a850baf2bf23785df6e231af930c47c4dac0cbf2b8edb3 0.01224912 0 | |
The inputs are not same but the outputs the the two txes are exact the same. Coincidence? | |
After some check, I confirmed all the transactions are from GWViUY2b3HAYWY9BbeGeFjc6rKdrBffzHa, | |
which should belong to pool.gold. | |
Finding 2 | |
Someone spent the incoming utxo right after he saw it from the mempool (tx from pool): | |
- 506710 8e5df7a991a1af820ff898328eebecab4e6139fd930375c735f1c06899aab19f 0 0.01479572 | |
- 506710 368b2dd019ba5c7a9fe56ce6c2b425ee9bac7e564f33e27bedf1689b30b845ca 0.01479572 0 | |
- 506688 50860f07c2f9a6f6f2ea16f04cf76adaf7b292efc623305ad97e59277b5260fd 0 0.01100774 | |
- 506688 199d8f657218722e59da190e9020bceabdb44bf9136d90bec609713c4e521514 0.01100774 0 | |
- 506671 ebe9f6709d37bb85bdb08d0c79eb8d44e73cc0976aec719c93030593e58cc8a6 0 0.01373011 | |
- 506671 503cc50f0817fa7972a41f702019fa139740f1907eac391ce4b328140834dc20 0.01373011 0 | |
- 506620 5739ee01fc03323e218297fa182c08b6ed8a103169980f1a875560b16bb89658 0 0.01383092 | |
- 506620 b1035e314bea092a780d17407fd83079ed8b0875ef2187a7765b033d42405d9a 0.01383092 0 | |
- 506542 2df89bd54b8fb940623c3c4e08ebb61388833a8a107f85c16b96b2a4303d6507 0 0.01121386 | |
- 506542 e90c6531f4615eb222de9f60d2532fc39a1e79ef702258fed873cabcf2bf10db 0.01121386 0 | |
Earlier withdraws have a bit delay: | |
- 506529 25906c6c2fea5f889b8204c0422c117ba6d457981d57e24cbd72d974849b3282 0 0.01264837 | |
- 506515 30259462cdb25ca352f71d60a94ffd32b1553f3151b22a28fcd84d2f0341d04a 0.01264837 0 | |
- 506458 f423d7eab2f336a4abc453dfbd92eb26d7a31d2bf72bb83bf33c698eaf6d259c 0 0.01335401 | |
- 506414 29307743cc86ce263c18c5873ae903ac9318ee1ec64997d21dad8dc38a48f71a 0.01335401 0 | |
First sweep: | |
- 506148 f5260eb0a23b6d77c4ecb477234bfc6dc28ea6fa2a85800232db471d5770dbe9 0 0.72877034 | |
''' | |
# check if any input is coinbase | |
for tx in txes: | |
send, recv = outputs(tx) | |
if recv: | |
assert 'coinbase' not in tx['vin'][0] | |
''' | |
All the inputs are not coinbase. | |
''' | |
# check output of the sweeps | |
for tx in txes: | |
send, recv = outputs(tx) | |
if send: | |
if len(tx['vout']) != 1: | |
print(tx) | |
continue | |
assert len(tx['vout'][0]['scriptPubKey']['addresses']) == 1 | |
addr = tx['vout'][0]['scriptPubKey']['addresses'][0] | |
print(tx['blockheight'], tx['txid'], addr) | |
''' | |
Except the first sweep, all the coins goes to the same wallet: GezU4t9Nq4893SrGT8FLT5keZoJPYoeqcP | |
The first sweep is: | |
-> GNpj941c1JprsWjbBTcWTbhNuxfcJ54a1W: 0.72 | |
-> GNpj941c1JprsWjbBTcWTbhNuxfcJ54a1W: 0.00868393 | |
-> GVsEunZckaBqN6vYrftMXH758UjrsRqMb8: 0.71131378 | |
=> GezU4t9Nq4893SrGT8FLT5keZoJPYoeqcP | |
-> GWUrTF6eVNyon9d2FHmwsua3cgTZYBfMBE 0.00868393 BTG (S) | |
-> GezU4t9Nq4893SrGT8FLT5keZoJPYoeqcP | |
''' | |
# check the input of 2df89bd54b8fb940623c3c4e08ebb61388833a8a107f85c16b96b2a4303d6507 | |
tx1 = [tx for tx in txes | |
if tx['txid'] == '2df89bd54b8fb940623c3c4e08ebb61388833a8a107f85c16b96b2a4303d6507'][0] | |
txid2 = tx1['vin'][0]['txid'] | |
tx2 = requests.get('https://explorer.bitcoingold.org/insight-api/tx/%s' % txid2).json() | |
txid_coinbase = tx2['vin'][0]['txid'] | |
tx_coinbase = requests.get('https://explorer.bitcoingold.org/insight-api/tx/%s' | |
% txid_coinbase).json() | |
print('tx block:', tx1['blockheight']) | |
print('coinbase:', tx_coinbase['blockheight']) | |
print(tx_coinbase['vin']) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment