Ejemplo n.º 1
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.º 2
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.º 3
0
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;
}
Ejemplo n.º 4
0
int deserialize_block(struct buff *buf, btc_msg_block *blk) {
  uint64 i;
  int res;

  res = deserialize_blockheader(buf, &blk->header);
  btcmsg_print_header(&blk->header);
  res |= deserialize_varint(buf, &blk->txCount);
  Warning("numTx=%llu\n", blk->txCount);

  blk->tx = safe_malloc(blk->txCount * sizeof *blk->tx);

  for (i = 0; i < blk->txCount; i++) {
    res |= deserialize_tx(buf, blk->tx + i);
  }

  Warning("sz: %zu vs %zu\n", buff_curlen(buf), buff_maxlen(buf));
  ASSERT(buff_space_left(buf) == 0);

  return res;
}
Ejemplo n.º 5
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.º 6
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.º 7
0
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;
}