static void runtest(const char *json_fn_base, const char *ser_fn_base) { char *fn = test_filename(json_fn_base); json_t *meta = read_json(fn); assert(json_is_object(meta)); char *ser_fn = test_filename(ser_fn_base); void *data = NULL; size_t data_len = 0; bool rc = bu_read_file(ser_fn, &data, &data_len, 100 * 1024 * 1024); assert(rc); const char *hashstr = json_string_value(json_object_get(meta, "hash")); assert(hashstr != NULL); unsigned int size = json_integer_value(json_object_get(meta, "size")); assert(data_len == size); struct bp_tx tx; bp_tx_init(&tx); struct const_buffer buf = { data, data_len }; rc = deser_bp_tx(&tx, &buf); assert(rc); cstring *gs = cstr_new_sz(10000); ser_bp_tx(gs, &tx); if (gs->len != data_len) { fprintf(stderr, "gs->len %ld, data_len %lu\n", (long)gs->len, data_len); assert(gs->len == data_len); } assert(memcmp(gs->str, data, data_len) == 0); bp_tx_calc_sha256(&tx); char hexstr[BU256_STRSZ]; bu256_hex(hexstr, &tx.sha256); if (strcmp(hexstr, hashstr)) { fprintf(stderr, "tx: wanted hash %s,\n got hash %s\n", hashstr, hexstr); assert(!strcmp(hexstr, hashstr)); } assert(tx.vin->len == 1); assert(tx.vout->len == 2); struct bp_tx tx_copy; bp_tx_init(&tx_copy); bp_tx_copy(&tx_copy, &tx); bp_tx_calc_sha256(&tx_copy); assert(bu256_equal(&tx_copy.sha256, &tx.sha256) == true); bp_tx_free(&tx); bp_tx_free(&tx_copy); cstr_free(gs, true); free(data); free(fn); free(ser_fn); json_decref(meta); }
void bp_tx_sighash(bu256_t *hash, const GString *scriptCode, const struct bp_tx *txTo, unsigned int nIn, int nHashType) { if (nIn >= txTo->vin->len) { bu256_set_u64(hash, 1); goto out; } struct bp_tx txTmp; bp_tx_init(&txTmp); bp_tx_copy(&txTmp, txTo); /* TODO: find-and-delete OP_CODESEPARATOR from scriptCode */ /* Blank out other inputs' signatures */ unsigned int i; struct bp_txin *txin; for (i = 0; i < txTmp.vin->len; i++) { txin = g_ptr_array_index(txTmp.vin, i); g_string_set_size(txin->scriptSig, 0); if (i == nIn) g_string_append_len(txin->scriptSig, scriptCode->str, scriptCode->len); } /* Blank out some of the outputs */ if ((nHashType & 0x1f) == SIGHASH_NONE) { /* Wildcard payee */ bp_tx_free_vout(&txTmp); txTmp.vout = g_ptr_array_new_full(1, g_free); /* Let the others update at will */ for (i = 0; i < txTmp.vin->len; i++) { txin = g_ptr_array_index(txTmp.vin, i); if (i != nIn) txin->nSequence = 0; } } else if ((nHashType & 0x1f) == SIGHASH_SINGLE) { /* Only lock-in the txout payee at same index as txin */ unsigned int nOut = nIn; if (nOut >= txTmp.vout->len) { bu256_set_u64(hash, 1); goto out; } g_ptr_array_set_size(txTmp.vout, nOut + 1); for (i = 0; i < nOut; i++) { struct bp_txout *txout; txout = g_ptr_array_index(txTmp.vout, i); bp_txout_set_null(txout); } /* Let the others update at will */ for (i = 0; i < txTmp.vin->len; i++) { txin = g_ptr_array_index(txTmp.vin, i); if (i != nIn) txin->nSequence = 0; } } /* Blank out other inputs completely; not recommended for open transactions */ if (nHashType & SIGHASH_ANYONECANPAY) { if (nIn > 0) g_ptr_array_remove_range(txTmp.vin, 0, nIn); g_ptr_array_set_size(txTmp.vin, 1); } /* Serialize and hash */ bp_tx_calc_sighash(hash, &txTmp, nHashType); out: bp_tx_free(&txTmp); }