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; }
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); } }
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; }
void bitcui_set_last_block_info(const uint256 *hash, int height, uint32 timestamp) { if (ui.inuse == 0) { return; } if (btcui->numBlocks > 0 && uint256_issame(hash, &btcui->blocks[btcui->blockProdIdx].hash)) { return; } mutex_lock(btcui->lock); if (btcui->numBlocks < ARRAYSIZE(btcui->blocks)) { btcui->numBlocks++; } btcui->blockProdIdx = (btcui->blockProdIdx + 1) % ARRAYSIZE(btcui->blocks); btcui->blocks[btcui->blockProdIdx].hash = *hash; btcui->blocks[btcui->blockProdIdx].height = height; btcui->blocks[btcui->blockProdIdx].timestamp = timestamp; btcui->height = height; mutex_unlock(btcui->lock); bitcui_req_notify_info_update(); }
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); }
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; }
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); }