Bitcoin Forum
April 25, 2024, 04:19:03 PM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Aggregating addresses to wallets (using armoryengine)  (Read 1089 times)
Sukrim (OP)
Legendary
*
Offline Offline

Activity: 2618
Merit: 1006


View Profile
July 04, 2012, 10:59:53 AM
Last edit: July 04, 2012, 11:14:17 AM by Sukrim
 #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://www.coinlend.org <-- automated lending at various exchanges.
https://www.bitfinex.com <-- Trade BTC for other currencies and vice versa.
1714061943
Hero Member
*
Offline Offline

Posts: 1714061943

View Profile Personal Message (Offline)

Ignore
1714061943
Reply with quote  #2

1714061943
Report to moderator
The Bitcoin software, network, and concept is called "Bitcoin" with a capitalized "B". Bitcoin currency units are called "bitcoins" with a lowercase "b" -- this is often abbreviated BTC.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1714061943
Hero Member
*
Offline Offline

Posts: 1714061943

View Profile Personal Message (Offline)

Ignore
1714061943
Reply with quote  #2

1714061943
Report to moderator
etotheipi
Legendary
*
expert
Offline Offline

Activity: 1428
Merit: 1093


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 (OP)
Legendary
*
Offline Offline

Activity: 2618
Merit: 1006


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://www.coinlend.org <-- automated lending at various exchanges.
https://www.bitfinex.com <-- Trade BTC for other currencies and vice versa.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!