function testBalanceLookupElegantlyHandlesUnhelpfulResponsesFromBlockchainDotInfo()
{
    $addresses = array('1GivesBlankContentiTDhViXbrogKqzbt', '1GivesLockWaitTimeoutTDhViXbrogKqzbt');
    foreach ($addresses as $a) {
        try {
            BlockchainDotInfo\getBalanceInSatoshis($a);
            fail("Expected to get exception for lookup on address {$a}");
        } catch (NetworkError $e) {
        }
    }
}
Example #2
0
function testGetBalanceUsesLocallyCachedValueWhenAppropriate()
{
    $address = '1K7dyLY6arFRXBidQhrtnyqksqJZdj2F37';
    $actualBalance = BlockchainDotInfo\getBalanceInSatoshis($address);
    $cachedBalance = $actualBalance + 1000;
    DB\delete('bitcoin_addresses', 'address = ?', array($address));
    DB\insertOne('bitcoin_addresses', array('address' => $address, 'satoshis' => $cachedBalance, 'updated_at' => new DateTime('now')));
    $balance = Bitcoin\getBalance($address, null);
    assertEqual($cachedBalance, $balance->numSatoshis);
    assertEqual($cachedBalance / Bitcoin\satoshisPerBTC(), $balance->numBTC);
}
Example #3
0
function getBalance($address, \DateInterval $maxCacheAge = null)
{
    if (empty($address) || trim($address) == '') {
        throw new InvalidAddress("Empty string/value is not valid");
    }
    $satoshis = null;
    $updatedAt = null;
    $needsUpdated = false;
    try {
        $row = DB\selectExactlyOne('bitcoin_addresses', 'address = ?', array($address));
        $satoshis = intval($row['satoshis']);
        if ($maxCacheAge) {
            $updatedAt = new DateTime($row['updated_at']);
            $expiresAt = $updatedAt->add($maxCacheAge);
            $now = new DateTime('now');
            if ($expiresAt->getTimestamp() < $now->getTimestamp()) {
                $needsUpdated = true;
            }
        }
    } catch (DB\NoMatchingRecords $_) {
        $needsUpdated = true;
    }
    if ($needsUpdated) {
        # Since we don't want to have two or three (or more) processes all trying to query
        # Blockchain.info at the same time, we use a lock to assure only one attempt is made
        # to update the cache.
        $lockObtained = withLock($address, function () use($address) {
            $satoshis = BlockchainDotInfo\getBalanceInSatoshis($address);
            cacheBalance($address, $satoshis);
        });
        if (!$lockObtained) {
            if ($satoshis === null) {
                Log\error("Failed to obtain lock for and no cached balance exists for Bitcoin address " . "{$address}; defaulting to zero");
            }
            $oneHourAgo = new DateTime('1 hour ago');
            if ($updatedAt && $updatedAt->getTimestamp() < $oneHourAgo->getTimestamp()) {
                Log\error("Balance for Bitcoin address {$address} has not been updated for " . "more than one hour");
            }
        }
    }
    //  $btcBalance = $satoshis / satoshisPerBTC();
    //  $balanceWithPrecision = $currency == 'BTC' ? $btcBalance : fromBTC($btcBalance, $currency);
    //  return $balanceWithPrecision;
    return new AmountOfBitcoin($satoshis);
}