@@ -290,6 +290,12 @@ func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB,
290290 handleClosedChannelsResponse (db , flags , p .randIntn ),
291291 mid .PassThroughErrorHandler ,
292292 ),
293+ "/lnrpc.Lightning/PendingChannels" : mid .NewResponseRewriter (
294+ & lnrpc.PendingChannelsRequest {},
295+ & lnrpc.PendingChannelsResponse {},
296+ handlePendingChannelsResponse (db , flags , p .randIntn ),
297+ mid .PassThroughErrorHandler ,
298+ ),
293299 }
294300}
295301
@@ -1006,6 +1012,311 @@ func handleClosedChannelsResponse(db firewalldb.PrivacyMapDB,
10061012 }
10071013}
10081014
1015+ // obfuscatePendingChannel is a helper to obfuscate the fields of a pending
1016+ // channel.
1017+ func obfuscatePendingChannel (c * lnrpc.PendingChannelsResponse_PendingChannel ,
1018+ tx firewalldb.PrivacyMapTx , randIntn func (int ) (int , error ),
1019+ flags session.PrivacyFlags ) (
1020+ * lnrpc.PendingChannelsResponse_PendingChannel , error ) {
1021+
1022+ var err error
1023+
1024+ remotePub := c .RemoteNodePub
1025+ if ! flags .Contains (session .ClearPubkeys ) {
1026+ remotePub , err = firewalldb .HideString (
1027+ tx , remotePub ,
1028+ )
1029+ if err != nil {
1030+ return nil , err
1031+ }
1032+ }
1033+
1034+ capacity , err := maybeHideAmount (
1035+ flags , randIntn , c .Capacity ,
1036+ )
1037+ if err != nil {
1038+ return nil , err
1039+ }
1040+
1041+ // We randomize local/remote balances.
1042+ localBalance , err := maybeHideAmount (
1043+ flags , randIntn , c .LocalBalance ,
1044+ )
1045+ if err != nil {
1046+ return nil , err
1047+ }
1048+
1049+ // We may have a too large value for the local
1050+ // balance, restrict it to the capacity.
1051+ if localBalance > capacity {
1052+ localBalance = capacity
1053+ }
1054+
1055+ // The remote balance is set constently to the local balance.
1056+ remoteBalance := c .RemoteBalance
1057+ if ! flags .Contains (session .ClearAmounts ) {
1058+ remoteBalance = capacity - localBalance
1059+ }
1060+
1061+ chanPoint := c .ChannelPoint
1062+ if ! flags .Contains (session .ClearChanIDs ) {
1063+ chanPoint , err = firewalldb .HideChanPointStr (
1064+ tx , c .ChannelPoint ,
1065+ )
1066+ if err != nil {
1067+ return nil , err
1068+ }
1069+ }
1070+
1071+ return & lnrpc.PendingChannelsResponse_PendingChannel {
1072+ // Obfuscated fields.
1073+ ChannelPoint : chanPoint ,
1074+ RemoteNodePub : remotePub ,
1075+ Capacity : capacity ,
1076+ LocalBalance : localBalance ,
1077+ RemoteBalance : remoteBalance ,
1078+
1079+ // Non-obfuscated fields.
1080+ ChanStatusFlags : c .ChanStatusFlags ,
1081+ Private : c .Private ,
1082+ CommitmentType : c .CommitmentType ,
1083+ Initiator : c .Initiator ,
1084+ NumForwardingPackages : c .NumForwardingPackages ,
1085+ Memo : c .Memo ,
1086+
1087+ // Omitted fields.
1088+ // LocalChanReserveSat
1089+ // RemoteChanReserveSat
1090+ }, nil
1091+ }
1092+
1093+ func handlePendingChannelsResponse (db firewalldb.PrivacyMapDB ,
1094+ flags session.PrivacyFlags ,
1095+ randIntn func (int ) (int , error )) func (ctx context.Context ,
1096+ r * lnrpc.PendingChannelsResponse ) (proto.Message , error ) {
1097+
1098+ return func (_ context.Context , r * lnrpc.PendingChannelsResponse ) (
1099+ proto.Message , error ) {
1100+
1101+ pendingOpens := make (
1102+ []* lnrpc.PendingChannelsResponse_PendingOpenChannel ,
1103+ len (r .PendingOpenChannels ),
1104+ )
1105+
1106+ pendingCloses := make (
1107+ []* lnrpc.PendingChannelsResponse_ClosedChannel ,
1108+ len (r .PendingClosingChannels ),
1109+ )
1110+
1111+ pendingForceCloses := make (
1112+ []* lnrpc.PendingChannelsResponse_ForceClosedChannel ,
1113+ len (r .PendingForceClosingChannels ),
1114+ )
1115+
1116+ waitingCloses := make (
1117+ []* lnrpc.PendingChannelsResponse_WaitingCloseChannel ,
1118+ len (r .WaitingCloseChannels ),
1119+ )
1120+
1121+ err := db .Update (func (tx firewalldb.PrivacyMapTx ) error {
1122+ for i , c := range r .PendingOpenChannels {
1123+ var err error
1124+
1125+ pendingChannel , err := obfuscatePendingChannel (
1126+ c .Channel , tx , randIntn , flags ,
1127+ )
1128+ if err != nil {
1129+ return err
1130+ }
1131+
1132+ pendingOpen := lnrpc.PendingChannelsResponse_PendingOpenChannel {
1133+ // Non-obfuscated fields.
1134+ CommitFee : c .CommitFee ,
1135+ CommitWeight : c .CommitWeight ,
1136+ FeePerKw : c .FeePerKw ,
1137+ FundingExpiryBlocks : c .FundingExpiryBlocks ,
1138+
1139+ // Obfuscated fields.
1140+ Channel : pendingChannel ,
1141+ }
1142+
1143+ pendingOpens [i ] = & pendingOpen
1144+ }
1145+
1146+ for i , c := range r .PendingClosingChannels {
1147+ var err error
1148+
1149+ pendingChannel , err := obfuscatePendingChannel (
1150+ c .Channel , tx , randIntn , flags ,
1151+ )
1152+ if err != nil {
1153+ return err
1154+ }
1155+
1156+ closingTxid := c .ClosingTxid
1157+ if ! flags .Contains (session .ClearClosingTxIds ) {
1158+ closingTxid , err = firewalldb .HideString (
1159+ tx , c .ClosingTxid ,
1160+ )
1161+ if err != nil {
1162+ return err
1163+ }
1164+ }
1165+
1166+ pendingClose := lnrpc.PendingChannelsResponse_ClosedChannel {
1167+ // Obfuscated fields.
1168+ ClosingTxid : closingTxid ,
1169+ Channel : pendingChannel ,
1170+ }
1171+
1172+ pendingCloses [i ] = & pendingClose
1173+ }
1174+
1175+ for i , c := range r .PendingForceClosingChannels {
1176+ var err error
1177+
1178+ pendingChannel , err := obfuscatePendingChannel (
1179+ c .Channel , tx , randIntn , flags ,
1180+ )
1181+ if err != nil {
1182+ return err
1183+ }
1184+
1185+ closingTxid := c .ClosingTxid
1186+ if ! flags .Contains (session .ClearClosingTxIds ) {
1187+ closingTxid , err = firewalldb .HideString (
1188+ tx , c .ClosingTxid ,
1189+ )
1190+ if err != nil {
1191+ return err
1192+ }
1193+ }
1194+
1195+ limboBalance , err := maybeHideAmount (
1196+ flags , randIntn , c .LimboBalance ,
1197+ )
1198+ if err != nil {
1199+ return err
1200+ }
1201+
1202+ if limboBalance > pendingChannel .Capacity {
1203+ limboBalance = pendingChannel .Capacity
1204+ }
1205+
1206+ recoveredBalance , err := maybeHideAmount (
1207+ flags , randIntn , c .RecoveredBalance ,
1208+ )
1209+ if err != nil {
1210+ return err
1211+ }
1212+
1213+ if recoveredBalance > pendingChannel .Capacity {
1214+ limboBalance = pendingChannel .Capacity
1215+ }
1216+
1217+ pendingForceClose := lnrpc.PendingChannelsResponse_ForceClosedChannel {
1218+ // Obfuscated fields.
1219+ ClosingTxid : closingTxid ,
1220+ LimboBalance : limboBalance ,
1221+ RecoveredBalance : recoveredBalance ,
1222+ Channel : pendingChannel ,
1223+
1224+ // Non-obfuscated fields.
1225+ MaturityHeight : c .MaturityHeight ,
1226+ BlocksTilMaturity : c .BlocksTilMaturity ,
1227+ Anchor : c .Anchor ,
1228+
1229+ // Omitted fields.
1230+ PendingHtlcs : []* lnrpc.PendingHTLC {},
1231+ }
1232+
1233+ pendingForceCloses [i ] = & pendingForceClose
1234+ }
1235+
1236+ for i , c := range r .WaitingCloseChannels {
1237+ var err error
1238+
1239+ pendingChannel , err := obfuscatePendingChannel (
1240+ c .Channel , tx , randIntn , flags ,
1241+ )
1242+ if err != nil {
1243+ return err
1244+ }
1245+
1246+ limboBalance , err := maybeHideAmount (
1247+ flags , randIntn , c .LimboBalance ,
1248+ )
1249+ if err != nil {
1250+ return err
1251+ }
1252+
1253+ if limboBalance > pendingChannel .Capacity {
1254+ limboBalance = pendingChannel .Capacity
1255+ }
1256+
1257+ closingTxid := c .ClosingTxid
1258+ if ! flags .Contains (session .ClearClosingTxIds ) {
1259+ closingTxid , err = firewalldb .HideString (
1260+ tx , closingTxid ,
1261+ )
1262+ if err != nil {
1263+ return err
1264+ }
1265+ }
1266+
1267+ // The closing tx hash is constrained by the
1268+ // request, see docstring, which is why we only
1269+ // obfuscate if a value is set.
1270+ closingTxHex := c .ClosingTxHex
1271+ if c .ClosingTxHex != "" &&
1272+ ! flags .Contains (
1273+ session .ClearClosingTxIds ,
1274+ ) {
1275+
1276+ closingTxHex , err = firewalldb .HideString (
1277+ tx , closingTxHex ,
1278+ )
1279+ if err != nil {
1280+ return err
1281+ }
1282+ }
1283+
1284+ waitingCloseChannel := lnrpc.PendingChannelsResponse_WaitingCloseChannel {
1285+ Channel : pendingChannel ,
1286+ LimboBalance : limboBalance ,
1287+ ClosingTxid : closingTxid ,
1288+ ClosingTxHex : closingTxHex ,
1289+
1290+ // Omitted.
1291+ Commitments : & lnrpc.PendingChannelsResponse_Commitments {},
1292+ }
1293+
1294+ waitingCloses [i ] = & waitingCloseChannel
1295+ }
1296+
1297+ return nil
1298+ })
1299+ if err != nil {
1300+ return nil , err
1301+ }
1302+
1303+ totalLimbo , err := maybeHideAmount (
1304+ flags , randIntn , r .TotalLimboBalance ,
1305+ )
1306+ if err != nil {
1307+ return nil , err
1308+ }
1309+
1310+ return & lnrpc.PendingChannelsResponse {
1311+ TotalLimboBalance : totalLimbo ,
1312+ PendingOpenChannels : pendingOpens ,
1313+ PendingClosingChannels : pendingCloses ,
1314+ PendingForceClosingChannels : pendingForceCloses ,
1315+ WaitingCloseChannels : waitingCloses ,
1316+ }, nil
1317+ }
1318+ }
1319+
10091320// maybeHideAmount hides an amount if the privacy flag is not set.
10101321func maybeHideAmount (flags session.PrivacyFlags , randIntn func (int ) (int ,
10111322 error ), a int64 ) (int64 , error ) {
0 commit comments