Exemplo n.º 1
0
Arquivo: txdb.c Projeto: haraldh/bitc
static void
txdb_print_coins(const struct txdb *txdb,
                 bool onlyUnspent)
{
    struct txo_entry *txo_array = NULL;
    int i;
    int n;

    n = hashtable_getnumentries(txdb->hash_txo);
    if (n == 0) {
        Log(LGPFX" %s: no coins found\n", __FUNCTION__);
        return;
    }

    hashtable_linearize(txdb->hash_txo, sizeof *txo_array, (void *)&txo_array);
    ASSERT(txo_array);
    Log(LGPFX" %s: %d coins available:\n", __FUNCTION__, n);

    for (i = 0; i < n; i++) {
        struct txo_entry *txo_ent = txo_array + i;
        char hashStr[80];

        if (onlyUnspent && txo_ent->spent) {
            continue;
        }

        uint256_snprintf_reverse(hashStr, sizeof hashStr, &txo_ent->txHash);
        Log(LGPFX" txo%03d: %s sp=%u id=%3u v=%llu\n",
            i, txo_ent->btc_addr, txo_ent->spent, txo_ent->outIdx, txo_ent->value);
    }
    free(txo_array);
}
Exemplo n.º 2
0
Arquivo: txdb.c Projeto: haraldh/bitc
void
txdb_export_tx_info(struct txdb *txdb)
{
    struct bitcui_tx *tx_info;
    struct bitcui_tx *ti;
    int tx_num;

    if (btcui->inuse == 0) {
        return;
    }

    /*
     * We may have in hash_tx some entries that are not relevant to our wallet
     * but whose presence is still useful for performance reasons. It's possible
     * we allocate too much memory for tx_info but that's fine for now.
     */
    tx_num  = hashtable_getnumentries(txdb->hash_tx);
    tx_info = safe_calloc(tx_num, sizeof *tx_info);
    ti = tx_info;

    hashtable_for_each(txdb->hash_tx, txdb_export_tx_cb, &ti);
    ASSERT(ti <= tx_info + tx_num);
    tx_num = ti - tx_info;

    qsort(tx_info, tx_num, sizeof *tx_info, txdb_bitcui_tx_entry_compare_cb);
    bitcui_set_tx_info(tx_num, tx_info);
}
Exemplo n.º 3
0
static int
wallet_save_keys(struct wallet *wallet)
{
   struct config *cfg;
   int res;
   int n;

   n = hashtable_getnumentries(wallet->hash_keys);

   Log(LGPFX" saving %u key%s in %sencrypted wallet %s.\n",
       n, n > 1 ? "s" : "",
       wallet->pass ? "encrypted" : "NON-",
       wallet->filename);

   cfg = config_create();
   config_setint64(cfg, n, "numKeys");

   if (wallet->pass) {
      char saltStr[80];
      int64 count = 0;
      bool s;

      res = RAND_bytes(wallet->ckey->salt, sizeof wallet->ckey->salt);
      if (res != 1) {
         res = ERR_get_error();
         Log(LGPFX" RAND_bytes failed: %d\n", res);
         goto exit;
      }
      str_snprintf_bytes(saltStr, sizeof saltStr, NULL,
                         wallet->ckey->salt, sizeof wallet->ckey->salt);
      config_setstring(cfg, saltStr, "encryption.salt");
      s = crypt_set_key_from_passphrase(wallet->pass, wallet->ckey, &count);
      ASSERT(s);
      ASSERT(count >= CRYPT_NUM_ITERATIONS_OLD);
      config_setint64(cfg, count, "encryption.numIterations");
   }

   hashtable_for_each(wallet->hash_keys, wallet_save_key_cb, cfg);

   file_rotate(wallet->filename, 1);
   res = file_create(wallet->filename);
   if (res) {
      Log(LGPFX" failed to create file '%s': %s\n",
          wallet->filename, strerror(res));
      goto exit;
   }
   res = file_chmod(wallet->filename, 0600);
   if (res) {
      Log(LGPFX" failed to chmod 0600 wallet.dat: %s\n",
          strerror(res));
      goto exit;
   }
   res = config_write(cfg, wallet->filename);

exit:
   config_free(cfg);

   return res;
}
Exemplo n.º 4
0
static void
blockstore_add_entry(struct blockstore *bs,
                     struct blockentry *be,
                     const uint256 *hash)
{
   bool s;

   if (bs->best_chain == NULL) {

      s = hashtable_insert(bs->hash_blk, hash, sizeof *hash, be);

      ASSERT(s);
      ASSERT(uint256_issame(hash, &bs->genesis_hash));
      ASSERT(be->prev == NULL);
      ASSERT(bs->height);

      bs->best_chain = be;
      bs->genesis = be;
      bs->height  = 0;
      be->height  = 0;

      memcpy(&bs->best_hash, hash, sizeof *hash);
   } else if (uint256_issame(&be->header.prevBlock, &bs->best_hash)) {

      s = hashtable_insert(bs->hash_blk, hash, sizeof *hash, be);
      ASSERT(s);

      bs->height++;
      be->height = bs->height;

      bs->best_chain->next = be;
      be->prev = bs->best_chain;
      bs->best_chain = be;

      memcpy(&bs->best_hash, hash, sizeof *hash);
   } else {
      char hashStr[80];
      uint32 count;

      be->height = -1;
      count = hashtable_getnumentries(bs->hash_orphans);

      uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
      Log(LGPFX" block %s orphaned. %u orphan%s total.\n",
          hashStr, count, count > 1 ? "s" : "");

      s = hashtable_insert(bs->hash_orphans, hash, sizeof *hash, be);
      ASSERT(s);

      blockstore_set_best_chain(bs, be, hash);
   }
}
Exemplo n.º 5
0
Arquivo: txdb.c Projeto: haraldh/bitc
static void
txdb_select_coins(struct txdb              *txdb,
                  const struct btc_tx_desc *desc,
                  btc_msg_tx               *tx,
                  uint64                   *change)
{
    struct txo_entry *txo_array;
    uint64 value;
    int txo_num;
    int i;

    i = 0;
    value = 0;
    tx->in_count = 0;
    txo_array = txdb_get_coins_sorted(txdb);
    txo_num = hashtable_getnumentries(txdb->hash_txo);

    /*
     * txo_array is sorted in chronological order, so we'll be consuming old
     * coins first.
     */
    Log(LGPFX" select_coins: total_value=%llu fee=%llu\n",
        desc->total_value, desc->fee);

    while (value < (desc->total_value + desc->fee) && i < txo_num) {
        struct txo_entry *txo_ent = &txo_array[i++];
        char hashStr[80];

        if (txo_ent->spent == 1 ||
                txo_ent->spendable == 0) {
            continue;
        }
        if (uint256_iszero(&txo_ent->blkHash)) {
            NOT_TESTED();
            continue;
        }

        uint256_snprintf_reverse(hashStr, sizeof hashStr, &txo_ent->txHash);
        Log(LGPFX" using txo for %s id=%3u of %s\n",
            txo_ent->btc_addr, txo_ent->outIdx, hashStr);
        value += txo_ent->value;
        memcpy(&tx->tx_in[tx->in_count].prevTxHash, &txo_ent->txHash, sizeof txo_ent->txHash);
        tx->tx_in[tx->in_count].prevTxOutIdx = txo_ent->outIdx;
        tx->tx_in[tx->in_count].sequence = UINT_MAX;
        tx->in_count++;
    }

    ASSERT(value >= desc->total_value);
    *change = value - desc->total_value - desc->fee;
    Log(LGPFX" change=%llu\n", *change);
    free(txo_array);
}
Exemplo n.º 6
0
Arquivo: txdb.c Projeto: haraldh/bitc
static struct txo_entry *
txdb_get_coins_sorted(struct txdb *txdb)
{
    struct txo_entry *ptr = NULL;
    int n;

    hashtable_linearize(txdb->hash_txo, sizeof(struct txo_entry), (void*)&ptr);
    ASSERT(ptr);

    n = hashtable_getnumentries(txdb->hash_txo);

    qsort(ptr, n, sizeof *ptr, txdb_txo_entry_compare_cb);

    return ptr;
}
Exemplo n.º 7
0
static void
wallet_export_bitcoin_addrs(const struct wallet *wallet,
                            struct bitcui_addr **addrsOut,
                            int *numAddr)
{
   struct bitcui_addr *addrs;

   *numAddr = hashtable_getnumentries(wallet->hash_keys);
   addrs = safe_malloc(*numAddr * sizeof(struct bitcui_addr));

   *addrsOut = addrs;

   hashtable_for_each(wallet->hash_keys, wallet_export_addrs_cb, &addrs);

   qsort(*addrsOut, *numAddr, sizeof *addrs, wallet_addr_info_compare);
}
Exemplo n.º 8
0
Arquivo: txdb.c Projeto: haraldh/bitc
static void
txdb_remove_from_hashtable(struct txdb      *txdb,
                           const uint256    *txHash)
{
    struct tx_entry *txe;
    char hashStr[80];
    bool s;

    txe = txdb_get_tx_entry(txdb, txHash);
    if (txe == NULL || txe->relevant == 1) {
        NOT_TESTED();
        return;
    }

    txdb_free_tx_entry(txe);

    uint256_snprintf_reverse(hashStr, sizeof hashStr, txHash);

    s = hashtable_remove(txdb->hash_tx, txHash, sizeof *txHash);
    Warning(LGPFX" %s removed from hash_tx: %d (count=%u)\n",
            hashStr, s, hashtable_getnumentries(txdb->hash_tx));
}
Exemplo n.º 9
0
Arquivo: txdb.c Projeto: haraldh/bitc
int
txdb_craft_tx(struct txdb              *txdb,
              const struct btc_tx_desc *tx_desc,
              btc_msg_tx               *tx)
{
    struct buff *buf;
    char hashStr[80];
    uint256 txHash;
    uint64 change;
    uint32 numCoins;
    bool relevant;
    mtime_t ts;
    int res;

    res = 0;
    relevant = 0;
    tx->version = 1;
    txdb_prepare_txout(tx_desc, tx);

    /*
     * In order to properly size 'tx->txIn', we need to determine how many coins
     * we're going to use. Right now, let's just vastly overestimate.
     */
    numCoins = hashtable_getnumentries(txdb->hash_txo);
    tx->tx_in = safe_calloc(numCoins, sizeof *tx->tx_in);

    txdb_print_coins(txdb, 1);
    txdb_select_coins(txdb, tx_desc, tx, &change);

    /*
     * Change! XXX: fix me.
     */
    if (change > 0) {
        const char *btc_change;

        btc_change = wallet_get_change_addr(btc->wallet);
        tx->out_count++;
        txdb_set_txo(tx, tx->out_count - 1, btc_change, change);
        Warning(LGPFX" change: %llu -- %.8f BTC\n", change, change / ONE_BTC);
    }

    txdb_sign_tx_inputs(txdb, tx);

    /*
     * Now that the tx is ready, serialize it and check that it's not too big.
     */
    btcmsg_print_tx(tx);

    buf = buff_alloc();
    serialize_tx(buf, tx);
    if (buff_curlen(buf) > BTC_TX_MAX_SIZE) {
        Warning(LGPFX" tx too large: %zu\n", buff_curlen(buf));
        res = 1;
        goto exit;
    }

    hash256_calc(buff_base(buf), buff_curlen(buf), &txHash);

    uint256_snprintf_reverse(hashStr, sizeof hashStr, &txHash);
    Warning(LGPFX" %s (%zu bytes)\n", hashStr, buff_curlen(buf));
    Log_Bytes(LGPFX" TX: ", buff_base(buf), buff_curlen(buf));

    if (bitc_testing) {
        Warning("TESTING! Not saving/relaying tx.\n");
        goto exit;
    }

    ts = time(NULL);

    res = txdb_remember_tx(txdb, 0 /* save to disk */, ts,
                           buff_base(buf), buff_curlen(buf),
                           &txHash, NULL, &relevant);

    txdb_save_tx_label(tx_desc, hashStr);
    txdb_export_tx_info(txdb);

    res = peergroup_new_tx_broadcast(btc->peerGroup, buf,
                                     ts + 2 * 60 * 60, &txHash);
    if (res) {
        Warning(LGPFX" failed to transmit tx: %d\n", res);
        bitcui_set_status("got errors while broadcasting tx");
    }
exit:
    buff_free(buf);
    /*
     * XXX: We should mark the coins used by this tx as "reserved", so that we
     * do not attempt to use conflicting coins in subsequent TXs.
     */
    return res;
}
Exemplo n.º 10
0
Arquivo: txdb.c Projeto: haraldh/bitc
static int
txdb_remember_tx(struct txdb   *txdb,
                 bool           alreadySaved,
                 mtime_t        ts,
                 const uint8   *buf,
                 size_t         len,
                 const uint256 *txHash,
                 const uint256 *blkHash,
                 bool          *relevant)
{
    struct tx_entry *txe;
    char hashStr[80];
    int res;

    ASSERT(txHash);
    ASSERT(relevant);

    *relevant = 0;

    /*
     * We always store the tx in the memory pool, that way we know quickly
     * whether we've already seen it.
     */
    res = txdb_add_to_hashtable(txdb, buf, len, txHash, blkHash, ts, &txe);
    if (res) {
        NOT_TESTED();
        return res;
    }

    uint256_snprintf_reverse(hashStr, sizeof hashStr, txHash);
    txdb_process_tx_entry(txdb, txHash, blkHash, &txe->tx, &txe->relevant);
    if (txe->relevant == 0) {
        Warning(LGPFX" tx %s not relevant (%u)\n",
                hashStr, hashtable_getnumentries(txdb->hash_tx));
        return 0;
    }

    if (alreadySaved) {
        return 0;
    }

    /*
     * OK -- this transaction is relevant to our wallet.
     */
    *relevant = 1;
    Warning(LGPFX" tx %s ok (%u)\n", hashStr, hashtable_getnumentries(txdb->hash_tx));

    res = txdb_save_tx(txdb, blkHash, txHash, ts, buf, len);
    if (res == 0) {
        txdb->tx_seq++;
    }

    txdb_export_tx_info(txdb);
    if (bitc_state_ready()) {
        int64 value = txdb_get_tx_credit(&txe->tx) - txdb_get_tx_debit(&txe->tx);

        bitcui_set_status("New payment %s: %.8f BTC",
                          value > 0 ? "received" : "made",
                          1.0 * value / ONE_BTC);
    }

    return res;
}
Exemplo n.º 11
0
static bool
wallet_alloc_key(struct wallet *wallet,
                 const char    *priv,
                 const char    *pub,
                 const char    *desc,
                 time_t         birth,
                 bool           spendable)
{
   struct wallet_key *wkey;
   struct key *key;
   uint160 pub_key;
   size_t len;
   uint8 *buf;
   bool s;

   ASSERT(priv);

   key = NULL;
   buf = NULL;
   len = 0;
   memset(&pub_key, 0, sizeof pub_key);

   if (btc->wallet_state == WALLET_ENCRYPTED_LOCKED) {
      if (wallet->pass) {
         struct secure_area *sec_b58;
         uint8 *encPrivKey;
         size_t encLen;

         if (!wallet_verify_hmac(wallet, priv, &encPrivKey, &encLen)) {
            return 0;
         }

         s = crypt_decrypt(wallet->ckey, encPrivKey, encLen, &sec_b58);
         free(encPrivKey);
         ASSERT(s);
         /*
          * 'buf' is a sensitive buffer here. It should be backed by
          * a struct secure_area.
          */
         s = b58_privkey_to_bytes((char *)sec_b58->buf, &buf, &len);
         secure_free(sec_b58);
         ASSERT(s);
      } else {
         uint8 *pkey;
         size_t plen;

         str_to_bytes(pub, &pkey, &plen);
         hash160_calc(pkey, plen, &pub_key);
         free(pkey);
      }
   } else {
      s = b58_privkey_to_bytes(priv, &buf, &len);
      ASSERT(s);
   }

   if (buf) {
      key = key_alloc();
      key_set_privkey(key, buf, len);
      memset(buf, 0, len);
      free(buf);
      key_get_pubkey_hash160(key, &pub_key);
   }
   ASSERT(!uint160_iszero(&pub_key));

   wkey = safe_calloc(1, sizeof *wkey);
   wkey->cfg_idx   = hashtable_getnumentries(wallet->hash_keys);
   wkey->btc_addr  = b58_pubkey_from_uint160(&pub_key);
   wkey->desc      = desc ? safe_strdup(desc) : NULL;
   wkey->pub_key   = pub_key;
   wkey->birth     = birth;
   wkey->key       = key;
   wkey->spendable = spendable;

   if (spendable == 0) {
      Log(LGPFX" funds on %s are not spendable.\n", wkey->btc_addr);
   }

   s = hashtable_insert(wallet->hash_keys, &pub_key, sizeof pub_key, wkey);
   ASSERT(s);

   return 1;
}