예제 #1
0
    virtual void edge(
        uint64_t      value,
        const uint8_t *upTXHash,
        uint64_t      outputIndex,
        const uint8_t *outputScript,
        uint64_t      outputScriptSize,
        const uint8_t *downTXHash,
        uint64_t      inputIndex,
        const uint8_t *inputScript,
        uint64_t      inputScriptSize
    )
    {
        uint8_t addrType[3];
        uint160_t pubKeyHash;
        int type = solveOutputScript(pubKeyHash.v, outputScript, outputScriptSize, addrType);
        if(unlikely(type<0)) return;

        uint64_t a;
        auto i = addrMap.find(pubKeyHash.v);
        if(unlikely(addrMap.end()!=i))
            a = i->second;
        else {
            Addr *addr = (Addr*)allocHash160();
            memcpy(addr->v, pubKeyHash.v, kRIPEMD160ByteSize);
            addrMap[addr->v] = a = allAddrs.size();
            allAddrs.push_back(addr);
        }

        vertices.push_back(a);
    }
예제 #2
0
    virtual int init(
        int argc,
        const char *argv[]
    )
    {
        optparse::Values &values = parser.parse_args(argc, argv);

        auto args = parser.args();
        for(size_t i=1; i<args.size(); ++i) {
            loadKeyList(rootHashes, args[i].c_str());
        }

        if(0==rootHashes.size()) {
            const char *addr = "1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp";
            warning("no addresses specified, using satoshi's dice address %s", addr);
            loadKeyList(rootHashes, addr);
        }

        addrMap.setEmptyKey(gEmptyKey);
        addrMap.resize(15 * 1000 * 1000);
        allAddrs.reserve(15 * 1000 * 1000);
        info("Building address equivalence graph ...");
        startTime = usecs();

        return 0;
    }
예제 #3
0
    virtual int init(
        int argc,
        const char *argv[]
    )
    {
        optparse::Values &values = parser.parse_args(argc, argv);

        auto args = parser.args();
        for(size_t i=1; i<args.size(); ++i) {
            loadKeyList(rootHashes, args[i].c_str());
        }

        if(0==rootHashes.size()) {
            const char *addr = getInterestingAddr();
            loadKeyList(rootHashes, addr);
        }

        addrMap.setEmptyKey(gEmptyKey);
        addrMap.resize(15 * 1000 * 1000);
        allAddrs.reserve(15 * 1000 * 1000);
        info("Building address equivalence graph ...");
        startTime = usecs();

        return 0;
    }
예제 #4
0
    virtual int init(
        int argc,
        const char *argv[]
    )
    {
        offset = 0;
        curBlock = 0;
        lastBlock = 0;
        firstBlock = 0;

        addrMap.setEmptyKey(emptyKey);
        addrMap.resize(15 * 1000 * 1000);
        allAddrs.reserve(15 * 1000 * 1000);

        optparse::Values &values = parser.parse_args(argc, argv);
        cutoffBlock = values.get("atBlock");
        showAddr = values.get("withAddr");
        detailed = values.get("detailed");
        limit = values.get("limit");

        auto args = parser.args();
        for(size_t i=1; i<args.size(); ++i) {
            loadKeyList(restricts, args[i].c_str());
        }

        if(0<=cutoffBlock) {
            info("only taking into account transactions before block %" PRIu64 "\n", cutoffBlock);
        }

        if(0!=restricts.size()) {

            info(
                "restricting output to %" PRIu64 " addresses ...\n",
                (uint64_t)restricts.size()
            );

            auto e = restricts.end();
            auto i = restricts.begin();
            restrictMap.setEmptyKey(emptyKey);
            while(e!=i) {
                const uint160_t &h = *(i++);
                restrictMap[h.v] = 1;
            }
        } else {
            if(detailed) {
                warning("asking for --detailed for *all* addresses in the blockchain will be *very* slow");
                warning("as a matter of fact, it likely won't ever finish unless you have *lots* of RAM");
            }
        }

        info("analyzing blockchain ...");
        return 0;
    }
예제 #5
0
    virtual void wrapup()
    {
        size_t size = boost::num_vertices(graph);
        info(
            "done, %.2f secs, found %" PRIu64 " address(es) \n",
            1e-6*(usecs() - startTime),
            size
        );

        info("Clustering ... ");
        startTime = usecs();

        std::vector<uint64_t> cc(size);
        uint64_t nbCC = boost::connected_components(graph, &cc[0]);
        info(
            "done, %.2f secs, found %" PRIu64 " clusters.\n",
            1e-6*(usecs() - startTime),
            nbCC
        );

        auto e = rootHashes.end();
        auto i = rootHashes.begin();
        while(e!=i) {

            uint64_t count = 0;
            const uint8_t *keyHash = (i++)->v;

            uint8_t b58[128];
            hash160ToAddr(b58, keyHash);
            info("Address cluster for address %s:", b58);

            auto j = addrMap.find(keyHash);
            if(unlikely(addrMap.end()==j)) {
                warning("specified key was never used to spend coins");
                showFullAddr(keyHash);
                printf("\n");
                count = 1;
            } else {
                uint64_t addrIndex = j->second;
                uint64_t homeComponentIndex = cc[addrIndex];
                for(size_t k=0; likely(k<cc.size()); ++k) {
                    uint64_t componentIndex = cc[k];
                    if(unlikely(homeComponentIndex==componentIndex)) {
                        Addr *addr = allAddrs[k];
                        showFullAddr(addr->v);
                        printf("\n");
                        ++count;
                    }
                }
            }
            info("%" PRIu64 " addresse(s)\n", count);
        }
    }
예제 #6
0
    void move(
        const uint8_t *script,
        uint64_t      scriptSize,
        const uint8_t *txHash,
        int64_t        value,
        const uint8_t *downTXHash = 0
    )
    {
        uint8_t addrType[3];
        uint160_t pubKeyHash;
        int type = solveOutputScript(pubKeyHash.v, script, scriptSize, addrType);
        if(unlikely(type<0)) return;

        Addr *addr;
        auto i = addrMap.find(pubKeyHash.v);
        if(unlikely(addrMap.end()!=i))
            addr = i->second;
        else {
            addr = allocAddr();
            memcpy(addr->hash.v, pubKeyHash.v, kRIPEMD160ByteSize);
            addr->sum = 0;

            addrMap[addr->hash.v] = addr;
            allAddrs.push_back(addr);
        }

        addr->lastTouched = blockTime;
        addr->sum += value;

        static uint64_t cnt = 0;
        if(unlikely(0==((cnt++)&0xFFFFF))) {

            if(
                curBlock   &&
                lastBlock  &&
                firstBlock
            )
            {
                double progress = curBlock->height/(double)lastBlock->height;
                info(
                    "%8" PRIu64 " blocks, "
                    "%8.3f MegaMoves , "
                    "%8.3f MegaAddrs , "
                    "%5.2f%%",
                    curBlock->height,
                    cnt*1e-6,
                    addrMap.size()*1e-6,
                    100.0*progress
                );
            }
        }
    }
예제 #7
0
    virtual int init(
        int argc,
        char *argv[]
    )
    {
        curBlock = 0;
        lastBlock = 0;
        firstBlock = 0;

        addrMap.setEmptyKey(emptyKey);
        addrMap.resize(15 * 1000 * 1000);
        allAddrs.reserve(15 * 1000 * 1000);

        option::Stats  stats(usageDescriptor, argc, argv);
        option::Option *buffer  = new option::Option[stats.buffer_max];
        option::Option *options = new option::Option[stats.options_max];
        option::Parser parse(usageDescriptor, argc, argv, options, buffer);
        if(parse.error()) exit(1);

        for(int i=0; i<parse.nonOptionsCount(); ++i) {
            loadKeyList(restricts, parse.nonOption(i));
        }

        if(0!=restricts.size()) {
            info(
                "restricting output to %" PRIu64 " addresses ...\n",
                (uint64_t)restricts.size()
            );

            auto e = restricts.end();
            auto i = restricts.begin();
            restrictMap.setEmptyKey(emptyKey);
            while(e!=i) {
                const uint160_t &h = *(i++);
                restrictMap[h.v] = 1;
            }
        }

        info("analyzing blockchain ...");
        delete [] options;
        delete [] buffer;
        return 0;
    }
예제 #8
0
    virtual void startBlock(
        const Block *b,
        uint64_t chainSize
    )
    {
        curBlock = b;

        const uint8_t *p = b->data;
        const uint8_t *sz = -4 + p;
        LOAD(uint32_t, size, sz);
        offset += size;

        double now = usecs();
        static double startTime = 0;
        static double lastStatTime = 0;
        double elapsed = now - lastStatTime;
        bool longEnough = (5*1000*1000<elapsed);
        bool closeEnough = ((chainSize - offset)<80);
        if(unlikely(longEnough || closeEnough)) {

            if(0==startTime) {
                startTime = now;
            }

            double progress = offset/(double)chainSize;
            double elasedSinceStart = 1e-6*(now - startTime);
            double speed = progress / elasedSinceStart;
            info(
                "%8" PRIu64 " blocks, "
                "%8.3f MegaAddrs , "
                "%6.2f%% , "
                "elapsed = %5.2fs , "
                "eta = %5.2fs , "
                ,
                curBlock->height,
                addrMap.size()*1e-6,
                100.0*progress,
                elasedSinceStart,
                (1.0/speed) - elasedSinceStart
            );

            lastStatTime = now;
        }

        SKIP(uint32_t, version, p);
        SKIP(uint256_t, prevBlkHash, p);
        SKIP(uint256_t, blkMerkleRoot, p);
        LOAD(uint32_t, bTime, p);
        blockTime = bTime;

        if(0<=cutoffBlock && cutoffBlock<=curBlock->height) {
            wrapup();
        }
    }
예제 #9
0
 virtual void start(
     const Block *,
     const Block *
 )
 {
     if(csv) {
         printf(
             "\"Time\","
             " \"Address\","
             "                                  \"TXId\","
             "                                                                   \"TXAmount\","
             "     \"NewBalance\""
             "\n"
         );
     }
     else {
         info("Dumping all transactions for %d address(es)\n", (int)addrMap.size());
         printf("    Time (GMT)                  Address                                     Transaction                                                                    OldBalance                     Amount                 NewBalance\n");
         printf("    =======================================================================================================================================================================================================================\n");
     }
 }
예제 #10
0
    virtual int init(
        int  argc,
        const char *argv[]
    )
    {
        sum = 0;
        adds = 0;
        subs = 0;
        nbTX = 0;

        optparse::Values &values = parser.parse_args(argc, argv);
        csv = values.get("csv");

        auto args = parser.args();
        for(size_t i=1; i<args.size(); ++i) {
            loadKeyList(rootHashes, args[i].c_str());
        }

        if(0==rootHashes.size()) {
            #if defined(LITECOIN)
                const char *addr = "LKvTVnkK2rAkJXfgPdkaDRgvEGvazxWS9o";
                warning("no addresses specified, using popular address %s", addr);
            #else
                const char *addr = "1dice8EMZmqKvrGE4Qc9bUFf9PX3xaYDp";
                warning("no addresses specified, using satoshi's dice address %s", addr);
            #endif
            loadKeyList(rootHashes, addr);
        }

        auto e = rootHashes.end();
        auto i = rootHashes.begin();
        addrMap.setEmptyKey(emptyKey);
        while(e!=i) {
            const uint160_t &h = *(i++);
            addrMap[h.v] = 1;
        }
        return 0;
    }
예제 #11
0
    void move(
        const uint8_t *script,
        uint64_t      scriptSize,
        const uint8_t *txHash,
        uint64_t       value,
        bool           add,
        const uint8_t *downTXHash = 0
    )
    {
        uint8_t addrType[3];
        uint160_t pubKeyHash;
        int type = solveOutputScript(pubKeyHash.v, script, scriptSize, addrType);
        if(unlikely(type<0)) return;

        bool match = (addrMap.end() != addrMap.find(pubKeyHash.v));
        if(unlikely(match)) {

            int64_t newSum = sum + value*(add ? 1 : -1);

            if(csv) {
                printf("%6" PRIu64 ", \"", bTime/86400 + 25569);
                showHex(pubKeyHash.v, kRIPEMD160ByteSize, false);
                printf("\", \"");
                showHex(downTXHash ? downTXHash : txHash);
                printf(
                    "\",%17.08f,%17.08f\n",
                    (add ? 1e-8 : -1e-8)*value,
                    newSum*1e-8
                );
            } else {

                struct tm gmTime;
                time_t blockTime = bTime;
                gmtime_r(&blockTime, &gmTime);

                char timeBuf[256];
                asctime_r(&gmTime, timeBuf);

                size_t sz =strlen(timeBuf);
                if(0<sz) timeBuf[sz-1] = 0;

                printf("    %s    ", timeBuf);
                showHex(pubKeyHash.v, kRIPEMD160ByteSize, false);

                printf("    ");
                showHex(downTXHash ? downTXHash : txHash);

                printf(
                    " %24.08f %c %24.08f = %24.08f\n",
                    sum*1e-8,
                    add ? '+' : '-',
                    value*1e-8,
                    newSum*1e-8
                );
            }

            (add ? adds : subs) += value;
            sum = newSum;
            ++nbTX;
        }
    }
예제 #12
0
    void move(
        const uint8_t *script,
        uint64_t      scriptSize,
        const uint8_t *upTXHash,
        int64_t       outputIndex,
        int64_t       value,
        const uint8_t *downTXHash = 0,
        uint64_t      inputIndex = -1
    )
    {
        uint8_t addrType[3];
        uint160_t pubKeyHash;
        int type = solveOutputScript(pubKeyHash.v, script, scriptSize, addrType);
        if(unlikely(type<0)) return;

        if(0!=restrictMap.size()) {
            auto r = restrictMap.find(pubKeyHash.v);
            if(restrictMap.end()==r) {
                return;
            }
        }

        Addr *addr;
        auto i = addrMap.find(pubKeyHash.v);
        if(unlikely(addrMap.end()!=i)) {
            addr = i->second;
        } else {

            addr = allocAddr();

            memcpy(addr->hash.v, pubKeyHash.v, kRIPEMD160ByteSize);
            addr->outputVec = 0;
            addr->nbOut = 0;
            addr->nbIn = 0;
            addr->sum = 0;

            if(detailed) {
                addr->outputVec = new OutputVec;
            }

            addrMap[addr->hash.v] = addr;
            allAddrs.push_back(addr);
        }

        if(0<value) {
            addr->lastIn = blockTime;
            ++(addr->nbIn);
        } else {
            addr->lastOut = blockTime;
            ++(addr->nbOut);
        }
        addr->sum += value;

        if(detailed) {
            struct Output output;
            output.value = value;
            output.time = blockTime;
            output.upTXHash = upTXHash;
            output.downTXHash = downTXHash;
            output.inputIndex = inputIndex;
            output.outputIndex = outputIndex;
            addr->outputVec->push_back(output);
        }
    }