Merge bitcoin/bitcoin#28246: wallet: Use CTxDestination in CRecipient instead of just scriptPubKey

ad0c469d98 wallet: Use CTxDestination in CRecipient rather than scriptPubKey (Andrew Chow)
07d3bdf4eb Add PubKeyDestination for P2PK scripts (Andrew Chow)
1a98a51c66 Allow CNoDestination to represent a raw script (Andrew Chow)
8dd067088d Make WitnessUnknown members private (Andrew Chow)

Pull request description:

  For silent payments, we want to provide a `SilentPaymentsDestination` to be used as the recipient, which requires `CRecipient` to use something other than just the `scriptPubKey` as we cannot know the output script for a silent payment prior to transaction creation. `CTxDestination` seems like the obvious place to add a `SilentPaymentsDestination` as it is our internal representation of an address.

  In order to still allow paying to arbitrary scriptPubKeys (e.g. for data carrier outputs, or the user hand crafted a raw transaction that they have given to `fundrawtransaction`), `CNoDestination` is changed to contain raw scripts.

  Additionally, P2PK scripts are now interpreted as a new `PubKeyDestination` rather than `PKHash`. This results in some things that would have given an address for P2PK scripts to no longer do so. This is arguably more correct.

  `ExtractDestination`'s behavior is slightly changed for the above. It now returns `true` for those destinations that have addresses, so P2PK scripts now result in `false`. Even though it returns false for `CNoDestination`, the script will now be included in that `CNoDestination`.

  Builds on #28244

ACKs for top commit:
  josibake:
    ACK ad0c469d98

Tree-SHA512: ef3f8f3c7284779d9806c77c85b21caf910a79a1f7e7f1b51abcc0d7e074f14e00abf30f625a13075e41d94dad6202c10ddff462c0ee74c2ca4aab585b145a52
This commit is contained in:
fanquake
2023-09-19 16:30:09 +00:00
19 changed files with 160 additions and 90 deletions

View File

@@ -186,7 +186,7 @@ FUZZ_TARGET(key, .init = initialize_key)
const CTxDestination tx_destination = GetDestinationForKey(pubkey, output_type);
assert(output_type == OutputType::LEGACY);
assert(IsValidDestination(tx_destination));
assert(CTxDestination{PKHash{pubkey}} == tx_destination);
assert(PKHash{pubkey} == *std::get_if<PKHash>(&tx_destination));
const CScript script_for_destination = GetScriptForDestination(tx_destination);
assert(script_for_destination.size() == 25);

View File

@@ -149,13 +149,16 @@ FUZZ_TARGET(script, .init = initialize_script)
const CTxDestination tx_destination_2{ConsumeTxDestination(fuzzed_data_provider)};
const std::string encoded_dest{EncodeDestination(tx_destination_1)};
const UniValue json_dest{DescribeAddress(tx_destination_1)};
Assert(tx_destination_1 == DecodeDestination(encoded_dest));
(void)GetKeyForDestination(/*store=*/{}, tx_destination_1);
const CScript dest{GetScriptForDestination(tx_destination_1)};
const bool valid{IsValidDestination(tx_destination_1)};
Assert(dest.empty() != valid);
Assert(valid == IsValidDestinationString(encoded_dest));
if (!std::get_if<PubKeyDestination>(&tx_destination_1)) {
// Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding
Assert(dest.empty() != valid);
Assert(tx_destination_1 == DecodeDestination(encoded_dest));
Assert(valid == IsValidDestinationString(encoded_dest));
}
(void)(tx_destination_1 < tx_destination_2);
if (tx_destination_1 == tx_destination_2) {

View File

@@ -172,6 +172,15 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no
[&] {
tx_destination = CNoDestination{};
},
[&] {
bool compressed = fuzzed_data_provider.ConsumeBool();
CPubKey pk{ConstructPubKeyBytes(
fuzzed_data_provider,
ConsumeFixedLengthByteVector(fuzzed_data_provider, (compressed ? CPubKey::COMPRESSED_SIZE : CPubKey::SIZE)),
compressed
)};
tx_destination = PubKeyDestination{pk};
},
[&] {
tx_destination = PKHash{ConsumeUInt160(fuzzed_data_provider)};
},
@@ -188,15 +197,11 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no
tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}};
},
[&] {
WitnessUnknown witness_unknown{};
witness_unknown.version = fuzzed_data_provider.ConsumeIntegralInRange(2, 16);
std::vector<uint8_t> witness_unknown_program_1{fuzzed_data_provider.ConsumeBytes<uint8_t>(40)};
if (witness_unknown_program_1.size() < 2) {
witness_unknown_program_1 = {0, 0};
std::vector<unsigned char> program{ConsumeRandomLengthByteVector(fuzzed_data_provider, /*max_length=*/40)};
if (program.size() < 2) {
program = {0, 0};
}
witness_unknown.length = witness_unknown_program_1.size();
std::copy(witness_unknown_program_1.begin(), witness_unknown_program_1.end(), witness_unknown.program);
tx_destination = witness_unknown;
tx_destination = WitnessUnknown{fuzzed_data_provider.ConsumeIntegralInRange<unsigned int>(2, 16), program};
})};
Assert(call_size == std::variant_size_v<CTxDestination>);
return tx_destination;

View File

@@ -203,8 +203,8 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
// TxoutType::PUBKEY
s.clear();
s << ToByteVector(pubkey) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
BOOST_CHECK(std::get<PKHash>(address) == PKHash(pubkey));
BOOST_CHECK(!ExtractDestination(s, address));
BOOST_CHECK(std::get<PubKeyDestination>(address) == PubKeyDestination(pubkey));
// TxoutType::PUBKEYHASH
s.clear();
@@ -249,10 +249,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
s.clear();
s << OP_1 << ToByteVector(pubkey);
BOOST_CHECK(ExtractDestination(s, address));
WitnessUnknown unk;
unk.length = 33;
unk.version = 1;
std::copy(pubkey.begin(), pubkey.end(), unk.program);
WitnessUnknown unk{1, ToByteVector(pubkey)};
BOOST_CHECK(std::get<WitnessUnknown>(address) == unk);
}