Skip to content

Commit e797abd

Browse files
committed
firewall: obfuscate PendingChannels
Only obfuscate pending open channels for now.
1 parent ef84753 commit e797abd

File tree

2 files changed

+465
-0
lines changed

2 files changed

+465
-0
lines changed

firewall/privacy_mapper.go

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
10101321
func maybeHideAmount(flags session.PrivacyFlags, randIntn func(int) (int,
10111322
error), a int64) (int64, error) {

0 commit comments

Comments
 (0)