int main (int argc, char *argv[]) { error_t aprc; aprc = argp_parse(&argp, argc, argv, 0, NULL, NULL); if (aprc) { fprintf(stderr, "argp_parse failed: %s\n", strerror(aprc)); return 1; } bp_tx_init(&tx); if (!opt_blank) read_data(); apply_mutations(); output_data(); if (opt_strict_free) bp_tx_free(&tx); return 0; }
static void test_script(bool is_valid,cstring *scriptSig, cstring *scriptPubKey, unsigned int idx, const char *scriptSigEnc, const char *scriptPubKeyEnc) { struct bp_tx tx; static const unsigned int test_flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; bp_tx_init(&tx); bool rc; rc = bp_script_verify(scriptSig, scriptPubKey, &tx, 0, test_flags, SIGHASH_NONE); if (rc != is_valid) { fprintf(stderr, "script: %sis_valid test %u failed\n" "script: [\"%s\", \"%s\"]\n", is_valid ? "" : "!", idx, scriptSigEnc, scriptPubKeyEnc); assert(rc == is_valid); } bp_tx_free(&tx); }
static void test_tx_valid(bool is_valid, struct bp_hashtab *input_map, cstring *tx_ser, bool enforce_p2sh) { struct bp_tx tx; bp_tx_init(&tx); struct const_buffer buf = { tx_ser->str, tx_ser->len }; assert(deser_bp_tx(&tx, &buf) == true); if (is_valid) { /* checking for valid tx; !bp_tx_valid implies test fail */ assert(bp_tx_valid(&tx) == true); } else { /* checking for invalid tx; bp_tx_valid==false implies test * succeeded; no more work to do; bp_tx_valid==true * implies the test will detect the invalid condition * further down in the code */ if (bp_tx_valid(&tx) == false) goto out; } bp_tx_calc_sha256(&tx); unsigned int i; for (i = 0; i < tx.vin->len; i++) { struct bp_txin *txin; txin = parr_idx(tx.vin, i); assert(txin != NULL); cstring *scriptPubKey = bp_hashtab_get(input_map, &txin->prevout); if (scriptPubKey == NULL) { if (!is_valid) { /* if testing tx_invalid.json, missing input * is invalid, and therefore correct */ continue; } char tx_hexstr[BU256_STRSZ], hexstr[BU256_STRSZ]; bu256_hex(tx_hexstr, &tx.sha256); bu256_hex(hexstr, &txin->prevout.hash); dump_comments(); fprintf(stderr, "tx-valid: TX %s\n" "tx-valid: prevout (%s, %u) not found\n", tx_hexstr, hexstr, txin->prevout.n); assert(scriptPubKey != NULL); } bool rc = bp_script_verify(txin->scriptSig, scriptPubKey, &tx, i, enforce_p2sh ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, 0); if (rc != is_valid) { char tx_hexstr[BU256_STRSZ]; bu256_hex(tx_hexstr, &tx.sha256); dump_comments(); fprintf(stderr, "tx-valid: TX %s\n" "tx-valid: txin %u script verification failed\n", tx_hexstr, i); assert(rc == is_valid); } } out: bp_tx_free(&tx); }
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); }