PSBT global xpub merging algorithm reworked
This commit is contained in:
parent
b84faa7f5e
commit
7f5c2795d6
|
@ -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,42 +169,34 @@ 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)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let len1 = 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)) {
|
|
||||||
(Ordering::Equal, Ordering::Equal, Ordering::Equal, Ordering::Equal) => {},
|
|
||||||
(Ordering::Equal, Ordering::Equal, Ordering::Equal, _) => {
|
|
||||||
return Err(psbt::Error::MergeConflict(format!(
|
|
||||||
"global xpub {} has inconsistent key sources", xpub
|
|
||||||
).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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if
|
||||||
|
derivation1.len() < derivation2.len() &&
|
||||||
|
derivation1[..] == derivation2[derivation2.len() - derivation1.len()..]
|
||||||
|
{
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..]
|
||||||
|
{
|
||||||
|
entry.insert((fingerprint1, derivation1));
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return Err(psbt::Error::MergeConflict(format!(
|
||||||
|
"global xpub {} has inconsistent key sources", xpub
|
||||||
|
).to_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue