diff --git a/src/psbt.cpp b/src/psbt.cpp index 4c9b439815..203e0a0bd3 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -153,6 +153,10 @@ void PSBTInput::Merge(const PSBTInput& input) } partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end()); + ripemd160_preimages.insert(input.ripemd160_preimages.begin(), input.ripemd160_preimages.end()); + sha256_preimages.insert(input.sha256_preimages.begin(), input.sha256_preimages.end()); + hash160_preimages.insert(input.hash160_preimages.begin(), input.hash160_preimages.end()); + hash256_preimages.insert(input.hash256_preimages.begin(), input.hash256_preimages.end()); hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end()); unknown.insert(input.unknown.begin(), input.unknown.end()); diff --git a/src/psbt.h b/src/psbt.h index 690d1b3bbd..43b1b249c5 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -37,6 +37,10 @@ static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05; static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06; static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07; static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08; +static constexpr uint8_t PSBT_IN_RIPEMD160 = 0x0A; +static constexpr uint8_t PSBT_IN_SHA256 = 0x0B; +static constexpr uint8_t PSBT_IN_HASH160 = 0x0C; +static constexpr uint8_t PSBT_IN_HASH256 = 0x0D; static constexpr uint8_t PSBT_IN_PROPRIETARY = 0xFC; // Output types @@ -171,6 +175,10 @@ struct PSBTInput CScriptWitness final_script_witness; std::map hd_keypaths; std::map partial_sigs; + std::map> ripemd160_preimages; + std::map> sha256_preimages; + std::map> hash160_preimages; + std::map> hash256_preimages; std::map, std::vector> unknown; std::set m_proprietary; std::optional sighash_type; @@ -221,6 +229,30 @@ struct PSBTInput // Write any hd keypaths SerializeHDKeypaths(s, hd_keypaths, CompactSizeWriter(PSBT_IN_BIP32_DERIVATION)); + + // Write any ripemd160 preimage + for (const auto& [hash, preimage] : ripemd160_preimages) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_RIPEMD160), Span{hash}); + s << preimage; + } + + // Write any sha256 preimage + for (const auto& [hash, preimage] : sha256_preimages) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_SHA256), Span{hash}); + s << preimage; + } + + // Write any hash160 preimage + for (const auto& [hash, preimage] : hash160_preimages) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_HASH160), Span{hash}); + s << preimage; + } + + // Write any hash256 preimage + for (const auto& [hash, preimage] : hash256_preimages) { + SerializeToVector(s, CompactSizeWriter(PSBT_IN_HASH256), Span{hash}); + s << preimage; + } } // Write script sig @@ -373,6 +405,90 @@ struct PSBTInput UnserializeFromVector(s, final_script_witness.stack); break; } + case PSBT_IN_RIPEMD160: + { + // Make sure that the key is the size of a ripemd160 hash + 1 + if (key.size() != CRIPEMD160::OUTPUT_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type ripemd160 preimage"); + } + // Read in the hash from key + std::vector hash_vec(key.begin() + 1, key.end()); + uint160 hash(hash_vec); + if (ripemd160_preimages.count(hash) > 0) { + throw std::ios_base::failure("Duplicate Key, input ripemd160 preimage already provided"); + } + + // Read in the preimage from value + std::vector preimage; + s >> preimage; + + // Add to preimages list + ripemd160_preimages.emplace(hash, std::move(preimage)); + break; + } + case PSBT_IN_SHA256: + { + // Make sure that the key is the size of a sha256 hash + 1 + if (key.size() != CSHA256::OUTPUT_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type sha256 preimage"); + } + // Read in the hash from key + std::vector hash_vec(key.begin() + 1, key.end()); + uint256 hash(hash_vec); + if (sha256_preimages.count(hash) > 0) { + throw std::ios_base::failure("Duplicate Key, input sha256 preimage already provided"); + } + + // Read in the preimage from value + std::vector preimage; + s >> preimage; + + // Add to preimages list + sha256_preimages.emplace(hash, std::move(preimage)); + break; + } + case PSBT_IN_HASH160: + { + // Make sure that the key is the size of a hash160 hash + 1 + if (key.size() != CHash160::OUTPUT_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type hash160 preimage"); + } + // Read in the hash from key + std::vector hash_vec(key.begin() + 1, key.end()); + uint160 hash(hash_vec); + if (hash160_preimages.count(hash) > 0) { + throw std::ios_base::failure("Duplicate Key, input hash160 preimage already provided"); + } + + // Read in the preimage from value + std::vector preimage; + s >> preimage; + + // Add to preimages list + hash160_preimages.emplace(hash, std::move(preimage)); + break; + } + case PSBT_IN_HASH256: + { + // Make sure that the key is the size of a hash256 hash + 1 + if (key.size() != CHash256::OUTPUT_SIZE + 1) { + throw std::ios_base::failure("Size of key was not the expected size for the type hash256 preimage"); + } + // Read in the hash from key + std::vector hash_vec(key.begin() + 1, key.end()); + uint256 hash(hash_vec); + if (hash256_preimages.count(hash) > 0) { + throw std::ios_base::failure("Duplicate Key, input hash256 preimage already provided"); + } + + // Read in the preimage from value + std::vector preimage; + s >> preimage; + + // Add to preimages list + hash256_preimages.emplace(hash, std::move(preimage)); + break; + } case PSBT_IN_PROPRIETARY: { PSBTProprietary this_prop; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 12ade466da..f2e8104e14 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1154,7 +1154,23 @@ static RPCHelpMan decodepsbt() { {RPCResult::Type::STR_HEX, "", "hex-encoded witness data (if any)"}, }}, - {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields", + {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/ true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "sha256_preimages", /*optional=*/ true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "hash160_preimages", /*optional=*/ true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "hash256_preimages", /*optional=*/ true, "", + { + {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, + }}, + {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/ true, "The unknown input fields", { {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, }}, @@ -1373,6 +1389,42 @@ static RPCHelpMan decodepsbt() in.pushKV("final_scriptwitness", txinwitness); } + // Ripemd160 hash preimages + if (!input.ripemd160_preimages.empty()) { + UniValue ripemd160_preimages(UniValue::VOBJ); + for (const auto& [hash, preimage] : input.ripemd160_preimages) { + ripemd160_preimages.pushKV(HexStr(hash), HexStr(preimage)); + } + in.pushKV("ripemd160_preimages", ripemd160_preimages); + } + + // Sha256 hash preimages + if (!input.sha256_preimages.empty()) { + UniValue sha256_preimages(UniValue::VOBJ); + for (const auto& [hash, preimage] : input.sha256_preimages) { + sha256_preimages.pushKV(HexStr(hash), HexStr(preimage)); + } + in.pushKV("sha256_preimages", sha256_preimages); + } + + // Hash160 hash preimages + if (!input.hash160_preimages.empty()) { + UniValue hash160_preimages(UniValue::VOBJ); + for (const auto& [hash, preimage] : input.hash160_preimages) { + hash160_preimages.pushKV(HexStr(hash), HexStr(preimage)); + } + in.pushKV("hash160_preimages", hash160_preimages); + } + + // Hash256 hash preimages + if (!input.hash256_preimages.empty()) { + UniValue hash256_preimages(UniValue::VOBJ); + for (const auto& [hash, preimage] : input.hash256_preimages) { + hash256_preimages.pushKV(HexStr(hash), HexStr(preimage)); + } + in.pushKV("hash256_preimages", hash256_preimages); + } + // Proprietary if (!input.m_proprietary.empty()) { UniValue proprietary(UniValue::VARR); diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json index dd24dce94d..8672400a92 100644 --- a/test/functional/data/rpc_psbt.json +++ b/test/functional/data/rpc_psbt.json @@ -39,7 +39,11 @@ "cHNidP8B+wQAAAAAAQB1AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAAAA/v///wLT3/UFAAAAABl2qRTQxZkDxbrChodg6Q/VIaRmWqdlIIisAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4ezLhMAAAEA/aUBAQAAAAABAomjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAABcWABS+GNFSqbASA52vPafeT1M0nuy5hf////+G+KpDpx3/FEiJOlMKcjfva0YIu7LdLQFx5jrsakiQtAEAAAAXFgAU/j6e8adF6XTZAsQ1WUOryzS9U1P/////AgDC6wsAAAAAGXapFIXP8Ql/2eAIuzSvcJxiGXs4l4pIiKxy/vhOLAAAABepFDOXJboh79Yqx1OpvNBn1semo50FhwJHMEQCICcSviLgJw85T1aDEdx8qaaJcLgCX907JAIp8H+KXzokAiABizjX3NMU5zTJJ2vW+0D2czJbxLqhRMgA0vLwLbJ2XAEhA9LhVnSUG61KmWNyy4fhhW02UmBtmFYv45xenn5BPyEFAkgwRQIhANErhS2F3Nlh0vX0q2YGVN9u7cx5TAwzzlzDCf+1/OWNAiBnM4qODhclwZf7GoivWfUeROQlWyAWfIaEAxwF0fJZKgEhAiO3K+7wll0Qvgd47+zWH8rG95pOoWk5M4BzRGT4TyqzAAAAAAAAAA==", "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAD/AAAAaoF/AKqqgABqgABAP2lAQEAAAAAAQKJo8ceq00g4Dcbu6TMaY+ilclGOvouOX+FM8y2L5Vn5QEAAAAXFgAUvhjRUqmwEgOdrz2n3k9TNJ7suYX/////hviqQ6cd/xRIiTpTCnI372tGCLuy3S0BceY67GpIkLQBAAAAFxYAFP4+nvGnRel02QLENVlDq8s0vVNT/////wIAwusLAAAAABl2qRSFz/EJf9ngCLs0r3CcYhl7OJeKSIiscv74TiwAAAAXqRQzlyW6Ie/WKsdTqbzQZ9bHpqOdBYcCRzBEAiAnEr4i4CcPOU9WgxHcfKmmiXC4Al/dOyQCKfB/il86JAIgAYs419zTFOc0ySdr1vtA9nMyW8S6oUTIANLy8C2ydlwBIQPS4VZ0lButSpljcsuH4YVtNlJgbZhWL+OcXp5+QT8hBQJIMEUCIQDRK4UthdzZYdL19KtmBlTfbu3MeUwMM85cwwn/tfzljQIgZzOKjg4XJcGX+xqIr1n1HkTkJVsgFnyGhAMcBdHyWSoBIQIjtyvu8JZdEL4HeO/s1h/KxveaTqFpOTOAc0Rk+E8qswAAAAAF/AKqqgEBqwAABfwCqqoCAawA", "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA", - "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAATwEENYfPAAAAAAAAAAAAG3t93NmzqdwlifBjtWBRnFrHYkoMdmriSG1s74PiZ8ID3+4wNJ18fPeMDsRRe9iTAopsKogDQfxLmL6Kgj07xScE2QxqTwAAAAAA" + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAATwEENYfPAAAAAAAAAAAAG3t93NmzqdwlifBjtWBRnFrHYkoMdmriSG1s74PiZ8ID3+4wNJ18fPeMDsRRe9iTAopsKogDQfxLmL6Kgj07xScE2QxqTwAAAAAA", + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAFQoYn3yLGjhv/o7tkbODDHp7zR53jAIBAhUK8pG6UBXfNIyAhT+luw95RvXJ4bMBAQAAAA==", + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAIQtL9RIvNEVUxTveLruM0rfj0WAK1jHDhaXXzOI8d4VFmgEBIQuhKHH+4hD7hhkpHq6hlFgcvSUx5LI3WdIl9oBpI/YyIgIBAgAAAA==", + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAFQwVzEnhkcvFINkZRGAKXLd69qoykQIBAhUMxRtmvO1eRJEAG9cCZpdw3M9ECYIBAQAAAA==", + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAIQ12pWrO2RXSUT3NhMLDeLLoqlzWMrW3HKLyrFsOOmSb2wIBAiENnBLP3ATHRYTXh6w9I3chMsGFJLx6so3sQhm4/FtCX3ABAQAAAA==" ], "creator" : [ {