libbitcoin / libbitcoin-system

Bitcoin Cross-Platform C++ Development Toolkit
https://libbitcoin.info/
Other
1.3k stars 385 forks source link

Transaction verification failed #1547

Closed awhooooo closed 2 weeks ago

awhooooo commented 2 weeks ago

I am testing transaction verification using libbitcoin-system v3.8.0 and while most of the data I am using passed, some are showing unexpected results. Here is the list of the transactions that failed their script verification tests. These are real bitcoin transactions that goes back like 12-13 years.

main net: c58b6a83c1b09a90011c4663380fea67977424df757f4459109583c56821308a
main net: 1c0b2efd35d401ea8a81f9ca3a3a832bc87769d3005b416caae6e26948f7f04e
main net: fd9d8d6156233ffc84c4c6c76b265ab1fd947bb4e99475a19d9d54da6d226556

Also, here is the code I used.

#include <iostream>
#include <string>

#include <bitcoin/system.hpp>

using namespace libbitcoin;

int main()
{
    const std::string raw_data = "raw transaction data of the list omitted";
    data_chunk raw_data_in_bytes;
    decode_base16(raw_data_in_bytes, raw_data);

    chain::transaction tx;
    tx.from_data(raw_data_in_bytes, /*wire=*/true, /*witness=*/false);

    for (unsigned int i = 0; i < tx.inputs().size(); i++) {
        const auto& input = tx.inputs()[i];
        libbitcoin::code validation_result = input.script().verify(tx, i, libbitcoin::machine::all_rules);
        if (validation_result.value() != libbitcoin::error::success) {
            std::cout << "Tx verification of input " << i << " failed\n";
            return EXIT_FAILURE;
        }
    }

    std::cout << "Tx verification succeed\n";
    return EXIT_SUCCESS;
}

Originally I thought that the script verification flags might be the reason for the failure so I tried lowering the level of strictness of the verification. So first I tried libbitcoin::machine::all_rules, and then adjusted the rules to Bitcoin Core's MANDATORY_SCRIPT_VERIFY_FLAGS (src/policy/policy.h) and then libbitcoin::machine::no_rules but those attempts didn't change the result. Judging by the looks of the failed ones, I presume this issue might be applied to all non-standard transactions. How do I resolve this problem? Thanks in advance.

evoskuil commented 2 weeks ago

What is the error code? You can serialize the code .message().

awhooooo commented 2 weeks ago

620b9d26bd24a598f3e27babaa46f12d932683b62dfaa56e9d80392a7c4f19f3 => bitcoin:65 (stack false) fd9d8d6156233ffc84c4c6c76b265ab1fd947bb4e99475a19d9d54da6d226556 => bitcoin:65 (stack false) c58b6a83c1b09a90011c4663380fea67977424df757f4459109583c56821308a => bitcoin:65 (stack false)

I checked the entire inputs and their corresponding error messages and they are all 65

evoskuil commented 2 weeks ago

Thanks. I don’t see where you are populating the previous outputs.

awhooooo commented 2 weeks ago

Isn't prev output already included in the input class? The standard transactions all return 0 (error::success).

evoskuil commented 2 weeks ago

The type is included, but of course the previous output cannot be inferred from the deserialized input tx.

awhooooo commented 2 weeks ago

Oh now I understand. No wonder the failing transactions all have non-standard inputs. Thanks for pointing it out!