PSBT global xpub merging algorithm reworked

This commit is contained in:
Dr Maxim Orlovsky 2020-12-18 22:32:02 +01:00
parent b84faa7f5e
commit 7f5c2795d6
No known key found for this signature in database
GPG Key ID: FFC0250947E5C6F7
1 changed files with 28 additions and 36 deletions

View File

@ -15,7 +15,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
use std::io::{self, Cursor, Read}; use std::io::{self, Cursor, Read};
use std::cmp::{self, Ordering}; use std::cmp;
use blockdata::transaction::Transaction; use blockdata::transaction::Transaction;
use consensus::{encode, Encodable, Decodable}; use consensus::{encode, Encodable, Decodable};
@ -169,43 +169,35 @@ impl Map for Global {
}, },
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
// Here in case of the conflict we select the version with algorithm: // Here in case of the conflict we select the version with algorithm:
// 1) if fingerprints are equal but derivations are not, we report an error; otherwise // 1) if everything is equal we do nothing
// 2) choose longest unhardened derivation; if equal // 2) report an error if
// 3) choose longest derivation; if equal // - derivation paths are equal and fingerprints are not
// 4) choose the largest derivation using binary ordering; if equal // - derivation paths are of the same length, but not equal
// 5) check that fingerprints are equal, otherwise fail; // - derivation paths has different length, but the shorter one
// 6) if fingerprints are also equal we do nothing // is not the strict suffix of the longer one
let (fingerprint2, len2, normal_len2, deriv_cmp) = { // 3) choose longest derivation otherwise
// weird scope needed for rustc 1.29 borrow checker
let (fp, deriv) = entry.get().clone(); let (fingerprint2, derivation2) = entry.get().clone();
(
fp, if derivation1 == derivation2 && fingerprint1 == fingerprint2
deriv.len(), {
deriv.into_iter().rposition(ChildNumber::is_normal), continue
derivation1.cmp(&deriv) }
) else if
}; derivation1.len() < derivation2.len() &&
let len1 = derivation1.len(); derivation1[..] == derivation2[derivation2.len() - derivation1.len()..]
let normal_len1 = derivation1.into_iter().rposition(ChildNumber::is_normal); {
match (normal_len1.cmp(&normal_len2), len1.cmp(&len2), deriv_cmp, fingerprint1.cmp(&fingerprint2)) { continue
(Ordering::Equal, Ordering::Equal, Ordering::Equal, Ordering::Equal) => {}, }
(Ordering::Equal, Ordering::Equal, Ordering::Equal, _) => { else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..]
{
entry.insert((fingerprint1, derivation1));
continue
}
return Err(psbt::Error::MergeConflict(format!( return Err(psbt::Error::MergeConflict(format!(
"global xpub {} has inconsistent key sources", xpub "global xpub {} has inconsistent key sources", xpub
).to_owned())); ).to_owned()));
} }
(Ordering::Greater, ..)
| (Ordering::Equal, Ordering::Greater, ..)
| (Ordering::Equal, Ordering::Equal, Ordering::Greater, _) => {
entry.insert((fingerprint1, derivation1));
},
(Ordering::Less, ..)
| (Ordering::Equal, Ordering::Less, ..)
| (Ordering::Equal, Ordering::Equal, Ordering::Less, _) => {
// do nothing here: we already own the proper data
}
}
}
} }
} }