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); }
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; }
int script_txo_generate(const uint160 *pubkey, uint8 **script, uint64 *scriptLen) { struct buff *buf = buff_alloc(); serialize_uint8(buf, OP_DUP); serialize_uint8(buf, OP_HASH160); script_push_data(buf, pubkey, sizeof *pubkey); serialize_uint8(buf, OP_EQUALVERIFY); serialize_uint8(buf, OP_CHECKSIG); *script = buff_base(buf); *scriptLen = buff_curlen(buf); free(buf); return 0; }
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; }
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); }
int script_sign(struct wallet *wallet, const struct btc_msg_tx_out *txo, struct btc_msg_tx *tx, uint32 idx, enum script_hash_type hashType) { struct btc_msg_tx_in *txi; enum script_txout_type type; struct buff *scriptSig; struct buff scriptPubKey; uint8 *data_addr; size_t data_len; uint256 hash; int res; ASSERT(idx < tx->in_count); scriptSig = buff_alloc(); buff_init(&scriptPubKey, txo->scriptPubKey, txo->scriptLength); Log_Bytes("scriptPubKey:", txo->scriptPubKey, txo->scriptLength); script_tx_sighash(wallet, &hash, &scriptPubKey, tx, idx, hashType); res = script_match_type(&scriptPubKey, &type, &data_addr, &data_len); if (res) { NOT_TESTED(); goto exit; } switch (type) { case TX_PUBKEY: Warning(LGPFX " script TX_PUBKEY\n"); NOT_IMPLEMENTED(); break; case TX_PUBKEYHASH: (void)0; // XXX: clang bug? uint160 *keyHash = (uint160 *)data_addr; ASSERT(data_len == sizeof(uint160)); res = script_sign_hash(wallet, keyHash, &hash, hashType, scriptSig); if (res) { NOT_TESTED(); goto exit; } res = script_push_pubkey(wallet, keyHash, scriptSig); if (res) { NOT_TESTED(); goto exit; } break; default: NOT_IMPLEMENTED(); Warning(LGPFX " script TX_NONSTANDARD\n"); break; } txi = tx->tx_in + idx; txi->scriptLength = buff_curlen(scriptSig); txi->scriptSig = buff_base(scriptSig); exit: free(scriptSig); free(data_addr); return res; }