Beispiel #1
0
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;
}
Beispiel #2
0
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;
}