Esempio n. 1
0
Status
HttpRequest::get(HttpReply &result, const std::string &url)
{
    if (!status_)
        return status_;

    // Final options:
    ABC_CHECK_CURL(curl_easy_setopt(handle_, CURLOPT_WRITEDATA, &result.body));
    ABC_CHECK_CURL(curl_easy_setopt(handle_, CURLOPT_WRITEFUNCTION,
                                    curlDataCallback));
    ABC_CHECK_CURL(curl_easy_setopt(handle_, CURLOPT_URL, url.c_str()));
    if (headers_)
        ABC_CHECK_CURL(curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers_));

    // Make the request:
    ABC_CHECK_CURL(curl_easy_perform(handle_));
    ABC_CHECK_CURL(curl_easy_getinfo(handle_, CURLINFO_RESPONSE_CODE,
                                     &result.code));
    if (result.codeOk())
        ABC_DebugLog("%s (%d)", url.c_str(), result.code);
    else
        ABC_DebugLog("%s (%d)\n%s", url.c_str(), result.code,
                     result.body.c_str());

    return Status();
}
Esempio n. 2
0
tABC_CC ABC_BridgePrioritizeAddress(Wallet &self,
                                    const char *szAddress,
                                    tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    bc::payment_address addr;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    if (szAddress)
    {
        if (!addr.set_encoded(szAddress))
        {
            cc = ABC_CC_Error;
            ABC_DebugLog("Invalid szAddress %s\n", szAddress);
            goto exit;
        }
    }

    watcher->prioritize_address(addr);

exit:
    return cc;
}
Esempio n. 3
0
tABC_CC ABC_BridgeWatcherConnect(Wallet &self, tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    tABC_GeneralInfo *ppInfo = NULL;
    const char *szServer = FALLBACK_OBELISK;

    Watcher *watcher = nullptr;
    ABC_CHECK_NEW(watcherFind(watcher, self));

    // Pick a server:
    if (isTestnet())
    {
        szServer = TESTNET_OBELISK;
    }
    else if (ABC_CC_Ok == ABC_GeneralGetInfo(&ppInfo, pError) &&
        0 < ppInfo->countObeliskServers)
    {
        ++gLastObelisk;
        if (ppInfo->countObeliskServers <= gLastObelisk)
            gLastObelisk = 0;
        szServer = ppInfo->aszObeliskServers[gLastObelisk];
    }

    // Connect:
    ABC_DebugLog("Wallet %s connecting to %s", self.id().c_str(), szServer);
    watcher->connect(szServer);

exit:
    ABC_GeneralFreeInfo(ppInfo);
    return cc;
}
Esempio n. 4
0
static void
bridgeQuietCallback(WatcherInfo *watcherInfo,
                    tABC_BitCoin_Event_Callback fAsyncCallback, void *pData)
{
    // If we are sweeping any keys, do that now:
    for (auto &sweep: watcherInfo->sweeping)
    {
        auto s = bridgeDoSweep(watcherInfo->wallet, sweep, fAsyncCallback, pData).log();
        if (!s)
        {
            ABC_DebugLog("IncomingSweep callback: wallet %s, status: %d",
                         watcherInfo->wallet.id().c_str(), s.value());
            tABC_AsyncBitCoinInfo info;
            info.pData = pData;
            info.eventType = ABC_AsyncEventType_IncomingSweep;
            s.toError(info.status, ABC_HERE());
            info.szWalletUUID = watcherInfo->wallet.id().c_str();
            info.szTxID = nullptr;
            info.sweepSatoshi = 0;
            fAsyncCallback(&info);

            sweep.done = true;
        }
    }

    // Remove completed ones:
    watcherInfo->sweeping.remove_if([](const PendingSweep& sweep)
    {
        return sweep.done;
    });
}
Esempio n. 5
0
Status
broadcastTx(Wallet &self, DataSlice rawTx)
{
    // Create communication resources:
    auto syncer = std::make_shared<Syncer>();
    auto s1 = std::make_shared<DelayedStatus>();
    auto s2 = std::make_shared<DelayedStatus>();
    auto s3 = std::make_shared<DelayedStatus>();

    // Launch the broadcasts:
    DataChunk tx(rawTx.begin(), rawTx.end());

    if (!self.bOverrideBitcoinServers)
    {
        std::thread(broadcastTask<blockchainPostTx>, syncer, s1, tx).detach();
        std::thread(broadcastTask<insightPostTx>, syncer, s2, tx).detach();
    }

    // Queue up an async broadcast over the TxUpdater:
    auto updaterDone = [syncer, s3](Status s)
    {
        {
            std::lock_guard<std::mutex> lock(syncer->mutex);
            s3->status = s;
            s3->done = true;
            if (s)
                ABC_DebugLog("Stratum broadcast OK");
            else
                s.log();
        }
        syncer->cv.notify_all();
    };
    watcherSend(self, updaterDone, rawTx).log();

    // Loop as long as any thread is still running:
    while (true)
    {
        // Wait for the condition variable, which also acquires the lock:
        std::unique_lock<std::mutex> lock(syncer->mutex);
        syncer->cv.wait(lock);

        // Stop waiting if any broadcast has succeeded:
        if (s1->done && s1->status)
            break;
        if (s2->done && s2->status)
            break;
        if (s3->done && s3->status)
            break;

        // If they are all done, we have an error:
        if (s1->done && s2->done && s3->done)
            return s1->status;
    }

    return Status();
}
Esempio n. 6
0
Status
syncRepo(const std::string &syncDir, const std::string &syncKey, bool &dirty)
{
    AutoSyncLock lock(gSyncMutex);

    AutoFree<git_repository, git_repository_free> repo;
    ABC_CHECK_GIT(git_repository_open(&repo.get(), syncDir.c_str()));

    std::string url;

    ABC_CHECK(syncUrl(url, syncKey));

    for (int i = 0; i < syncServers.size(); i++)
    {
        ABC_CHECK(syncUrl(url, syncKey, true));
        if (sync_fetch(repo, url.c_str()) >= 0)
        {
            ABC_DebugLog("Syncing to: %s", url.c_str());
            break;
        }
        else
        {
            ABC_DebugLog("FAIlED Syncing to: %s", url.c_str());
        }
    }

    int files_changed, need_push;
    ABC_CHECK_GIT(sync_master(repo, &files_changed, &need_push));

    if (need_push)
        ABC_CHECK_GIT(sync_push(repo, url.c_str()));

    // If this fails, the app has been shut down, leaving us for dead.
    // We will crash anyhow, but this at least makes it official:
    assert(gContext);

    dirty = !!files_changed;
    return Status();
}
Esempio n. 7
0
static int
curlDebugCallback(CURL *handle, curl_infotype type, char *data, size_t size,
                  void *userp)
{
    std::string payload(data, size);
    switch (type)
    {
    case CURLINFO_HEADER_OUT:
        ABC_DebugLog("cURL header out: %s", payload.c_str());
        return 0;
    case CURLINFO_DATA_OUT:
        ABC_DebugLog("cURL data out: %s", payload.c_str());
        return 0;
    case CURLINFO_HEADER_IN:
        ABC_DebugLog("cURL header in: %s", payload.c_str());
        return 0;
    case CURLINFO_DATA_IN:
        ABC_DebugLog("cURL data in: %s", payload.c_str());
        return 0;
    default:
        return 0;
    }
}
Esempio n. 8
0
tABC_CC ABC_BridgeWatchAddr(Wallet &self,
                            const char *pubAddress,
                            tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;

    ABC_DebugLog("Watching %s for %s", pubAddress, self.id().c_str());
    bc::payment_address addr;

    WatcherInfo *watcherInfo = nullptr;
    ABC_CHECK_NEW(watcherFind(watcherInfo, self));

    if (!addr.set_encoded(pubAddress))
    {
        cc = ABC_CC_Error;
        ABC_DebugLog("Invalid pubAddress %s\n", pubAddress);
        goto exit;
    }
    watcherInfo->addresses.insert(pubAddress);
    watcherInfo->watcher.watch_address(addr);

exit:
    return cc;
}
Esempio n. 9
0
void Status::toError(tABC_Error &error)
{
    std::stringstream s;
    s << *this;
    ABC_DebugLog("%s", s.str().c_str());

    error.code = value_;
    strncpy(error.szDescription, message_.c_str(), ABC_MAX_STRING_LENGTH);
    strncpy(error.szSourceFunc, function_, ABC_MAX_STRING_LENGTH);
    strncpy(error.szSourceFile, file_, ABC_MAX_STRING_LENGTH);
    error.nSourceLine = line_;

    error.szDescription[ABC_MAX_STRING_LENGTH] = 0;
    error.szSourceFunc[ABC_MAX_STRING_LENGTH] = 0;
    error.szSourceFile[ABC_MAX_STRING_LENGTH] = 0;
}
Esempio n. 10
0
Status
AddressDb::load()
{
    std::lock_guard<std::mutex> lock(mutex_);

    addresses_.clear();
    files_.clear();

    // Open the directory:
    DIR *dir = opendir(dir_.c_str());
    if (dir)
    {
        struct dirent *de;
        while (nullptr != (de = readdir(dir)))
        {
            if (!fileIsJson(de->d_name))
                continue;

            // Try to load the address:
            Address address;
            AddressJson json;
            if (json.load(dir_ + de->d_name, wallet_.dataKey()).log() &&
                    json.unpack(address).log())
            {
                if (path(address) != dir_ + de->d_name)
                    ABC_DebugLog("Filename %s does not match address", de->d_name);

                addresses_[address.address] = address;
                files_[address.address] = json;
            }
        }
        closedir(dir);
    }

    ABC_CHECK(stockpile());
    return Status();
}
Esempio n. 11
0
static
void ABC_BridgeTxCallback(WatcherInfo *watcherInfo, const libbitcoin::transaction_type& tx,
                          tABC_BitCoin_Event_Callback fAsyncBitCoinEventCallback,
                          void *pData)
{
    tABC_CC cc = ABC_CC_Ok;
    tABC_Error error;
    int64_t fees = 0;
    int64_t totalInSatoshi = 0, totalOutSatoshi = 0, totalMeSatoshi = 0, totalMeInSatoshi = 0;
    tABC_TxOutput **iarr = NULL, **oarr = NULL;
    unsigned int idx = 0, iCount = 0, oCount = 0;
    std::string txId, malTxId;

    if (watcherInfo == NULL)
    {
        cc = ABC_CC_Error;
        goto exit;
    }

    txId = ABC_BridgeNonMalleableTxId(tx);
    malTxId = bc::encode_hash(bc::hash_transaction(tx));

    idx = 0;
    iCount = tx.inputs.size();
    iarr = (tABC_TxOutput **) malloc(sizeof(tABC_TxOutput *) * iCount);
    for (auto i : tx.inputs)
    {
        bc::payment_address addr;
        bc::extract(addr, i.script);
        auto prev = i.previous_output;

        // Create output
        tABC_TxOutput *out = (tABC_TxOutput *) malloc(sizeof(tABC_TxOutput));
        out->input = true;
        out->szTxId = stringCopy(bc::encode_hash(prev.hash));
        out->szAddress = stringCopy(addr.encoded());

        // Check prevouts for values
        auto tx = watcherInfo->watcher.find_tx(prev.hash);
        if (prev.index < tx.outputs.size())
        {
            out->value = tx.outputs[prev.index].value;
            totalInSatoshi += tx.outputs[prev.index].value;
            auto row = watcherInfo->addresses.find(addr.encoded());
            if  (row != watcherInfo->addresses.end())
                totalMeInSatoshi += tx.outputs[prev.index].value;
        }
        iarr[idx] = out;
        idx++;
    }

    idx = 0;
    oCount = tx.outputs.size();
    oarr = (tABC_TxOutput **) malloc(sizeof(tABC_TxOutput *) * oCount);
    for (auto o : tx.outputs)
    {
        bc::payment_address addr;
        bc::extract(addr, o.script);
        // Create output
        tABC_TxOutput *out = (tABC_TxOutput *) malloc(sizeof(tABC_TxOutput));
        out->input = false;
        out->value = o.value;
        out->szAddress = stringCopy(addr.encoded());
        out->szTxId = stringCopy(malTxId);

        // Do we own this address?
        auto row = watcherInfo->addresses.find(addr.encoded());
        if  (row != watcherInfo->addresses.end())
        {
            totalMeSatoshi += o.value;
        }
        totalOutSatoshi += o.value;

        oarr[idx] = out;
        idx++;
    }
    if (totalMeSatoshi == 0 && totalMeInSatoshi == 0)
    {
        ABC_DebugLog("values == 0, this tx does not concern me.\n");
        goto exit;
    }
    fees = totalInSatoshi - totalOutSatoshi;
    totalMeSatoshi -= totalMeInSatoshi;

    ABC_DebugLog("calling ABC_TxReceiveTransaction");
    ABC_DebugLog("Total Me: %s, Total In: %s, Total Out: %s, Fees: %s",
        std::to_string(totalMeSatoshi).c_str(),
        std::to_string(totalInSatoshi).c_str(),
        std::to_string(totalOutSatoshi).c_str(),
        std::to_string(fees).c_str());
    ABC_CHECK_RET(
        ABC_TxReceiveTransaction(
            watcherInfo->wallet,
            totalMeSatoshi, fees,
            iarr, iCount,
            oarr, oCount,
            txId.c_str(), malTxId.c_str(),
            fAsyncBitCoinEventCallback,
            pData,
            &error));
    watcherSave(watcherInfo->wallet); // Failure is not fatal

exit:
    ABC_FREE(oarr);
    ABC_FREE(iarr);
}
Esempio n. 12
0
Status
onReceive(Wallet &wallet, const TxInfo &info,
          tABC_BitCoin_Event_Callback fCallback, void *pData)
{
    wallet.balanceDirty();
    ABC_CHECK(wallet.addresses.markOutputs(info));

    // Does the transaction already exist?
    TxMeta meta;
    if (!wallet.txs.get(meta, info.ntxid))
    {
        const auto balance = wallet.addresses.balance(info);

        meta.ntxid = info.ntxid;
        meta.txid = info.txid;
        meta.timeCreation = time(nullptr);
        meta.internal = false;
        meta.airbitzFeeWanted = 0;
        meta.airbitzFeeSent = 0;

        // Receives can accumulate Airbitz fees:
        const auto airbitzFeeInfo = generalAirbitzFeeInfo();
        meta.airbitzFeeWanted = airbitzFeeIncoming(airbitzFeeInfo, balance);
        logInfo("Airbitz fee: " +
                std::to_string(meta.airbitzFeeWanted) + " wanted, " +
                std::to_string(wallet.txs.airbitzFeePending()) + " pending");

        // Grab metadata from the address:
        for (const auto &io: info.ios)
        {
            AddressMeta address;
            if (wallet.addresses.get(address, io.address))
                meta.metadata = address.metadata;
        }
        ABC_CHECK(gContext->exchangeCache.satoshiToCurrency(
                      meta.metadata.amountCurrency, balance,
                      static_cast<Currency>(wallet.currency())));

        // Save the metadata:
        ABC_CHECK(wallet.txs.save(meta, balance, info.fee));

        // Update the GUI:
        ABC_DebugLog("IncomingBitCoin callback: wallet %s, txid: %s",
                     wallet.id().c_str(), info.txid.c_str());
        tABC_AsyncBitCoinInfo async;
        async.pData = pData;
        async.eventType = ABC_AsyncEventType_IncomingBitCoin;
        Status().toError(async.status, ABC_HERE());
        async.szWalletUUID = wallet.id().c_str();
        async.szTxID = info.txid.c_str();
        async.sweepSatoshi = 0;
        fCallback(&async);
    }
    else
    {
        // Update the GUI:
        ABC_DebugLog("BalanceUpdate callback: wallet %s, txid: %s",
                     wallet.id().c_str(), info.txid.c_str());
        tABC_AsyncBitCoinInfo async;
        async.pData = pData;
        async.eventType = ABC_AsyncEventType_BalanceUpdate;
        Status().toError(async.status, ABC_HERE());
        async.szWalletUUID = wallet.id().c_str();
        async.szTxID = info.txid.c_str();
        async.sweepSatoshi = 0;
        fCallback(&async);
    }

    return Status();
}
Esempio n. 13
0
static Status
bridgeTxCallback(Wallet &wallet,
                 const libbitcoin::transaction_type &tx,
                 tABC_BitCoin_Event_Callback fAsyncCallback, void *pData)
{
    const auto addresses = wallet.addresses.list();
    const auto info = wallet.txCache.txInfo(tx, addresses);

    // Does this transaction concern us?
    if (wallet.txCache.isRelevant(tx, addresses))
    {
        // Does the transaction already exist?
        Tx meta;
        if (!wallet.txs.get(meta, info.ntxid))
        {
            meta.ntxid = info.ntxid;
            meta.txid = info.txid;
            meta.timeCreation = time(nullptr);
            meta.internal = false;

            // Grab metadata from the address:
            TxMetadata metadata;
            for (const auto &io: info.ios)
            {
                Address address;
                if (wallet.addresses.get(address, io.address))
                    meta.metadata = address.metadata;
            }
            meta.metadata.amountSatoshi = info.balance;
            meta.metadata.amountFeesMinersSatoshi = info.fee;
            ABC_CHECK(gContext->exchangeCache.satoshiToCurrency(
                          meta.metadata.amountCurrency, info.balance,
                          static_cast<Currency>(wallet.currency())));

            // Save the metadata:
            ABC_CHECK(wallet.txs.save(meta));

            // Update the transaction cache:
            watcherSave(wallet).log(); // Failure is not fatal
            wallet.balanceDirty();
            ABC_CHECK(wallet.addresses.markOutputs(info.ios));

            // Update the GUI:
            ABC_DebugLog("IncomingBitCoin callback: wallet %s, txid: %s",
                         wallet.id().c_str(), info.txid.c_str());
            tABC_AsyncBitCoinInfo async;
            async.pData = pData;
            async.eventType = ABC_AsyncEventType_IncomingBitCoin;
            Status().toError(async.status, ABC_HERE());
            async.szWalletUUID = wallet.id().c_str();
            async.szTxID = info.txid.c_str();
            async.sweepSatoshi = 0;
            fAsyncCallback(&async);
        }
        else
        {
            // Update the transaction cache:
            watcherSave(wallet).log(); // Failure is not fatal
            wallet.balanceDirty();
            ABC_CHECK(wallet.addresses.markOutputs(info.ios));

            // Update the GUI:
            ABC_DebugLog("BalanceUpdate callback: wallet %s, txid: %s",
                         wallet.id().c_str(), info.txid.c_str());
            tABC_AsyncBitCoinInfo async;
            async.pData = pData;
            async.eventType = ABC_AsyncEventType_BalanceUpdate;
            Status().toError(async.status, ABC_HERE());
            async.szWalletUUID = wallet.id().c_str();
            async.szTxID = info.txid.c_str();
            async.sweepSatoshi = 0;
            fAsyncCallback(&async);
        }
    }
    else
    {
        ABC_DebugLog("New (irrelevant) transaction:  wallet %s, txid: %s",
                     wallet.id().c_str(), info.txid.c_str());
    }

    return Status();
}
Esempio n. 14
0
static Status
bridgeDoSweep(Wallet &wallet, PendingSweep &sweep,
              tABC_BitCoin_Event_Callback fAsyncCallback, void *pData)
{
    // Find utxos for this address:
    AddressSet addresses;
    addresses.insert(sweep.address);
    auto utxos = wallet.txCache.get_utxos(addresses);

    // Bail out if there are no funds to sweep:
    if (!utxos.size())
    {
        // Tell the GUI if there were funds in the past:
        if (wallet.txCache.has_history(sweep.address))
        {
            ABC_DebugLog("IncomingSweep callback: wallet %s, value: 0",
                         wallet.id().c_str());
            tABC_AsyncBitCoinInfo info;
            info.pData = pData;
            info.eventType = ABC_AsyncEventType_IncomingSweep;
            Status().toError(info.status, ABC_HERE());
            info.szWalletUUID = wallet.id().c_str();
            info.szTxID = nullptr;
            info.sweepSatoshi = 0;
            fAsyncCallback(&info);

            sweep.done = true;
        }
        return Status();
    }

    // Build a transaction:
    bc::transaction_type tx;
    tx.version = 1;
    tx.locktime = 0;

    // Set up the output:
    Address address;
    wallet.addresses.getNew(address);
    bc::transaction_output_type output;
    ABC_CHECK(outputScriptForAddress(output.script, address.address));
    tx.outputs.push_back(output);

    // Set up the inputs:
    uint64_t fee, funds;
    ABC_CHECK(inputsPickMaximum(fee, funds, tx, utxos));
    if (outputIsDust(funds))
        return ABC_ERROR(ABC_CC_InsufficientFunds, "Not enough funds");
    tx.outputs[0].value = funds;

    // Now sign that:
    KeyTable keys;
    keys[sweep.address] = sweep.key;
    ABC_CHECK(signTx(tx, wallet.txCache, keys));

    // Send:
    bc::data_chunk raw_tx(satoshi_raw_size(tx));
    bc::satoshi_save(tx, raw_tx.begin());
    ABC_CHECK(broadcastTx(wallet, raw_tx));

    // Calculate transaction information:
    const auto info = wallet.txCache.txInfo(tx, wallet.addresses.list());

    // Save the transaction metadata:
    Tx meta;
    meta.ntxid = info.ntxid;
    meta.txid = info.txid;
    meta.timeCreation = time(nullptr);
    meta.internal = true;
    meta.metadata.amountSatoshi = funds;
    meta.metadata.amountFeesAirbitzSatoshi = 0;
    ABC_CHECK(gContext->exchangeCache.satoshiToCurrency(
                  meta.metadata.amountCurrency, info.balance,
                  static_cast<Currency>(wallet.currency())));
    ABC_CHECK(wallet.txs.save(meta));

    // Update the transaction cache:
    if (wallet.txCache.insert(tx))
        watcherSave(wallet).log(); // Failure is not fatal
    wallet.balanceDirty();
    ABC_CHECK(wallet.addresses.markOutputs(info.ios));

    // Done:
    ABC_DebugLog("IncomingSweep callback: wallet %s, txid: %s, value: %d",
                 wallet.id().c_str(), info.txid.c_str(), output.value);
    tABC_AsyncBitCoinInfo async;
    async.pData = pData;
    async.eventType = ABC_AsyncEventType_IncomingSweep;
    Status().toError(async.status, ABC_HERE());
    async.szWalletUUID = wallet.id().c_str();
    async.szTxID = info.txid.c_str();
    async.sweepSatoshi = output.value;
    fAsyncCallback(&async);

    sweep.done = true;

    return Status();
}
Esempio n. 15
0
Status
bridgeWatcherLoop(Wallet &self,
                  tABC_BitCoin_Event_Callback fCallback,
                  void *pData)
{
    WatcherInfo *watcherInfo = nullptr;
    ABC_CHECK(watcherFind(watcherInfo, self));

    // Set up the address-changed callback:
    auto wakeupCallback = [watcherInfo]()
    {
        watcherInfo->watcher.sendWakeup();
    };
    self.addressCache.wakeupCallbackSet(wakeupCallback);

    // Set up the address-synced callback:
    auto doneCallback = [watcherInfo, fCallback, pData]()
    {
        ABC_DebugLog("AddressCheckDone callback: wallet %s",
                     watcherInfo->wallet.id().c_str());
        tABC_AsyncBitCoinInfo info;
        info.pData = pData;
        info.eventType = ABC_AsyncEventType_AddressCheckDone;
        Status().toError(info.status, ABC_HERE());
        info.szWalletUUID = watcherInfo->wallet.id().c_str();
        info.szTxID = nullptr;
        info.sweepSatoshi = 0;
        fCallback(&info);
    };
    self.addressCache.doneCallbackSet(doneCallback);

    // Set up new-transaction callback:
    auto txCallback = [watcherInfo, fCallback, pData]
                      (const libbitcoin::transaction_type &tx)
    {
        bridgeTxCallback(watcherInfo->wallet, tx, fCallback, pData).log();
    };
    watcherInfo->watcher.set_tx_callback(txCallback);

    // Set up new-block callback:
    auto heightCallback = [watcherInfo, fCallback, pData](const size_t height)
    {
        // Update the GUI:
        ABC_DebugLog("BlockHeightChange callback: wallet %s",
                     watcherInfo->wallet.id().c_str());
        tABC_AsyncBitCoinInfo info;
        info.pData = pData;
        info.eventType = ABC_AsyncEventType_BlockHeightChange;
        Status().toError(info.status, ABC_HERE());
        info.szWalletUUID = watcherInfo->wallet.id().c_str();
        info.szTxID = nullptr;
        info.sweepSatoshi = 0;
        fCallback(&info);

        watcherSave(watcherInfo->wallet).log(); // Failure is not fatal
    };
    watcherInfo->watcher.set_height_callback(heightCallback);

    // Set up sweep-trigger callback:
    auto onQuiet = [watcherInfo, fCallback, pData]()
    {
        bridgeQuietCallback(watcherInfo, fCallback, pData);
    };
    watcherInfo->watcher.set_quiet_callback(onQuiet);

    // Do the loop:
    watcherInfo->watcher.loop();

    // Cancel all callbacks:
    watcherInfo->watcher.set_quiet_callback(nullptr);
    watcherInfo->watcher.set_height_callback(nullptr);
    watcherInfo->watcher.set_tx_callback(nullptr);
    self.addressCache.wakeupCallbackSet(nullptr);
    self.addressCache.doneCallbackSet(nullptr);

    return Status();
}
Esempio n. 16
0
/**
 * Generate the QR code for a previously created receive request.
 *
 * @param szRequestID   ID of this request
 * @param pszURI        Pointer to string to store URI(optional)
 * @param paData        Pointer to store array of data bytes (0x0 white, 0x1 black)
 * @param pWidth        Pointer to store width of image (image will be square)
 * @param pError        A pointer to the location to store the error if there is one
 */
tABC_CC ABC_TxGenerateRequestQRCode(Wallet &self,
                                    const char *szRequestID,
                                    char **pszURI,
                                    unsigned char **paData,
                                    unsigned int *pWidth,
                                    tABC_Error *pError)
{
    tABC_CC cc = ABC_CC_Ok;
    AutoCoreLock lock(gCoreMutex);

    QRcode *qr = NULL;
    unsigned char *aData = NULL;
    unsigned int length = 0;
    char *szURI = NULL;

    // load the request/address
    Address address;
    ABC_CHECK_NEW(self.addresses.get(address, szRequestID));

    // Get the URL string for this info
    tABC_BitcoinURIInfo infoURI;
    memset(&infoURI, 0, sizeof(tABC_BitcoinURIInfo));
    infoURI.amountSatoshi = address.metadata.amountSatoshi;
    infoURI.szAddress = address.address.c_str();

    // Set the label if there is one
    ABC_CHECK_RET(ABC_TxBuildFromLabel(self, &(infoURI.szLabel), pError));

    // if there is a note
    if (!address.metadata.notes.empty())
    {
        infoURI.szMessage = address.metadata.notes.c_str();
    }
    ABC_CHECK_RET(ABC_BridgeEncodeBitcoinURI(&szURI, &infoURI, pError));

    // encode our string
    ABC_DebugLog("Encoding: %s", szURI);
    qr = QRcode_encodeString(szURI, 0, QR_ECLEVEL_L, QR_MODE_8, 1);
    ABC_CHECK_ASSERT(qr != NULL, ABC_CC_Error, "Unable to create QR code");
    length = qr->width * qr->width;
    ABC_ARRAY_NEW(aData, length, unsigned char);
    for (unsigned i = 0; i < length; i++)
    {
        aData[i] = qr->data[i] & 0x1;
    }
    *pWidth = qr->width;
    *paData = aData;
    aData = NULL;

    if (pszURI != NULL)
    {
        *pszURI = stringCopy(szURI);
    }

exit:
    ABC_FREE_STR(szURI);
    QRcode_free(qr);
    ABC_CLEAR_FREE(aData, length);

    return cc;
}