Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501SerializeToVector(s, CompactSizeWriter(PSBT_IN_MUSIG2_PARTIAL_SIG), std::span{pubkey}, std::span{agg_pubkey}, leaf_hash);502}503SerializeToVector(s, psig);504}505}506}508// Write script sig509if (!final_script_sig.empty()) {510SerializeToVector(s, CompactSizeWriter(PSBT_IN_SCRIPTSIG));511s << final_script_sig;512}513// write script witness514if (!final_script_witness.IsNull()) {515SerializeToVector(s, CompactSizeWriter(PSBT_IN_SCRIPTWITNESS));516SerializeToVector(s, final_script_witness.stack);517}519// Write PSBTv2 fields520if (m_psbt_version >= 2) {521// Write prev txid, vout, sequence, and lock times522SerializeToVector(s, CompactSizeWriter(PSBT_IN_PREVIOUS_TXID));523SerializeToVector(s, prev_txid);525SerializeToVector(s, CompactSizeWriter(PSBT_IN_OUTPUT_INDEX));526SerializeToVector(s, prev_out);528if (sequence != std::nullopt) {529SerializeToVector(s, CompactSizeWriter(PSBT_IN_SEQUENCE));530SerializeToVector(s, *sequence);531}532if (time_locktime != std::nullopt) {533SerializeToVector(s, CompactSizeWriter(PSBT_IN_REQUIRED_TIME_LOCKTIME));534SerializeToVector(s, *time_locktime);535}536if (height_locktime != std::nullopt) {537SerializeToVector(s, CompactSizeWriter(PSBT_IN_REQUIRED_HEIGHT_LOCKTIME));538SerializeToVector(s, *height_locktime);539}540}542// Write proprietary things543for (const auto& entry : m_proprietary) {544s << entry.key;545s << entry.value;546}548// Write unknown things549for (auto& entry : unknown) {550s << entry.first;551s << entry.second;552}554s << PSBT_SEPARATOR;555}558template <typename Stream>559inline void Unserialize(Stream& s) {560// Used for duplicate key detection561std::set<std::vector<unsigned char>> key_lookup;562// Cache whether PSBTv2 required fields were seen563bool found_prev_txid = false;564bool found_prev_out = false;566// Read loop567bool found_sep = false;568while(!s.empty()) {569// Read the key of format "<keylen><keytype><keydata>" after which570// "key" will contain "<keytype><keydata>"571std::vector<unsigned char> key;572s >> key;574// the key is empty if that was actually a separator byte575// This is a special case for key lengths 0 as those are not allowed (except for separator)576if (key.empty()) {577found_sep = true;578break;579}581// Duplicate keys are not permitted582if (!key_lookup.emplace(key).second) {583throw std::ios_base::failure(tfm::format("Duplicate Key, input key \"%s\" already provided", HexStr(key)));584}586// "skey" is used so that "key" is unchanged after reading keytype below587SpanReader skey{key};588// keytype is of the format compact size uint at the beginning of "key"589uint64_t type = ReadCompactSize(skey);591// Do stuff based on keytype "type", i.e., key checks, reading values of the592// format "<valuelen><valuedata>" from the stream "s", and value checks593switch(type) {594case PSBT_IN_NON_WITNESS_UTXO:595{596ExpectedKeySize("Input Non-witness UTXO", key, 1);597// Set the stream to unserialize with witness since this is always a valid network transaction598UnserializeFromVector(s, TX_WITH_WITNESS(non_witness_utxo));599break;600}601case PSBT_IN_WITNESS_UTXO:602ExpectedKeySize("Input Witness UTXO", key, 1);603UnserializeFromVector(s, witness_utxo);604break;605case PSBT_IN_PARTIAL_SIG:606{607// Make sure that the key is the size of pubkey + 1608if (key.size() != CPubKey::SIZE + 1 && key.size() != CPubKey::COMPRESSED_SIZE + 1) {609throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey");610}611// Read in the pubkey from key612CPubKey pubkey(key.begin() + 1, key.end());613if (!pubkey.IsFullyValid()) {614throw std::ios_base::failure("Invalid pubkey");615}617// Read in the signature from value618std::vector<unsigned char> sig;619s >> sig;621// Check that the signature is validly encoded622if (sig.empty() || !CheckSignatureEncoding(sig, SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_STRICTENC, nullptr)) {623throw std::ios_base::failure("Signature is not a valid encoding");624}626// Add to list627partial_sigs.emplace(pubkey.GetID(), SigPair(pubkey, std::move(sig)));628break;629}630case PSBT_IN_SIGHASH:631ExpectedKeySize("Input Sighash Type", key, 1);632int sighash;633UnserializeFromVector(s, sighash);634sighash_type = sighash;635break;636case PSBT_IN_REDEEMSCRIPT:637{638ExpectedKeySize("Input redeemScript", key, 1);639s >> redeem_script;640break;641}642case PSBT_IN_WITNESSSCRIPT:643{644ExpectedKeySize("Input witnessScript", key, 1);645s >> witness_script;646break;647}648case PSBT_IN_BIP32_DERIVATION:649{650DeserializeHDKeypaths(s, key, hd_keypaths);651break;652}653case PSBT_IN_SCRIPTSIG:654{655ExpectedKeySize("Input Final scriptSig", key, 1);656s >> final_script_sig;657break;658}659case PSBT_IN_SCRIPTWITNESS:660{661ExpectedKeySize("Input Final scriptWitness", key, 1);662UnserializeFromVector(s, final_script_witness.stack);663break;664}665case PSBT_IN_RIPEMD160:666{667ExpectedKeySize("Input RIPEMD160 Preimage", key, CRIPEMD160::OUTPUT_SIZE + 1);668// Read in the hash from key669std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());670uint160 hash(hash_vec);672// Read in the preimage from value673std::vector<unsigned char> preimage;674s >> preimage;676// Add to preimages list677ripemd160_preimages.emplace(hash, std::move(preimage));678break;679}680case PSBT_IN_SHA256:681{682ExpectedKeySize("Input SHA256 Preimage", key, CSHA256::OUTPUT_SIZE + 1);683// Read in the hash from key684std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());685uint256 hash(hash_vec);687// Read in the preimage from value688std::vector<unsigned char> preimage;689s >> preimage;691// Add to preimages list692sha256_preimages.emplace(hash, std::move(preimage));693break;694}695case PSBT_IN_HASH160:696{697ExpectedKeySize("Input Hash160 Preimage", key, CHash160::OUTPUT_SIZE + 1);698// Read in the hash from key699std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());700uint160 hash(hash_vec);702// Read in the preimage from value703std::vector<unsigned char> preimage;704s >> preimage;706// Add to preimages list707hash160_preimages.emplace(hash, std::move(preimage));708break;709}710case PSBT_IN_HASH256:711{712ExpectedKeySize("Input Hash256 Preimage", key, CHash256::OUTPUT_SIZE + 1);713// Read in the hash from key714std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());715uint256 hash(hash_vec);717// Read in the preimage from value718std::vector<unsigned char> preimage;719s >> preimage;721// Add to preimages list722hash256_preimages.emplace(hash, std::move(preimage));723break;724}725case PSBT_IN_PREVIOUS_TXID:726{727ExpectedKeySize("Input Previous TXID", key, 1);728if (m_psbt_version < 2) {729throw std::ios_base::failure("Previous txid is not allowed in PSBTv0");730}731UnserializeFromVector(s, prev_txid);732found_prev_txid = true;733break;734}735case PSBT_IN_OUTPUT_INDEX:736{737ExpectedKeySize("Input Previous Output's Index", key, 1);738if (m_psbt_version < 2) {739throw std::ios_base::failure("Previous output's index is not allowed in PSBTv0");740}741UnserializeFromVector(s, prev_out);742found_prev_out = true;743break;744}745case PSBT_IN_SEQUENCE:746{747ExpectedKeySize("Input Sequence", key, 1);748if (m_psbt_version < 2) {749throw std::ios_base::failure("Sequence is not allowed in PSBTv0");750}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.