Bitcoin Forum
December 08, 2016, 02:25:12 PM *
News: Latest stable version of Bitcoin Core: 0.13.1  [Torrent].
 
   Home   Help Search Donate Login Register  
Pages: [1]
  Print  
Author Topic: Aggregating addresses to wallets (using armoryengine)  (Read 897 times)
Sukrim
Legendary
*
Offline Offline

Activity: 1848


View Profile
July 04, 2012, 10:59:53 AM
 #1

Since there's currently a lot of fuzz about pirateat40's operations (is it a ponzi? is it legit? where does he get his coins from/back, if he really sells them OTC? how is GPUMax fitting in?), I think one of the best ways to analyze the situation is to get an address that surely belongs to him, hope for combined inputs if he sends something from that address, assume these belong to him as well (as he'd need to have private keys for that) and work our way from there until we have all linked addresses to a single bitcoin address.
Also something like this might also be useful for other purposes and I haven't found many projects concerning this (one would be toolongdidntread.com)...

After that, we can assume this as his wallet and check the balance, money flows etc. (which is currently a bit beyond what I did so far).

The first problem I ran into however is:
Is my code so far really correct? I don't want to make accusations or draw conclusions when it turns out that I included an MtGox address out of stupidity...

Anyways, here's the code to track any address (supplied in the "trackaddr" list) for multiple inputs. It will iterate over the whole blockchain multiple times until no more new inputs are found. Because of recent blockchain spam, I limited it currently to block 160000 (enough for the address I have so far) and there's probably a nicer way than running ~10 times over the whole chain. I have a fast CPU however, so it doesn't really bother me atm, the bigger concern is if it is really doing what it's supposed to do and has no chance of picking up and including some random other addresses.

Code (with Armory's donation address up to block 170000):
Code:
from armoryengine import *

BDM_LoadBlockchainFile()

topBlock = TheBDM.getTopBlockHeight()

trackaddr = ['1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX']
taintedblocks = []

addratstart = len(trackaddr)
addratend = 0

iterations = 0
transactioncount = 0

while addratstart != addratend:
  transactioncount = 0
  iterations += 1
  addratstart = len(trackaddr)
  for h in xrange(0, 170000): #topBlock+1):
    if h%10000 == 0:
      print '\tScanned %d blocks' % h
      print 'Found %d addresses so far.' % len(trackaddr)
    
    header = TheBDM.getHeaderByHeight(h)
    txList = header.getTxRefPtrList()
    for tx in txList:
      foundaddr = False
      for nin in range(tx.getNumTxIn()):
        txin = tx.getTxInRef(nin)
        try:
          senderAddr20 = TheBDM.getSenderAddr20(txin)
          address = hash160_to_addrStr(senderAddr20)
          #print address
          if address in trackaddr:
            foundaddr = True
            print "FOUND TRANSACTION! At block " + str (h)
        except:
          pass
      if foundaddr is True:
        for nin in range(tx.getNumTxIn()):
          txin = tx.getTxInRef(nin)
          try:
            senderAddr20 = TheBDM.getSenderAddr20(txin)
            address = hash160_to_addrStr(senderAddr20)
            trackaddr.append(address)
          except:
            pass
        trackaddr = list(set(trackaddr))
        transactioncount += 1
        taintedblocks.append(h)
        taintedblocks = list(set(taintedblocks))
  addratend = len(trackaddr)

print trackaddr
print taintedblocks
print "Went through the blockchain %d times!" % iterations
print "Found %d transactions" % transactioncount
print "Found %d blocks where these transactions were included" % len(taintedblocks)
print "Found %d addresses" % addratend

Oh, and I won't post any results (it's easy with armory to include all found addresses to a "wallet" for example and read the spendable balance of that at each block) publicly or in PMs until I have verified this code to be correct! Also pirate seems to be quite paranoid about posting bitcoin addresses belonging to him, so good luck with finding some (unless you're a customer at BTCS&T, then you can of course use your deposit address).

Edit:
I was using armory 0.76 rc1 - the current 0.81 version throws:
Code:
Traceback (most recent call last):
  File "!findwallet.py", line 29, in <module>
    for nin in range(tx.getNumTxIn()):
  File "xxxxxxxxx\Armory_0_81\CppBlockUtils.py"
, line 813, in <lambda>
    __getattr__ = lambda self, name: _swig_getattr(self, TxRef, name)
  File "xxxxxxxxx\Armory_0_81\CppBlockUtils.py"
, line 51, in _swig_getattr
    raise AttributeError(name)
AttributeError: getNumTxIn

https://bitfinex.com <-- leveraged trading of BTCUSD, LTCUSD and LTCBTC (long and short) - 10% discount on fees for the first 30 days with this refcode: x5K9YtL3Zb
Mail me at Bitmessage: BM-BbiHiVv5qh858ULsyRDtpRrG9WjXN3xf
1481207112
Hero Member
*
Offline Offline

Posts: 1481207112

View Profile Personal Message (Offline)

Ignore
1481207112
Reply with quote  #2

1481207112
Report to moderator
1481207112
Hero Member
*
Offline Offline

Posts: 1481207112

View Profile Personal Message (Offline)

Ignore
1481207112
Reply with quote  #2

1481207112
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1481207112
Hero Member
*
Offline Offline

Posts: 1481207112

View Profile Personal Message (Offline)

Ignore
1481207112
Reply with quote  #2

1481207112
Report to moderator
1481207112
Hero Member
*
Offline Offline

Posts: 1481207112

View Profile Personal Message (Offline)

Ignore
1481207112
Reply with quote  #2

1481207112
Report to moderator
etotheipi
Legendary
*
expert
Offline Offline

Activity: 1428


Core Armory Developer


View Profile WWW
July 05, 2012, 06:52:57 PM
 #2

Version 0.80 was a reworking of the underlying blockchain engine, whereby I had to change some of the interfaces slightly to be more scalable.  As such, "TxRef" objects are mainly just pointers to blk000X.dat file locations.  All the methods are now part of "Tx" objects which are copies of the tx-data.   As such, the following code needs to change

FROM

Quote

    txList = header.getTxRefPtrList()
    for tx in txList:
      foundaddr = False
      for nin in range(tx.getNumTxIn()):
      ...


TO


Quote

    txList = header.getTxRefPtrList()
    for txref in txList:
      tx = txref.getTxCopy()
      foundaddr = False
      for nin in range(tx.getNumTxIn()):
      ...


And I notice you are tracking my address in your example...

Founder and CEO of Armory Technologies, Inc.
Armory Bitcoin Wallet: Bringing cold storage to the average user!
Only use Armory software signed by the Armory Offline Signing Key (0x98832223)

Please donate to the Armory project by clicking here!    (or donate directly via 1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX -- yes, it's a real address!)
Sukrim
Legendary
*
Offline Offline

Activity: 1848


View Profile
July 05, 2012, 11:17:57 PM
 #3

Thanks for the help, I changed the script now a little bit to the following (runs now with armory 0.81):
Code:
from armoryengine import *

BDM_LoadBlockchainFile()

topBlock = TheBDM.getTopBlockHeight()

trackaddr = dict({'pirateat40 GPUMAX':['1PSf86KnLuzM7Ris5kDhTEZwooR3p2iyfV'],
                  'Armory Client Developer':['1QBDLYTDFHHZAABYSKGKPWKLSXZWCCJQBX']})

addratstart = 0
for item in trackaddr.itervalues():
     addratstart += len(item)

addratend = 0

iterations = 0

while addratstart != addratend:
  iterations += 1
  addratstart = 0
  for item in trackaddr.itervalues():
     addratstart += len(item)
  for h in xrange(0, topBlock+1):
    if h%5000 == 0:
      print '\tScanned %d blocks' % h
   
    header = TheBDM.getHeaderByHeight(h)
    txList = header.getTxRefPtrList()
    for txref in txList:
      tx = txref.getTxCopy()
      foundaddr = False
      addressowner = ''
      for nin in range(tx.getNumTxIn()):
        txin = tx.getTxIn(nin)
        try:
          senderAddr20 = TheBDM.getSenderAddr20(txin)
          address = hash160_to_addrStr(senderAddr20)
          #print address
          for owner in trackaddr.keys():
            if address in trackaddr[owner]:
              foundaddr = True
              addressowner = owner
              print "FOUND TRANSACTION! At block " + str (h) + ' owned by ' + addressowner
              break
        except:
          pass
      if foundaddr is True:
        for nin in range(tx.getNumTxIn()):
          txin = tx.getTxIn(nin)
          try:
            senderAddr20 = TheBDM.getSenderAddr20(txin)
            address = hash160_to_addrStr(senderAddr20)
            trackaddr[addressowner].append(address)
          except:
            pass
        trackaddr[addressowner] = list(set(trackaddr[addressowner]))
  addratend = 0
  for item in trackaddr.itervalues():
     addratend += len(item)

print trackaddr
print "Went through the blockchain %d times!" % iterations
print "Found %d addresses in total" % addratend
for owner in trackaddr.keys():
     print owner + ' has ' + str(len(trackaddr[owner])) + ' addresses'

The pirate address comes from https://bitcointalk.org/index.php?topic=88486.msg980130#msg980130 btw. and the donation address was public anyways and one of the first ones I randomly found while looking for an address.

It's easy now to enter more "name:address" relationships and search for all of them, though it might get weird if you try to give 2 different names to the same cluster of addresses I fear... I proabably need a list of names as well for each entity there. Also I haven't tested very tough cookies (GLBSE, MtGox(!)) so I don't know if it scales well. For tracking smaller/medium sized wallets it should be enough though.

https://bitfinex.com <-- leveraged trading of BTCUSD, LTCUSD and LTCBTC (long and short) - 10% discount on fees for the first 30 days with this refcode: x5K9YtL3Zb
Mail me at Bitmessage: BM-BbiHiVv5qh858ULsyRDtpRrG9WjXN3xf
Pages: [1]
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!