@@ -1054,6 +1054,135 @@ impl<A: Anchor> TxGraph<A> {
1054
1054
. filter_map ( Result :: transpose)
1055
1055
}
1056
1056
1057
+ /// Get a canonical set of txids.
1058
+ pub fn canoncial_set < C : ChainOracle > (
1059
+ & self ,
1060
+ chain : & C ,
1061
+ chain_tip : BlockId ,
1062
+ ) -> Result < HashSet < Txid > , C :: Error > {
1063
+ let mut definitely_canonical = HashSet :: < Txid > :: new ( ) ;
1064
+ let mut definitely_not_canonical = HashSet :: < Txid > :: new ( ) ;
1065
+ let txid_by_last_seen = self
1066
+ . last_seen
1067
+ . iter ( )
1068
+ . map ( |( & txid, & last_seen) | ( last_seen, txid) )
1069
+ . collect :: < BTreeSet < _ > > ( ) ;
1070
+ for ( _, txid) in txid_by_last_seen {
1071
+ self . canonicalize_by_traversing_up (
1072
+ chain,
1073
+ chain_tip,
1074
+ & mut definitely_canonical,
1075
+ & mut definitely_not_canonical,
1076
+ txid,
1077
+ ) ?;
1078
+ }
1079
+ Ok ( definitely_canonical)
1080
+ }
1081
+
1082
+ fn canonicalize_by_traversing_up < C : ChainOracle > (
1083
+ & self ,
1084
+ chain : & C ,
1085
+ chain_tip : BlockId ,
1086
+ definitely_canonical : & mut HashSet < Txid > ,
1087
+ definitely_not_canonical : & mut HashSet < Txid > ,
1088
+ txid : Txid ,
1089
+ ) -> Result < ( ) , C :: Error > {
1090
+ type TxWithId = ( Txid , Arc < Transaction > ) ;
1091
+ let tx = match self . get_tx ( txid) {
1092
+ Some ( tx) => tx,
1093
+ None => return Ok ( ( ) ) ,
1094
+ } ;
1095
+ let maybe_canonical = TxAncestors :: new_include_root (
1096
+ self ,
1097
+ tx,
1098
+ |_: usize , tx : Arc < Transaction > | -> Option < Result < TxWithId , C :: Error > > {
1099
+ let txid = tx. compute_txid ( ) ;
1100
+ match self . is_definitely_canonical (
1101
+ chain,
1102
+ chain_tip,
1103
+ definitely_canonical,
1104
+ definitely_not_canonical,
1105
+ txid,
1106
+ ) {
1107
+ Ok ( None ) => Some ( Ok ( ( txid, tx) ) ) ,
1108
+ Ok ( Some ( _) ) => None ,
1109
+ Err ( err) => Some ( Err ( err) ) ,
1110
+ }
1111
+ } ,
1112
+ )
1113
+ . collect :: < Result < Vec < _ > , C :: Error > > ( ) ?;
1114
+ // TODO: Check if this is correct.
1115
+ for ( txid, tx) in maybe_canonical {
1116
+ if !definitely_not_canonical. contains ( & txid) {
1117
+ self . mark_definitely_canonical ( definitely_canonical, tx) ;
1118
+ }
1119
+ }
1120
+ Ok ( ( ) )
1121
+ }
1122
+
1123
+ fn is_definitely_canonical < C : ChainOracle > (
1124
+ & self ,
1125
+ chain : & C ,
1126
+ chain_tip : BlockId ,
1127
+ definitely_canonical : & mut HashSet < Txid > ,
1128
+ definitely_not_canonical : & mut HashSet < Txid > ,
1129
+ txid : Txid ,
1130
+ ) -> Result < Option < bool > , C :: Error > {
1131
+ if definitely_canonical. contains ( & txid) {
1132
+ return Ok ( Some ( true ) ) ;
1133
+ }
1134
+ if definitely_not_canonical. contains ( & txid) {
1135
+ return Ok ( Some ( false ) ) ;
1136
+ }
1137
+ let tx = match self . get_tx ( txid) {
1138
+ Some ( tx) => tx,
1139
+ None => return Ok ( None ) ,
1140
+ } ;
1141
+ for anchor in self . anchors . get ( & txid) . unwrap_or ( & self . empty_anchors ) {
1142
+ if chain. is_block_in_chain ( anchor. anchor_block ( ) , chain_tip) ? == Some ( true ) {
1143
+ self . mark_definitely_canonical ( definitely_canonical, tx) ;
1144
+ return Ok ( Some ( true ) ) ;
1145
+ }
1146
+ }
1147
+ for ( _, conflicting_txid) in self . direct_conflicts ( & tx) {
1148
+ if definitely_canonical. contains ( & conflicting_txid) {
1149
+ self . mark_definitely_not_canonical ( definitely_not_canonical, txid) ;
1150
+ return Ok ( Some ( false ) ) ;
1151
+ }
1152
+ }
1153
+ Ok ( None )
1154
+ }
1155
+
1156
+ fn mark_definitely_not_canonical (
1157
+ & self ,
1158
+ definitely_not_canonical : & mut HashSet < Txid > ,
1159
+ txid : Txid ,
1160
+ ) {
1161
+ TxDescendants :: new_include_root ( self , txid, |_: usize , txid : Txid | -> Option < ( ) > {
1162
+ if definitely_not_canonical. insert ( txid) {
1163
+ Some ( ( ) )
1164
+ } else {
1165
+ None
1166
+ }
1167
+ } )
1168
+ . for_each ( |_| { } )
1169
+ }
1170
+
1171
+ fn mark_definitely_canonical (
1172
+ & self ,
1173
+ definitely_canonical : & mut HashSet < Txid > ,
1174
+ tx : Arc < Transaction > ,
1175
+ ) {
1176
+ TxAncestors :: new_include_root ( self , tx, |_: usize , tx : Arc < Transaction > | -> Option < ( ) > {
1177
+ if definitely_canonical. insert ( tx. compute_txid ( ) ) {
1178
+ Some ( ( ) )
1179
+ } else {
1180
+ None
1181
+ }
1182
+ } )
1183
+ . for_each ( |_| { } )
1184
+ }
1185
+
1057
1186
/// Get a filtered list of outputs from the given `outpoints` that are in `chain` with
1058
1187
/// `chain_tip`.
1059
1188
///
0 commit comments