Ejemplo n.º 1
0
static int
blockstore_set_chain_links(struct blockstore *bs,
                           struct blockentry *be)
{
   struct blockentry *prev;
   char hashStr[80];
   uint256 hash;
   bool s;

   hash256_calc(&be->header, sizeof be->header, &hash);
   uint256_snprintf_reverse(hashStr, sizeof hashStr, &hash);

   if (be->height >= 0) {
      struct blockentry *li;
      /*
       * We've reached the junction with the current/old best chain. All the
       * entries from now on need to be made orphans.
       */

      Log(LGPFX" Reached block %s\n", hashStr);

      li = be->next;
      while (li) {
         hash256_calc(&li->header, sizeof li->header, &hash);
         uint256_snprintf_reverse(hashStr, sizeof hashStr, &hash);
         Log(LGPFX" moving #%d %s from blk -> orphan\n", li->height, hashStr);
         s = hashtable_remove(bs->hash_blk, &hash, sizeof hash);
         ASSERT(s);
         li->height = -1;
         s = hashtable_insert(bs->hash_orphans, &hash, sizeof hash, li);
         ASSERT(s);
         li = li->next;
      }

      return be->height;
   }

   ASSERT(be->height == -1); // orphan

   prev = blockstore_lookup(bs, &be->header.prevBlock);
   ASSERT(prev);

   be->height = 1 + blockstore_set_chain_links(bs, prev);

   Log(LGPFX" moving #%d %s from orphan -> blk\n", be->height, hashStr);

   prev->next = be;
   be->prev = prev;

   s = hashtable_remove(bs->hash_orphans, &hash, sizeof hash);
   ASSERT(s);
   s = hashtable_insert(bs->hash_blk, &hash, sizeof hash, be);
   ASSERT(s);

   return be->height;
}
Ejemplo n.º 2
0
static bool
blockstore_validate_chkpt(const uint256 *hash,
                          uint32 height)
{
   struct block_cpt_entry *array;
   size_t n;
   int i;

   if (btc->testnet) {
      array = block_cpt_testnet;
      n = ARRAYSIZE(block_cpt_testnet);
   } else {
      array = block_cpt_main;
      n = ARRAYSIZE(block_cpt_main);
   }

   for (i = 0; i < n; i++) {
      if (height == array[i].height) {
         if (!uint256_issame(hash, &array[i].hash)) {
            char str[128];
            uint256_snprintf_reverse(str, sizeof str, hash);
            Warning(LGPFX" chkpt validation failed. height=%u %s\n",
                    height, str);
            return 0;
         }
         return 1;
      }
   }

   return 1;
}
Ejemplo n.º 3
0
Archivo: txdb.c Proyecto: 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);
}
Ejemplo n.º 4
0
int blockstore_get_block_height(struct blockstore *bs, const uint256 *hash) {
  struct blockentry *be;
  int height;
  bool s;

  if (uint256_iszero(hash)) {
    return 0;
  }

  mutex_lock(bs->lock);

  s = hashtable_lookup(bs->hash_blk, hash, sizeof *hash, (void *)&be);
  if (s == 0) {
    char hashStr[80];

    uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
    Panic(LGPFX " block %s not found.\n", hashStr);
  }

  height = be->height;

  mutex_unlock(bs->lock);

  return height;
}
Ejemplo n.º 5
0
time_t blockstore_get_block_timestamp(const struct blockstore *bs,
                                      const uint256 *hash) {
  struct blockentry *be;
  time_t ts = 0;

  mutex_lock(bs->lock);

  if (uint256_iszero(hash)) {
    goto done;
  }

  be = blockstore_lookup(bs, hash);
  if (be == NULL) {
    char hashStr[80];

    uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
    Panic(LGPFX " block %s not found.\n", hashStr);
  }

  ts = be->header.timestamp;

done:
  mutex_unlock(bs->lock);

  return ts;
}
Ejemplo n.º 6
0
void
bitc_ios_dashboard_update(void)
{
   btc_block_header hdr;
   char hashStr[80];
   char *ts = NULL;
   uint256 hash;
   int height;
   bool s;

   if (btc->blockStore == NULL) {
      return;
   }

   height = blockstore_get_height(btc->blockStore);
   if (height == 0) {
      return;
   }

   s = blockstore_get_block_at_height(btc->blockStore, height, &hash, &hdr);

   ASSERT(mutex_islocked(btcui->lock));

   uint256_snprintf_reverse(hashStr, sizeof hashStr, &hash);
   ts = print_time_local(hdr.timestamp, "%c");

   DashboardUpdate(height, hashStr,
                   btcui->num_peers_active,
                   btcui->num_peers_alive,
                   btcui->num_addrs,
                   ts ? ts : "");
   free(ts);
}
Ejemplo n.º 7
0
Archivo: txdb.c Proyecto: 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);
}
Ejemplo n.º 8
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);
   }
}
Ejemplo n.º 9
0
Archivo: txdb.c Proyecto: haraldh/bitc
static void
txdb_export_tx_cb(const void *key,
                  size_t keyLen,
                  void *cbData,
                  void *keyData)
{
    struct bitcui_tx **txiPtr = (struct bitcui_tx **)cbData;
    struct tx_entry *txe = (struct tx_entry *)keyData;
    struct bitcui_tx *txi = *txiPtr;
    char hashStr[80];

    if (txe->relevant == 0) {
        return;
    }

    /*
     * We need to weed out transactions that made it in an orphan block but were
     * not integrated later on in the main chain.
     */

    txi->src  = NULL;
    txi->dst  = NULL;
    txi->desc = NULL;

    ASSERT(keyLen == sizeof(uint256));
    memcpy(&txi->txHash, key, keyLen);
    txi->value  = txdb_get_tx_credit(&txe->tx);
    txi->value -= txdb_get_tx_debit(&txe->tx);

    txi->blockHeight = -1;
    if (!uint256_iszero(&txe->blkHash)) {
        txi->blockHeight = blockstore_get_block_height(btc->blockStore,
                           &txe->blkHash);
    }

    uint256_snprintf_reverse(hashStr, sizeof hashStr, (uint256*)key);
    txi->desc = config_getstring(btc->txLabelsCfg, NULL, "tx.%s.label", hashStr) ;
    /*
     * This is a workaround for a bug caused by truncated hashStr.
     */
    if (txi->desc == NULL) {
        hashStr[63] = '\0';
        txi->desc = config_getstring(btc->txLabelsCfg, NULL, "tx.%s.label", hashStr) ;
    }

    txi->timestamp = txe->timestamp;
    *txiPtr += 1;
}
Ejemplo n.º 10
0
Archivo: txdb.c Proyecto: haraldh/bitc
static int
txdb_save_tx(struct txdb   *txdb,
             const uint256 *blkHash,
             const uint256 *txHash,
             mtime_t        timestamp,
             const uint8   *buf,
             size_t         len)
{
    struct tx_ser_data txdata;
    struct buff *bufd;
    struct buff *bufk;
    char hashStr[80];
    char *err;

    err = NULL;
    memset(&txdata, 0, sizeof txdata);

    if (blkHash) {
        memcpy(&txdata.blkHash, blkHash, sizeof *blkHash);
    }

    txdata.buf       = (uint8 *)buf;
    txdata.len       = len;
    txdata.timestamp = timestamp;

    uint256_snprintf_reverse(hashStr, sizeof hashStr, txHash);
    bufk = txdb_serialize_tx_key(txdb->tx_seq, hashStr);
    bufd = txdb_serialize_tx_data(&txdata);

    leveldb_put(txdb->db, txdb->wr_opts,
                buff_base(bufk), buff_curlen(bufk),
                buff_base(bufd), buff_curlen(bufd),
                &err);

    buff_free(bufk);
    buff_free(bufd);

    if (err) {
        Warning(LGPFX" failed to save tx %s: %s\n", hashStr, err);
        free(err);
    }

    return err != NULL;
}
Ejemplo n.º 11
0
void
blockstore_get_hash_from_birth(const struct blockstore *bs,
                               time_t                   birth,
                               uint256                 *hash)
{
   struct blockentry *e;

   for (e = bs->best_chain; e != bs->genesis; e = e->prev)  {
      if (e->header.timestamp < birth) {
         char hashStr[80];
         uint64 ts = birth;

         hash256_calc(&e->header, sizeof e->header, hash);
         uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
         Log(LGPFX" birth %llu --> block %s.\n", ts, hashStr);
         return;
      }
   }
   memcpy(hash, &bs->genesis_hash, sizeof *hash);
}
Ejemplo n.º 12
0
time_t
blockstore_get_block_timestamp(const struct blockstore *bs,
                               const uint256 *hash)
{
   struct blockentry *be;

   if (uint256_iszero(hash)) {
      return 0;
   }

   be = blockstore_lookup(bs, hash);
   if (be == NULL) {
      char hashStr[80];

      uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
      Warning(LGPFX" block %s not found.\n", hashStr);
      ASSERT(0);
      return 0;
   }

   return be->header.timestamp;
}
Ejemplo n.º 13
0
Archivo: txdb.c Proyecto: 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));
}
Ejemplo n.º 14
0
int
blockstore_get_block_height(struct blockstore *bs,
                            const uint256 *hash)
{
   struct blockentry *be;
   bool s;

   if (uint256_iszero(hash)) {
      return 0;
   }

   s = hashtable_lookup(bs->hash_blk, hash, sizeof *hash, (void*)&be);
   if (s == 0) {
      char hashStr[80];

      uint256_snprintf_reverse(hashStr, sizeof hashStr, hash);
      Warning(LGPFX" block %s not found.\n", hashStr);
      //ASSERT(0);
      return 0;
   }

   return be->height;
}
Ejemplo n.º 15
0
static int
blockset_open_file(struct blockstore *blockStore,
                   struct blockset *bs)
{
   uint64 offset;
   mtime_t ts;
   int res;

   res = file_open(bs->filename, 0 /* R/O */, 0 /* !unbuf */, &bs->desc);
   if (res) {
      return res;
   }

   bs->filesize = file_getsize(bs->desc);
   if (bs->filesize < 0) {
      return errno;
   }

   if (bs->filesize > 0) {
      char *s = print_size(bs->filesize);
      char *name = file_getname(bs->filename);
      Log(LGPFX" reading file %s -- %s -- %llu headers.\n",
          name, s, bs->filesize / sizeof(btc_block_header));
      free(name);
      free(s);
   }

   ts = time_get();
   offset = 0;
   while (offset < bs->filesize) {
      btc_block_header buf[10000];
      size_t numRead;
      size_t numBytes;
      int numHeaders;
      int i;

      numBytes = MIN(bs->filesize - offset, sizeof buf);

      res = file_pread(bs->desc, offset, buf, numBytes, &numRead);
      if (res != 0) {
         break;
      }

      if (btc->stop != 0) {
         res = 1;
         NOT_TESTED();
         break;
      }

      numHeaders = numRead / sizeof(btc_block_header);
      for (i = 0; i < numHeaders; i++) {
         struct blockentry *be;
         uint256 hash;

         be = blockstore_alloc_entry(buf + i);
         be->written = 1;
         hash256_calc(buf + i, sizeof buf[0], &hash);

         if (!blockstore_validate_chkpt(&hash, blockStore->height + 1)) {
            return 1;
         }

         blockstore_add_entry(blockStore, be, &hash);

         if (i == numHeaders - 1) {
            bitcui_set_status("loading headers .. %llu%%",
                             (offset + numBytes) * 100 / bs->filesize);
         }
         if (i == numHeaders - 1 ||
             (numBytes < sizeof buf && i > numHeaders - 256)) {
            bitcui_set_last_block_info(&hash, blockStore->height,
                                      be->header.timestamp);
         }
      }

      offset += numRead;
   }

   ts = time_get() - ts;

   char hashStr[80];
   char *latStr;

   uint256_snprintf_reverse(hashStr, sizeof hashStr, &blockStore->best_hash);
   Log(LGPFX" loaded blocks up to %s\n", hashStr);
   latStr = print_latency(ts);
   Log(LGPFX" this took %s\n", latStr);
   free(latStr);

   return res;
}
Ejemplo n.º 16
0
Archivo: txdb.c Proyecto: haraldh/bitc
void
txdb_confirm_one_tx(struct txdb   *txdb,
                    const uint256 *blkHash,
                    const uint256 *txHash)
{
    leveldb_iterator_t *iter;
    struct tx_entry *txe;
    char bkHashStr[80];
    char txHashStr[80];

    ASSERT(!uint256_iszero(blkHash));
    ASSERT(!uint256_iszero(txHash));

    txe = txdb_get_tx_entry(txdb, txHash);
    if (txe == NULL) {
        return;
    }

    if (txe->relevant == 0) {
        txdb_remove_from_hashtable(txdb, txHash);
        NOT_TESTED();
        return;
    }

    if (!uint256_iszero(&txe->blkHash)) {
        /*
         * It's possible for the ASSERT below to fire if a tx is confirmed in
         * a block that is later orphaned. The tx should then be relayed again
         * until it finds its way in a new block.
         */
        ASSERT(uint256_issame(&txe->blkHash, blkHash));
        return;
    }

    peergroup_stop_broadcast_tx(btc->peerGroup, txHash);
    memcpy(&txe->blkHash, blkHash, sizeof *blkHash);

    uint256_snprintf_reverse(bkHashStr, sizeof bkHashStr, blkHash);
    uint256_snprintf_reverse(txHashStr, sizeof txHashStr, txHash);
    Warning(LGPFX" %s confirmed in %s\n", txHashStr, bkHashStr);

    NOT_TESTED();

    iter = leveldb_create_iterator(txdb->db, txdb->rd_opts);
    leveldb_iter_seek_to_first(iter);

    while (leveldb_iter_valid(iter)) {
        struct tx_ser_key *txkey;
        struct tx_ser_data *txdata;
        struct buff *buf;
        const char *key;
        const char *val;
        size_t klen;
        size_t vlen;
        char *err = NULL;

        key = leveldb_iter_key(iter, &klen);
        txkey = txdb_deserialize_tx_key(key, klen);

        if (txkey == NULL || uint256_issame(txHash, &txkey->txHash) == 0) {
            free(txkey);
            leveldb_iter_next(iter);
            continue;
        }

        NOT_TESTED();

        val = leveldb_iter_value(iter, &vlen);
        txdata = txdb_deserialize_tx_data(val, vlen);
        ASSERT(uint256_iszero(&txdata->blkHash));
        ASSERT(txdata->timestamp != 0);
        memcpy(&txdata->blkHash, blkHash, sizeof *blkHash);

        buf = txdb_serialize_tx_data(txdata);

        leveldb_put(txdb->db, txdb->wr_opts, key, klen,
                    buff_base(buf), buff_curlen(buf), &err);
        buff_free(buf);
        if (err) {
            Warning(LGPFX" failed to write tx entry: %s\n", err);
        }

        txdb_export_tx_info(txdb);

        free(txkey);
        free(txdata->buf);
        free(txdata);
        break;
    }
    leveldb_iter_destroy(iter);
}
Ejemplo n.º 17
0
Archivo: txdb.c Proyecto: 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;
}
Ejemplo n.º 18
0
Archivo: txdb.c Proyecto: 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;
}
Ejemplo n.º 19
0
Archivo: txdb.c Proyecto: haraldh/bitc
static void
txdb_process_tx_entry(struct txdb      *txdb,
                      const uint256    *txHash,
                      const uint256    *blkHash,
                      const btc_msg_tx *tx,
                      bool             *relevant)
{
    struct txo_entry *txo_entry;
    char hashStr[80];
    uint32 i;
    bool s;

    ASSERT(txdb);
    ASSERT(*relevant == 0);

    uint256_snprintf_reverse(hashStr, sizeof hashStr, txHash);
    Log(LGPFX" processing  %s\n", hashStr);

    /*
     * Look at all the tx referred to by the inputs. If any of these match
     * a txo for the wallet keys, we have a debit.
     */
    for (i = 0; i < tx->in_count; i++) {
        const btc_msg_tx_in *txi = tx->tx_in + i;
        /*
         * Look to see if the txi refers to one of our coins (a known txo). If
         * so, we need to mark it as spent.
         */
        txo_entry = txdb_lookup_txo(&txi->prevTxHash, txi->prevTxOutIdx);
        if (txo_entry == NULL) {
            continue;
        }

        ASSERT(txo_entry->spent == 0);
        txo_entry->spent = 1;
        *relevant = 1;
    }

    /*
     * Analyze all the txo to see if any credit our addresses.
     */
    for (i = 0; i < tx->out_count; i++) {
        char key[32 + 4]; // txHash + txo_idx
        const btc_msg_tx_out *txo = tx->tx_out + i;
        uint160 pub_key;

        if (script_parse_pubkey_hash(txo->scriptPubKey, txo->scriptLength, &pub_key)
                || !wallet_is_pubkey_hash160_mine(btc->wallet, &pub_key)) {
            continue;
        }
        *relevant = 1;

        memcpy(key,  txHash, sizeof(uint256));
        memcpy(key + 32, &i, sizeof(uint32));

        txo_entry = safe_malloc(sizeof *txo_entry);
        txo_entry->spent     = 0;
        txo_entry->value     = txo->value;
        txo_entry->btc_addr  = b58_pubkey_from_uint160(&pub_key);
        txo_entry->outIdx    = i;
        txo_entry->spendable = wallet_is_pubkey_spendable(btc->wallet, &pub_key);
        memcpy(&txo_entry->txHash, txHash,  sizeof *txHash);
        if (blkHash) {
            memcpy(&txo_entry->blkHash, blkHash, sizeof *blkHash);
        } else {
            memset(&txo_entry->blkHash, 0, sizeof txo_entry->blkHash);
        }

        s = hashtable_insert(txdb->hash_txo, key, sizeof key, txo_entry);
        ASSERT(s);
    }
}
Ejemplo n.º 20
0
Archivo: txdb.c Proyecto: haraldh/bitc
static int
txdb_load_tx(struct txdb *txdb,
             const char  *key,
             size_t       klen,
             const char  *val,
             size_t       vlen)
{
    struct tx_ser_data *txd;
    struct tx_ser_key *txk;
    char hashStr[80];
    bool relevant = 0;
    uint256 txHash;
    bool confirmed;
    int res = 0;

    ASSERT(strncmp(key, "/tx/", 4) == 0);

    txk = txdb_deserialize_tx_key(key, klen);
    txd = txdb_deserialize_tx_data(val, vlen);

    ASSERT(txdb->tx_seq == txk->seq);
    txdb->tx_seq++;

    confirmed = !uint256_iszero(&txd->blkHash);

    hash256_calc(txd->buf, txd->len, &txHash);
    ASSERT(uint256_issame(&txHash, &txk->txHash));
    uint256_snprintf_reverse(hashStr, sizeof hashStr, &txHash);
    LOG(1, (LGPFX" loading %ctx %s\n", confirmed ? 'c' : 'u', hashStr));

    res = txdb_remember_tx(txdb, 1 /* not on disk, just hashtable */,
                           txd->timestamp, txd->buf, txd->len,
                           &txk->txHash, &txd->blkHash, &relevant);

    /*
     * If the transaction is still unconfirmed, add to relay set.
     */
    if (!confirmed) {
        struct buff buf;
        int numSec;

        numSec = time(NULL) - txd->timestamp;

        if (numSec > 0) {
            int hours = numSec / (60 * 60);
            int min  = (numSec % (60 * 60)) / 60;

            Log(LGPFX" unconfirmed tx %s was sent %d hours %d min ago.\n",
                hashStr, hours, min);
        }

        buff_init(&buf, txd->buf, txd->len);

        Log(LGPFX" adding tx %s to relay-set\n", hashStr);
        peergroup_new_tx_broadcast(btc->peerGroup, &buf,
                                   txd->timestamp + 2 * 60 * 60,
                                   &txHash);
    } else {
        uint256_snprintf_reverse(hashStr, sizeof hashStr, &txd->blkHash);
        Log(LGPFX" tx in block %s\n", hashStr);
    }

    free(txd->buf);
    free(txd);
    free(txk);

    return res;
}