bool bp_script_verify(const cstring *scriptSig, const cstring *scriptPubKey, const struct bp_tx *txTo, unsigned int nIn, unsigned int flags, int nHashType) { bool rc = false; parr *stack = parr_new(0, buffer_freep); parr *stackCopy = NULL; struct const_buffer sigbuf = { scriptSig->str, scriptSig->len }; if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !is_bsp_pushonly(&sigbuf)) goto out; if (!bp_script_eval(stack, scriptSig, txTo, nIn, flags, nHashType)) goto out; if (flags & SCRIPT_VERIFY_P2SH) { stackCopy = parr_new(stack->len, buffer_freep); stack_copy(stackCopy, stack); } if (!bp_script_eval(stack, scriptPubKey, txTo, nIn, flags, nHashType)) goto out; if (stack->len == 0) goto out; if (CastToBool(stacktop(stack, -1)) == false) goto out; if ((flags & SCRIPT_VERIFY_P2SH) && is_bsp_p2sh_str(scriptPubKey)) { // scriptSig must be literals-only or validation fails if (!is_bsp_pushonly(&sigbuf)) goto out; // stack cannot be empty here, because if it was the // P2SH HASH <> EQUAL scriptPubKey would be evaluated with // an empty stack and the script_eval above would return false. if (stackCopy->len < 1) goto out; struct buffer *pubKeySerialized = stack_take(stackCopy, -1); popstack(stackCopy); cstring *pubkey2 = cstr_new_buf(pubKeySerialized->p, pubKeySerialized->len); buffer_freep(pubKeySerialized); bool rc2 = bp_script_eval(stackCopy, pubkey2, txTo, nIn, flags, nHashType); cstr_free(pubkey2, true); if (!rc2) goto out; if (stackCopy->len == 0) goto out; if (CastToBool(stacktop(stackCopy, -1)) == false) goto out; } // The CLEANSTACK check is only performed after potential P2SH evaluation, // as the non-P2SH evaluation of a P2SH script will obviously not result in // a clean stack (the P2SH inputs remain). if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { // Disallow CLEANSTACK without P2SH, as otherwise a switch CLEANSTACK->P2SH+CLEANSTACK // would be possible, which is not a softfork (and P2SH should be one). assert((flags & SCRIPT_VERIFY_P2SH) != 0); if (stackCopy->len != 1) goto out; } rc = true; out: parr_free(stack, true); if (stackCopy) parr_free(stackCopy, true); return rc; }
bool bp_script_verify(const GString *scriptSig, const GString *scriptPubKey, const struct bp_tx *txTo, unsigned int nIn, unsigned int flags, int nHashType) { bool rc = false; GPtrArray *stack = g_ptr_array_new_with_free_func( (GDestroyNotify) buffer_free); GString *pubkey2 = NULL; GPtrArray *stackCopy = NULL; if (!bp_script_eval(stack, scriptSig, txTo, nIn, flags, nHashType)) goto out; if (flags & SCRIPT_VERIFY_P2SH) { stackCopy = g_ptr_array_new_full(stack->len, (GDestroyNotify) buffer_free); stack_copy(stackCopy, stack); } if (!bp_script_eval(stack, scriptPubKey, txTo, nIn, flags, nHashType)) goto out; if (stack->len == 0) goto out; if (CastToBool(stacktop(stack, -1)) == false) goto out; if ((flags & SCRIPT_VERIFY_P2SH) && is_bsp_p2sh_str(scriptPubKey)) { struct const_buffer sigbuf = { scriptSig->str, scriptSig->len }; if (!is_bsp_pushonly(&sigbuf)) goto out; if (stackCopy->len < 1) goto out; struct buffer *pubkey2_buf = stack_take(stackCopy, -1); popstack(stackCopy); GString *pubkey2 = g_string_sized_new(pubkey2_buf->len); g_string_append_len(pubkey2, pubkey2_buf->p, pubkey2_buf->len); buffer_free(pubkey2_buf); bool rc2 = bp_script_eval(stackCopy, pubkey2, txTo, nIn, flags, nHashType); g_string_free(pubkey2, TRUE); if (!rc2) goto out; if (stackCopy->len == 0) goto out; if (CastToBool(stacktop(stackCopy, -1)) == false) goto out; } rc = true; out: g_ptr_array_free(stack, TRUE); if (pubkey2) g_string_free(pubkey2, TRUE); if (stackCopy) g_ptr_array_free(stackCopy, TRUE); return rc; }