Skip to content

Commit 88ed73f

Browse files
committed
wip
1 parent 38c8474 commit 88ed73f

File tree

4 files changed

+107
-35
lines changed

4 files changed

+107
-35
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ struct btck_TransactionInput : Handle<btck_TransactionInput, CTxIn> {};
495495
struct btck_TransactionOutPoint: Handle<btck_TransactionOutPoint, COutPoint> {};
496496
struct btck_Txid: Handle<btck_Txid, Txid> {};
497497

498+
struct btck_ScriptVerifyResult {
499+
bool is_valid;
500+
};
501+
498502
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
499503
{
500504
if (raw_transaction == nullptr && raw_transaction_len != 0) {
@@ -607,25 +611,26 @@ void btck_transaction_output_destroy(btck_TransactionOutput* output)
607611
delete output;
608612
}
609613

610-
int btck_script_pubkey_verify(const btck_ScriptPubkey* script_pubkey,
611-
const int64_t amount,
612-
const btck_Transaction* tx_to,
613-
const btck_TransactionOutput** spent_outputs_, size_t spent_outputs_len,
614-
const unsigned int input_index,
615-
const btck_ScriptVerificationFlags flags,
616-
btck_ScriptVerifyStatus* status)
614+
btck_ScriptVerifyResult* btck_script_pubkey_verify(
615+
const btck_ScriptPubkey* script_pubkey,
616+
const int64_t amount,
617+
const btck_Transaction* tx_to,
618+
const btck_TransactionOutput** spent_outputs_, size_t spent_outputs_len,
619+
const unsigned int input_index,
620+
const btck_ScriptVerificationFlags flags,
621+
btck_ScriptVerifyStatus* status)
617622
{
618623
// Assert that all specified flags are part of the interface before continuing
619624
assert((flags & ~btck_ScriptVerificationFlags_ALL) == 0);
620625

621626
if (!is_valid_flag_combination(script_verify_flags::from_int(flags))) {
622627
if (status) *status = btck_ScriptVerifyStatus_ERROR_INVALID_FLAGS_COMBINATION;
623-
return 0;
628+
return nullptr;
624629
}
625630

626631
if (flags & btck_ScriptVerificationFlags_TAPROOT && spent_outputs_ == nullptr) {
627632
if (status) *status = btck_ScriptVerifyStatus_ERROR_SPENT_OUTPUTS_REQUIRED;
628-
return 0;
633+
return nullptr;
629634
}
630635

631636
if (status) *status = btck_ScriptVerifyStatus_OK;
@@ -654,7 +659,18 @@ int btck_script_pubkey_verify(const btck_ScriptPubkey* script_pubkey,
654659
script_verify_flags::from_int(flags),
655660
TransactionSignatureChecker(&tx, input_index, amount, txdata, MissingDataBehavior::FAIL),
656661
nullptr);
657-
return result ? 1 : 0;
662+
663+
return new btck_ScriptVerifyResult{result};
664+
}
665+
666+
int btck_script_verify_result_is_valid(const btck_ScriptVerifyResult* result)
667+
{
668+
return result->is_valid ? 1 : 0;
669+
}
670+
671+
void btck_script_verify_result_destroy(btck_ScriptVerifyResult* result)
672+
{
673+
delete result;
658674
}
659675

660676
btck_TransactionInput* btck_transaction_input_copy(const btck_TransactionInput* input)

src/kernel/bitcoinkernel.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,16 @@ typedef struct btck_TransactionOutPoint btck_TransactionOutPoint;
284284

285285
typedef struct btck_Txid btck_Txid;
286286

287+
/**
288+
* Opaque data structure for holding the result of a script verification.
289+
*
290+
* This object is returned by @ref btck_script_pubkey_verify and represents
291+
* a successful execution of the verification logic. If the verification
292+
* could not be performed (e.g., due to invalid parameters), the verify
293+
* function returns NULL instead of this object.
294+
*/
295+
typedef struct btck_ScriptVerifyResult btck_ScriptVerifyResult;
296+
287297
/** Current sync state passed to tip changed callbacks. */
288298
typedef uint8_t btck_SynchronizationState;
289299
#define btck_SynchronizationState_INIT_REINDEX ((btck_SynchronizationState)(0))
@@ -610,10 +620,12 @@ BITCOINKERNEL_API btck_ScriptPubkey* BITCOINKERNEL_WARN_UNUSED_RESULT btck_scrip
610620
* @param[in] spent_outputs_len Length of the spent_outputs array.
611621
* @param[in] input_index Index of the input in tx_to spending the script_pubkey.
612622
* @param[in] flags Bitfield of btck_ScriptVerificationFlags controlling validation constraints.
613-
* @param[out] status Nullable, will be set to an error code if the operation fails, or OK otherwise.
614-
* @return 1 if the script is valid, 0 otherwise.
623+
* @param[out] status Nullable, will be set to an error code if the function returns NULL,
624+
* or OK if a result object is returned.
625+
* @return A result object if verification was performed, or NULL if parameters
626+
* were invalid (check status for details).
615627
*/
616-
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_script_pubkey_verify(
628+
BITCOINKERNEL_API btck_ScriptVerifyResult* BITCOINKERNEL_WARN_UNUSED_RESULT btck_script_pubkey_verify(
617629
const btck_ScriptPubkey* script_pubkey,
618630
int64_t amount,
619631
const btck_Transaction* tx_to,
@@ -622,6 +634,20 @@ BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_script_pubkey_verify
622634
btck_ScriptVerificationFlags flags,
623635
btck_ScriptVerifyStatus* status) BITCOINKERNEL_ARG_NONNULL(1, 3);
624636

637+
/**
638+
* @brief Check if the verified script is valid.
639+
*
640+
* @param[in] result Non-null, result object from @ref btck_script_pubkey_verify.
641+
* @return 1 if the script is valid, 0 if the script is invalid.
642+
*/
643+
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_script_verify_result_is_valid(
644+
const btck_ScriptVerifyResult* result) BITCOINKERNEL_ARG_NONNULL(1);
645+
646+
/**
647+
* Destroy the script verification result.
648+
*/
649+
BITCOINKERNEL_API void btck_script_verify_result_destroy(btck_ScriptVerifyResult* result);
650+
625651
/**
626652
* @brief Serializes the script pubkey through the passed in callback to bytes.
627653
*

src/kernel/bitcoinkernel_wrapper.h

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,22 @@ class UniqueHandle
367367
const CType* get() const { return m_ptr.get(); }
368368
};
369369

370+
class ScriptVerifyResult : public UniqueHandle<btck_ScriptVerifyResult, btck_script_verify_result_destroy>
371+
{
372+
public:
373+
explicit ScriptVerifyResult(btck_ScriptVerifyResult* ptr) : UniqueHandle{ptr} {}
374+
375+
bool IsValid() const
376+
{
377+
return btck_script_verify_result_is_valid(get()) == 1;
378+
}
379+
380+
explicit operator bool() const
381+
{
382+
return IsValid();
383+
}
384+
};
385+
370386
class Transaction;
371387
class TransactionOutput;
372388

@@ -383,12 +399,13 @@ class ScriptPubkeyApi
383399
ScriptPubkeyApi() = default;
384400

385401
public:
386-
bool Verify(int64_t amount,
387-
const Transaction& tx_to,
388-
std::span<const TransactionOutput> spent_outputs,
389-
unsigned int input_index,
390-
ScriptVerificationFlags flags,
391-
ScriptVerifyStatus& status) const;
402+
std::optional<ScriptVerifyResult> Verify(
403+
int64_t amount,
404+
const Transaction& tx_to,
405+
std::span<const TransactionOutput> spent_outputs,
406+
unsigned int input_index,
407+
ScriptVerificationFlags flags,
408+
ScriptVerifyStatus& status) const;
392409

393410
std::vector<std::byte> ToBytes() const
394411
{
@@ -627,12 +644,13 @@ class Transaction : public Handle<btck_Transaction, btck_transaction_copy, btck_
627644
};
628645

629646
template <typename Derived>
630-
bool ScriptPubkeyApi<Derived>::Verify(int64_t amount,
631-
const Transaction& tx_to,
632-
const std::span<const TransactionOutput> spent_outputs,
633-
unsigned int input_index,
634-
ScriptVerificationFlags flags,
635-
ScriptVerifyStatus& status) const
647+
std::optional<ScriptVerifyResult> ScriptPubkeyApi<Derived>::Verify(
648+
int64_t amount,
649+
const Transaction& tx_to,
650+
const std::span<const TransactionOutput> spent_outputs,
651+
unsigned int input_index,
652+
ScriptVerificationFlags flags,
653+
ScriptVerifyStatus& status) const
636654
{
637655
const btck_TransactionOutput** spent_outputs_ptr = nullptr;
638656
std::vector<const btck_TransactionOutput*> raw_spent_outputs;
@@ -652,7 +670,10 @@ bool ScriptPubkeyApi<Derived>::Verify(int64_t amount,
652670
input_index,
653671
static_cast<btck_ScriptVerificationFlags>(flags),
654672
reinterpret_cast<btck_ScriptVerifyStatus*>(&status));
655-
return result == 1;
673+
if (!result) {
674+
return std::nullopt;
675+
}
676+
return ScriptVerifyResult{result};
656677
}
657678

658679
template <typename Derived>

src/test/kernel/test_kernel.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,41 +226,48 @@ void run_verify_test(
226226
auto status = ScriptVerifyStatus::OK;
227227

228228
if (taproot) {
229-
BOOST_CHECK(spent_script_pubkey.Verify(
229+
auto result = spent_script_pubkey.Verify(
230230
amount,
231231
spending_tx,
232232
spent_outputs,
233233
input_index,
234234
ScriptVerificationFlags::ALL,
235-
status));
235+
status);
236+
BOOST_CHECK(result.has_value());
237+
BOOST_CHECK(result->IsValid());
236238
BOOST_CHECK(status == ScriptVerifyStatus::OK);
237239
} else {
238-
BOOST_CHECK(!spent_script_pubkey.Verify(
240+
auto result = spent_script_pubkey.Verify(
239241
amount,
240242
spending_tx,
241243
spent_outputs,
242244
input_index,
243245
ScriptVerificationFlags::ALL,
244-
status));
246+
status);
247+
BOOST_CHECK(!result.has_value());
245248
BOOST_CHECK(status == ScriptVerifyStatus::ERROR_SPENT_OUTPUTS_REQUIRED);
246249
}
247250

248-
BOOST_CHECK(spent_script_pubkey.Verify(
251+
auto result_pre_taproot = spent_script_pubkey.Verify(
249252
amount,
250253
spending_tx,
251254
spent_outputs,
252255
input_index,
253256
VERIFY_ALL_PRE_TAPROOT,
254-
status));
257+
status);
258+
BOOST_CHECK(result_pre_taproot.has_value());
259+
BOOST_CHECK(result_pre_taproot->IsValid());
255260
BOOST_CHECK(status == ScriptVerifyStatus::OK);
256261

257-
BOOST_CHECK(spent_script_pubkey.Verify(
262+
auto result_pre_segwit = spent_script_pubkey.Verify(
258263
0,
259264
spending_tx,
260265
spent_outputs,
261266
input_index,
262267
VERIFY_ALL_PRE_SEGWIT,
263-
status));
268+
status);
269+
BOOST_CHECK(result_pre_segwit.has_value());
270+
BOOST_CHECK(result_pre_segwit->IsValid());
264271
BOOST_CHECK(status == ScriptVerifyStatus::OK);
265272
}
266273

@@ -955,7 +962,9 @@ BOOST_AUTO_TEST_CASE(btck_chainman_regtest_tests)
955962
BOOST_CHECK(inputs.size() == spent_outputs.size());
956963
ScriptVerifyStatus status = ScriptVerifyStatus::OK;
957964
for (size_t i{0}; i < inputs.size(); ++i) {
958-
BOOST_CHECK(spent_outputs[i].GetScriptPubkey().Verify(spent_outputs[i].Amount(), transaction, spent_outputs, i, ScriptVerificationFlags::ALL, status));
965+
auto result = spent_outputs[i].GetScriptPubkey().Verify(spent_outputs[i].Amount(), transaction, spent_outputs, i, ScriptVerificationFlags::ALL, status);
966+
BOOST_CHECK(result.has_value());
967+
BOOST_CHECK(result->IsValid());
959968
}
960969
}
961970
}

0 commit comments

Comments
 (0)