| 563 | |
| 564 | template <typename Stream> |
| 565 | inline void Unserialize(Stream& s) { |
| 566 | // Used for duplicate key detection |
| 567 | std::set<std::vector<unsigned char>> key_lookup; |
| 568 | |
| 569 | // Read loop |
| 570 | bool found_sep = false; |
| 571 | while(!s.empty()) { |
| 572 | // Read |
| 573 | std::vector<unsigned char> key; |
| 574 | s >> key; |
| 575 | |
| 576 | // the key is empty if that was actually a separator byte |
| 577 | // This is a special case for key lengths 0 as those are not allowed (except for separator) |
| 578 | if (key.empty()) { |
| 579 | found_sep = true; |
| 580 | break; |
| 581 | } |
| 582 | |
| 583 | // Type is compact size uint at beginning of key |
| 584 | SpanReader skey(s.GetType(), s.GetVersion(), key); |
| 585 | uint64_t type = ReadCompactSize(skey); |
| 586 | |
| 587 | // Do stuff based on type |
| 588 | switch(type) { |
| 589 | case PSBT_IN_NON_WITNESS_UTXO: |
| 590 | { |
| 591 | if (!key_lookup.emplace(key).second) { |
| 592 | throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided"); |
| 593 | } else if (key.size() != 1) { |
| 594 | throw std::ios_base::failure("Non-witness utxo key is more than one byte type"); |
| 595 | } |
| 596 | // Set the stream to unserialize with witness since this is always a valid network transaction |
| 597 | OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() & ~SERIALIZE_TRANSACTION_NO_WITNESS); |
| 598 | UnserializeFromVector(os, non_witness_utxo); |
| 599 | break; |
| 600 | } |
| 601 | case PSBT_IN_WITNESS_UTXO: |
| 602 | if (!key_lookup.emplace(key).second) { |
| 603 | throw std::ios_base::failure("Duplicate Key, input witness utxo already provided"); |
| 604 | } else if (key.size() != 1) { |
| 605 | throw std::ios_base::failure("Witness utxo key is more than one byte type"); |
| 606 | } |
| 607 | UnserializeFromVector(s, witness_utxo); |
| 608 | break; |
| 609 | case PSBT_IN_PARTIAL_SIG: |
| 610 | { |
| 611 | // Make sure that the key is the size of pubkey + 1 |
| 612 | if (key.size() != CPubKey::SIZE + 1 && key.size() != CPubKey::COMPRESSED_SIZE + 1) { |
| 613 | throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey"); |
| 614 | } |
| 615 | // Read in the pubkey from key |
| 616 | CPubKey pubkey(key.begin() + 1, key.end()); |
| 617 | if (!pubkey.IsFullyValid()) { |
| 618 | throw std::ios_base::failure("Invalid pubkey"); |
| 619 | } |
| 620 | if (partial_sigs.count(pubkey.GetID()) > 0) { |
| 621 | throw std::ios_base::failure("Duplicate Key, input partial signature for pubkey already provided"); |
| 622 | } |
nothing calls this directly
no test coverage detected