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
void
blockstore_get_locator_hashes(const struct blockstore *bs,
                              uint256 **hash,
                              int *num)
{
   volatile struct blockentry *be;
   uint256 h[64];
   uint32 step = 1;
   int n = 0;

   *hash = NULL;
   *num = 0;

   be = bs->best_chain;
   while (be) {
      int i;

      ASSERT(n < ARRAYSIZE(h));
      hash256_calc((void *)&be->header, sizeof be->header, h + n);
      n++;
      if (n >= 10) {
         step *= 2;
      }
      for (i = 0; i < step && be; i++) {
         be = be->prev;
      }
   }
   *num = n;
   if (n > 0) {
      *hash = safe_malloc(n * sizeof(uint256));
      memcpy(*hash, h, n * sizeof(uint256));
   }
}
Ejemplo n.º 3
0
Archivo: txdb.c Proyecto: haraldh/bitc
int
txdb_handle_tx(struct txdb   *txdb,
               const uint256 *blkHash,
               const uint8   *buf,
               size_t         len,
               bool          *relevant)
{
    uint256 txHash;
    mtime_t ts = 0;
    bool txKnown;

    *relevant = 0;
    hash256_calc(buf, len, &txHash);

    txKnown = txdb_has_tx(txdb, &txHash);

    if (!uint256_iszero(blkHash)) {
        txdb_confirm_one_tx(txdb, blkHash, &txHash);
    }

    if (txKnown) {
        return 0;
    }

    if (uint256_iszero(blkHash)) {
        ts = time(NULL);
    } else {
        ts = blockstore_get_block_timestamp(btc->blockStore, blkHash);
    }

    return txdb_remember_tx(txdb, 0 /* save to disk */, ts, buf, len,
                            &txHash, blkHash, relevant);
}
Ejemplo n.º 4
0
void
blockstore_get_next_hashes(struct blockstore *bs,
                           const uint256 *start,
                           uint256 **hash,
                           int *n)
{
   struct blockentry *be;
   uint256 *table;
   int num;
   bool s;
   int i;

   i = 0;
   table = NULL;

   s = hashtable_lookup(bs->hash_blk, start, sizeof *start, (void*)&be);
   if (s == 0 || be->next == NULL) {
      goto exit;
   }

   be = be->next;
   num = 1000;
   table = safe_malloc(num * sizeof *table);

   while (be && i < num) {
      hash256_calc(&be->header, sizeof be->header, table + i);
      i++;
      be = be->next;
   }

exit:
   *n = i;
   *hash = table;
}
Ejemplo n.º 5
0
bool blockstore_add_header(struct blockstore *bs, const btc_block_header *hdr,
                           const uint256 *hash, bool *orphan) {
  static unsigned int count;
  struct blockentry *be;

  *orphan = 0;

  /*
   * The caller is supposed to compute the checksum of the header it's adding.
   * Verify that it doesn't get this wrong every few blocks.
   */
  count++;
  if ((count % 32) == 0) {
    uint256 hash0;
    hash256_calc(hdr, sizeof *hdr, &hash0);
    ASSERT(uint256_issame(hash, &hash0));
  }

  be = blockstore_lookup(bs, hash);
  if (be) {
    return 0;
  }

  ASSERT(blockstore_validate_chkpt(hash, bs->height + 1));
  ASSERT(bs->best_chain || uint256_issame(hash, &bs->genesis_hash));

  be = blockstore_alloc_entry(hdr);
  blockstore_add_entry(bs, be, hash);

  *orphan = be->height == -1;

  return 1;
}
Ejemplo n.º 6
0
static void script_tx_sighash(struct wallet *wallet, uint256 *hash,
                              const struct buff *scriptPubKey,
                              const struct btc_msg_tx *tx, uint32 idx,
                              enum script_hash_type hashType) {
  struct btc_msg_tx *tx2;
  struct buff *buf;
  int i;

  ASSERT(idx < tx->in_count);

  memset(hash, 0, sizeof *hash);
  tx2 = btc_msg_tx_dup(tx);

  Log(LGPFX " Computing sighash for txi-%u/%llu\n", idx, tx2->in_count);

  /*
   * Zero-out all the inputs' signatures.
   */
  for (i = 0; i < tx2->in_count; i++) {
    tx2->tx_in[i].scriptLength = 0;
  }

  size_t len = buff_maxlen(scriptPubKey);
  ASSERT(len > 0);

  ASSERT(tx2->tx_in[idx].scriptSig == NULL);
  ASSERT(tx2->tx_in[idx].scriptLength == 0);

  tx2->tx_in[idx].scriptLength = len;
  tx2->tx_in[idx].scriptSig = safe_malloc(len);

  memcpy(tx2->tx_in[idx].scriptSig, buff_base(scriptPubKey), len);

  ASSERT((hashType & 0x1f) == SIGHASH_ALL);

  /*
   * Final step:
   *
   * Serialize tx + hashType (as a uint32) and compute hash.
   */

  buf = buff_alloc();
  serialize_tx(buf, tx2);
  serialize_uint32(buf, hashType);
  hash256_calc(buff_base(buf), buff_curlen(buf), hash);
  buff_free(buf);

  btc_msg_tx_free(tx2);
  free(tx2);
}
Ejemplo n.º 7
0
bool
blockstore_is_next(struct blockstore *bs,
                   const uint256 *prev,
                   const uint256 *next)
{
   struct blockentry *be;
   uint256 hash;
   bool s;

   s = hashtable_lookup(bs->hash_blk, prev, sizeof *prev, (void*)&be);
   if (s == 0 || be->next == NULL) {
      return 0;
   }

   hash256_calc(&be->next->header, sizeof be->next->header, &hash);
   return uint256_issame(&hash, next);
}
Ejemplo n.º 8
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.º 9
0
bool blockstore_get_block_at_height(struct blockstore *bs, int height,
                                    uint256 *hash, btc_block_header *header) {
  struct blockentry *e;
  bool s = 0;

  mutex_lock(bs->lock);

  ASSERT(height <= bs->height);

  for (e = bs->best_chain; e != bs->genesis; e = e->prev) {
    if (e->height == height) {
      hash256_calc(&e->header, sizeof e->header, hash);
      *header = e->header;
      s = 1;
      break;
    }
  }

  mutex_unlock(bs->lock);

  return s;
}
Ejemplo n.º 10
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.º 11
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;
}
Ejemplo n.º 12
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;
}