static bool nc_msg_block(struct nc_conn *conn) { struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len }; struct bp_block block; bp_block_init(&block); bool rc = false; if (!deser_bp_block(&block, &buf)) goto out; bp_block_calc_sha256(&block); char hexstr[BU256_STRSZ]; bu256_hex(hexstr, &block.sha256); if (debugging) { fprintf(plog, "net: %s block %s\n", conn->addr_str, hexstr); } if (!bp_block_valid(&block)) { fprintf(plog, "net: %s invalid block %s\n", conn->addr_str, hexstr); goto out; } /* check for duplicate block */ if (blkdb_lookup(&db, &block.sha256) || have_orphan(&block.sha256)) goto out_ok; struct iovec iov[2]; iov[0].iov_base = &conn->msg.hdr; // TODO: endian bug? iov[0].iov_len = sizeof(conn->msg.hdr); iov[1].iov_base = (void *) buf.p; // cast away 'const' iov[1].iov_len = buf.len; size_t total_write = iov[0].iov_len + iov[1].iov_len; /* store current file position */ off64_t fpos64 = lseek64(blocks_fd, 0, SEEK_CUR); if (fpos64 == (off64_t)-1) { fprintf(plog, "blocks: lseek64 failed %s\n", strerror(errno)); goto out; } /* write new block to disk */ errno = 0; ssize_t bwritten = writev(blocks_fd, iov, ARRAY_SIZE(iov)); if (bwritten != total_write) { fprintf(plog, "blocks: write failed %s\n", strerror(errno)); goto out; } /* process block */ if (!process_block(&block, fpos64)) { fprintf(plog, "blocks: process-block failed\n"); goto out; } out_ok: rc = true; out: bp_block_free(&block); return rc; }
static bool blkdb_connect(struct blkdb *db, struct blkinfo *bi, struct blkdb_reorg *reorg_info) { memset(reorg_info, 0, sizeof(*reorg_info)); if (blkdb_lookup(db, &bi->hash)) return false; bool rc = false; BIGNUM cur_work; BN_init(&cur_work); u256_from_compact(&cur_work, bi->hdr.nBits); bool best_chain = false; /* verify genesis block matches first record */ if (bp_hashtab_size(db->blocks) == 0) { if (!bu256_equal(&bi->hdr.sha256, &db->block0)) goto out; /* bi->prev = NULL; */ bi->height = 0; BN_copy(&bi->work, &cur_work); best_chain = true; } /* lookup and verify previous block */ else { struct blkinfo *prev = blkdb_lookup(db, &bi->hdr.hashPrevBlock); if (!prev) goto out; bi->prev = prev; bi->height = prev->height + 1; if (!BN_add(&bi->work, &cur_work, &prev->work)) goto out; if (BN_cmp(&bi->work, &db->best_chain->work) > 0) best_chain = true; } /* add to block map */ bp_hashtab_put(db->blocks, &bi->hash, bi); /* if new best chain found, update pointers */ if (best_chain) { struct blkinfo *old_best = db->best_chain; struct blkinfo *new_best = bi; reorg_info->old_best = old_best; /* likely case: new best chain has greater height */ if (!old_best) { while (new_best) { new_best = new_best->prev; reorg_info->conn++; } } else { while (new_best && (new_best->height > old_best->height)) { new_best = new_best->prev; reorg_info->conn++; } } /* unlikely case: old best chain has greater height */ while (old_best && new_best && (old_best->height > new_best->height)) { old_best = old_best->prev; reorg_info->disconn++; } /* height matches, but we are still walking parallel chains */ while (old_best && new_best && (old_best != new_best)) { new_best = new_best->prev; reorg_info->conn++; old_best = old_best->prev; reorg_info->disconn++; } /* reorg analyzed. update database's best-chain pointer */ db->best_chain = bi; } rc = true; out: BN_clear_free(&cur_work); return rc; }
/* * struct msg_vinv { parr *invs; array of bp_inv }; struct bp_inv { uint32_t type; bu256_t hash; }; * * */ static bool nc_msg_inv(struct nc_conn *conn) { struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len }; struct msg_vinv mv, mv_out; bool rc = false; unsigned int i=0; int msg_tx, msg_block, msg_other; msg_tx = msg_block = msg_other = 0; msg_vinv_init(&mv);//memset msg_vinv_init(&mv_out);//memset if (!deser_msg_vinv(&mv, &buf)) goto out; if (mv.invs){ //LOG("Peer [%s] gave %d inventory vectors",conn->addr_str, mv.invs->len); for (i = 0;i < mv.invs->len; i++){ struct bp_inv *inv = parr_idx(mv.invs, 0); switch (inv->type){ case MSG_TX: msg_tx++; break; case MSG_BLOCK: msg_block++; break; default: msg_other++; } } if (mv.invs->len > 0){ LOG("Inventory vectors: msg[%d], block[%d], other[%d]", msg_tx, msg_block, msg_other); } } if (debugging && mv.invs && mv.invs->len == 1) { struct bp_inv *inv = parr_idx(mv.invs, 0); char hexstr[BU256_STRSZ]; bu256_hex(hexstr, &inv->hash); char typestr[32]; switch (inv->type) { case MSG_TX: strcpy(typestr, "tx"); break; case MSG_BLOCK: strcpy(typestr, "block"); break; default: sprintf(typestr, "unknown 0x%x", inv->type); break; } fprintf(plog, "net: %s inv %s %s\n", conn->addr_str, typestr, hexstr); } else if (debugging && mv.invs) { fprintf(plog, "net: %s inv (%zu sz)\n", conn->addr_str, mv.invs->len); } if (!mv.invs || !mv.invs->len) goto out_ok; /* scan incoming inv's for interesting material */ /*declared at beginnning of function--> unsigned int i;*/ for (i = 0; i < mv.invs->len; i++) { struct bp_inv *inv = parr_idx(mv.invs, i); switch (inv->type) { case MSG_BLOCK: if (!blkdb_lookup(&db, &inv->hash) && !have_orphan(&inv->hash)) msg_vinv_push(&mv_out, MSG_BLOCK, &inv->hash); break; case MSG_TX: default: break; } } /* send getdata, if they have anything we want */ if (mv_out.invs && mv_out.invs->len) { cstring *s = ser_msg_vinv(&mv_out); rc = nc_conn_send(conn, "getdata", s->str, s->len); cstr_free(s, true); } out_ok: rc = true; out: msg_vinv_free(&mv); msg_vinv_free(&mv_out); return rc; }