void bp_tx_sigserializer(cstring *s, const cstring *scriptCode, const struct bp_tx *txTo, unsigned int nIn, int nHashType) { const bool fAnyoneCanPay = (!!(nHashType & SIGHASH_ANYONECANPAY)); const bool fHashSingle = ((nHashType & 0x1f) == SIGHASH_SINGLE); const bool fHashNone = ((nHashType & 0x1f) == SIGHASH_NONE); /** Serialize txTo */ // Serialize nVersion ser_u32(s, txTo->nVersion); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo->vin->len; ser_varlen(s, nInputs); unsigned int nInput; for (nInput = 0; nInput < nInputs; nInput++) { /** Serialize an input of txTo */ // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized if (fAnyoneCanPay) nInput = nIn; struct bp_txin *txin = parr_idx(txTo->vin, nInput); // Serialize the prevout ser_bp_outpt(s, &txin->prevout); // Serialize the script if (nInput != nIn) // Blank out other inputs' signatures ser_varlen(s, (int)0); else if (scriptCode == NULL) cstr_append_c(s, 0); else { /** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */ struct const_buffer it = { scriptCode->str, scriptCode->len }; struct const_buffer itBegin = it; struct bscript_op op; unsigned int nCodeSeparators = 0; struct bscript_parser bp; bsp_start(&bp, &it); while (bsp_getop(&op, &bp)) { if (op.op == OP_CODESEPARATOR) nCodeSeparators++; } ser_varlen(s, scriptCode->len - nCodeSeparators); it = itBegin; bsp_start(&bp, &it); while (bsp_getop(&op, &bp)) { if (op.op == OP_CODESEPARATOR) { ser_bytes(s, itBegin.p, it.p - itBegin.p - 1); itBegin = it; } } if (itBegin.p != scriptCode->str + scriptCode->len) ser_bytes(s, itBegin.p, it.p - itBegin.p); } // Serialize the nSequence if ((nInput != nIn) && (fHashSingle || fHashNone)) // let the others update at will ser_u32(s, (int)0); else ser_u32(s, txin->nSequence); } // Serialize vout unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? (nIn + 1) : txTo->vout->len); ser_varlen(s, nOutputs); unsigned int nOutput; for (nOutput = 0; nOutput < nOutputs; nOutput++) { struct bp_txout *txout = parr_idx(txTo->vout, nOutput); if (fHashSingle && (nOutput != nIn)) // Do not lock-in the txout payee at other indices as txin; bp_txout_set_null(txout); ser_bp_txout(s, txout); } // Serialize nLockTime ser_u32(s, txTo->nLockTime); }
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); }