17
17
//! Optimizing compiler from concrete policies to Miniscript
18
18
//!
19
19
20
- use std:: collections:: HashMap ;
20
+ use std:: collections:: BTreeMap ;
21
21
use std:: convert:: From ;
22
22
use std:: marker:: PhantomData ;
23
- use std:: { cmp, error, f64, fmt} ;
23
+ use std:: { cmp, error, f64, fmt, mem } ;
24
24
25
25
use miniscript:: types:: extra_props:: MAX_OPS_PER_SCRIPT ;
26
26
use miniscript:: types:: { self , ErrorKind , ExtData , Property , Type } ;
@@ -33,7 +33,7 @@ use {policy, Terminal};
33
33
use { Miniscript , MiniscriptKey } ;
34
34
35
35
type PolicyCache < Pk , Ctx > =
36
- HashMap < ( Concrete < Pk > , OrdF64 , Option < OrdF64 > ) , HashMap < CompilationKey , AstElemExt < Pk , Ctx > > > ;
36
+ BTreeMap < ( Concrete < Pk > , OrdF64 , Option < OrdF64 > ) , BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > > ;
37
37
38
38
///Ordered f64 for comparison
39
39
#[ derive( Copy , Clone , PartialEq , PartialOrd , Debug ) ]
@@ -107,7 +107,7 @@ impl hash::Hash for OrdF64 {
107
107
108
108
/// Compilation key: This represents the state of the best possible compilation
109
109
/// of a given policy(implicitly keyed).
110
- #[ derive( Copy , Clone , PartialEq , Eq , Debug , Hash ) ]
110
+ #[ derive( Copy , Clone , PartialEq , Eq , Debug , PartialOrd , Ord ) ]
111
111
struct CompilationKey {
112
112
/// The type of the compilation result
113
113
ty : Type ,
@@ -646,7 +646,7 @@ fn all_casts<Pk: MiniscriptKey, Ctx: ScriptContext>() -> [Cast<Pk, Ctx>; 10] {
646
646
/// In general, we maintain the invariant that if anything is inserted into the
647
647
/// map, it's cast closure must also be considered for best compilations.
648
648
fn insert_elem < Pk : MiniscriptKey , Ctx : ScriptContext > (
649
- map : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
649
+ map : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
650
650
elem : AstElemExt < Pk , Ctx > ,
651
651
sat_prob : f64 ,
652
652
dissat_prob : Option < f64 > ,
@@ -680,10 +680,13 @@ fn insert_elem<Pk: MiniscriptKey, Ctx: ScriptContext>(
680
680
if !is_worse {
681
681
// If the element is not worse any element in the map, remove elements
682
682
// whose subtype is the current element and have worse cost.
683
- map. retain ( |& existing_key, existing_elem| {
684
- let existing_elem_cost = existing_elem. cost_1d ( sat_prob, dissat_prob) ;
685
- !( elem_key. is_subtype ( existing_key) && existing_elem_cost >= elem_cost)
686
- } ) ;
683
+ * map = mem:: replace ( map, BTreeMap :: new ( ) )
684
+ . into_iter ( )
685
+ . filter ( |& ( ref existing_key, ref existing_elem) | {
686
+ let existing_elem_cost = existing_elem. cost_1d ( sat_prob, dissat_prob) ;
687
+ !( elem_key. is_subtype ( * existing_key) && existing_elem_cost >= elem_cost)
688
+ } )
689
+ . collect ( ) ;
687
690
map. insert ( elem_key, elem) ;
688
691
}
689
692
!is_worse
@@ -698,7 +701,7 @@ fn insert_elem<Pk: MiniscriptKey, Ctx: ScriptContext>(
698
701
/// all map is smallest possible closure of all compilations of a policy with
699
702
/// given sat and dissat probabilities.
700
703
fn insert_elem_closure < Pk : MiniscriptKey , Ctx : ScriptContext > (
701
- map : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
704
+ map : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
702
705
astelem_ext : AstElemExt < Pk , Ctx > ,
703
706
sat_prob : f64 ,
704
707
dissat_prob : Option < f64 > ,
@@ -734,7 +737,7 @@ fn insert_elem_closure<Pk: MiniscriptKey, Ctx: ScriptContext>(
734
737
fn insert_best_wrapped < Pk : MiniscriptKey , Ctx : ScriptContext > (
735
738
policy_cache : & mut PolicyCache < Pk , Ctx > ,
736
739
policy : & Concrete < Pk > ,
737
- map : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
740
+ map : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
738
741
data : AstElemExt < Pk , Ctx > ,
739
742
sat_prob : f64 ,
740
743
dissat_prob : Option < f64 > ,
@@ -762,7 +765,7 @@ fn best_compilations<Pk, Ctx>(
762
765
policy : & Concrete < Pk > ,
763
766
sat_prob : f64 ,
764
767
dissat_prob : Option < f64 > ,
765
- ) -> Result < HashMap < CompilationKey , AstElemExt < Pk , Ctx > > , CompilerError >
768
+ ) -> Result < BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > , CompilerError >
766
769
where
767
770
Pk : MiniscriptKey ,
768
771
Ctx : ScriptContext ,
@@ -774,7 +777,7 @@ where
774
777
return Ok ( ret. clone ( ) ) ;
775
778
}
776
779
777
- let mut ret = HashMap :: new ( ) ;
780
+ let mut ret = BTreeMap :: new ( ) ;
778
781
779
782
//handy macro for good looking code
780
783
macro_rules! insert_wrap {
@@ -843,7 +846,7 @@ where
843
846
compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
844
847
compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
845
848
compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
846
- let mut zero_comp = HashMap :: new ( ) ;
849
+ let mut zero_comp = BTreeMap :: new ( ) ;
847
850
zero_comp. insert (
848
851
CompilationKey :: from_type (
849
852
Type :: from_false ( ) ,
@@ -1042,9 +1045,9 @@ where
1042
1045
fn compile_binary < Pk , Ctx , F > (
1043
1046
policy_cache : & mut PolicyCache < Pk , Ctx > ,
1044
1047
policy : & Concrete < Pk > ,
1045
- ret : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1046
- left_comp : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1047
- right_comp : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1048
+ ret : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1049
+ left_comp : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1050
+ right_comp : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1048
1051
weights : [ f64 ; 2 ] ,
1049
1052
sat_prob : f64 ,
1050
1053
dissat_prob : Option < f64 > ,
@@ -1076,10 +1079,10 @@ where
1076
1079
fn compile_tern < Pk : MiniscriptKey , Ctx : ScriptContext > (
1077
1080
policy_cache : & mut PolicyCache < Pk , Ctx > ,
1078
1081
policy : & Concrete < Pk > ,
1079
- ret : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1080
- a_comp : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1081
- b_comp : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1082
- c_comp : & mut HashMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1082
+ ret : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1083
+ a_comp : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1084
+ b_comp : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1085
+ c_comp : & mut BTreeMap < CompilationKey , AstElemExt < Pk , Ctx > > ,
1083
1086
weights : [ f64 ; 2 ] ,
1084
1087
sat_prob : f64 ,
1085
1088
dissat_prob : Option < f64 > ,
@@ -1170,6 +1173,7 @@ mod tests {
1170
1173
use super :: * ;
1171
1174
use bitcoin:: blockdata:: { opcodes, script} ;
1172
1175
use bitcoin:: { self , hashes, secp256k1, SigHashType } ;
1176
+ use std:: collections:: HashMap ;
1173
1177
use std:: str:: FromStr ;
1174
1178
use std:: string:: String ;
1175
1179
@@ -1272,7 +1276,7 @@ mod tests {
1272
1276
fn compile_q ( ) {
1273
1277
let policy = SPolicy :: from_str ( "or(1@and(pk(),pk()),127@pk())" ) . expect ( "parsing" ) ;
1274
1278
let compilation: DummySegwitAstElemExt =
1275
- best_t ( & mut HashMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
1279
+ best_t ( & mut BTreeMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
1276
1280
1277
1281
assert_eq ! ( compilation. cost_1d( 1.0 , None ) , 88.0 + 74.109375 ) ;
1278
1282
assert_eq ! (
@@ -1284,7 +1288,7 @@ mod tests {
1284
1288
"and(and(and(or(127@thresh(2,pk(),pk(),thresh(2,or(127@pk(),1@pk()),after(100),or(and(pk(),after(200)),and(pk(),sha256(66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925))),pk())),1@pk()),sha256(66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925)),or(127@pk(),1@after(300))),or(127@after(400),pk()))"
1285
1289
) . expect ( "parsing" ) ;
1286
1290
let compilation: DummySegwitAstElemExt =
1287
- best_t ( & mut HashMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
1291
+ best_t ( & mut BTreeMap :: new ( ) , & policy, 1.0 , None ) . unwrap ( ) ;
1288
1292
1289
1293
assert_eq ! ( compilation. cost_1d( 1.0 , None ) , 437.0 + 299.4003295898438 ) ;
1290
1294
assert_eq ! (
0 commit comments