Merge pull request #5061 from chimp1984/persist-failed-mailbox-msg-decryption-attempts

Persist failed attempts of decrypting mailbox messages
This commit is contained in:
Christoph Atteneder 2021-01-08 10:35:41 +01:00 committed by GitHub
commit 1daa58624d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 172 additions and 6 deletions

View File

@ -44,6 +44,7 @@ import bisq.core.user.PreferencesPayload;
import bisq.core.user.UserPayload;
import bisq.network.p2p.MailboxMessageList;
import bisq.network.p2p.mailbox.IgnoredMailboxMap;
import bisq.network.p2p.peers.peerexchange.PeerList;
import bisq.network.p2p.storage.persistence.SequenceNumberMap;
@ -132,7 +133,8 @@ public class CorePersistenceProtoResolver extends CoreProtoResolver implements P
return TradeStatistics3Store.fromProto(proto.getTradeStatistics3Store());
case MAILBOX_MESSAGE_LIST:
return MailboxMessageList.fromProto(proto.getMailboxMessageList(), networkProtoResolver);
case IGNORED_MAILBOX_MAP:
return IgnoredMailboxMap.fromProto(proto.getIgnoredMailboxMap());
default:
throw new ProtobufferRuntimeException("Unknown proto message case(PB.PersistableEnvelope). " +
"messageCase=" + proto.getMessageCase() + "; proto raw data=" + proto.toString());

View File

@ -36,6 +36,7 @@ import bisq.core.user.Preferences;
import bisq.core.user.User;
import bisq.network.p2p.P2PService;
import bisq.network.p2p.mailbox.IgnoredMailboxService;
import bisq.network.p2p.peers.PeerManager;
import bisq.network.p2p.storage.P2PDataStorage;
@ -68,6 +69,7 @@ public class CorePersistedDataHost {
persistedDataHosts.add(injector.getInstance(P2PDataStorage.class));
persistedDataHosts.add(injector.getInstance(PeerManager.class));
persistedDataHosts.add(injector.getInstance(P2PService.class));
persistedDataHosts.add(injector.getInstance(IgnoredMailboxService.class));
if (injector.getInstance(Config.class).daoActivated) {
persistedDataHosts.add(injector.getInstance(BallotListService.class));

View File

@ -19,6 +19,7 @@ package bisq.network.p2p;
import bisq.network.Socks5ProxyProvider;
import bisq.network.crypto.EncryptionService;
import bisq.network.p2p.mailbox.IgnoredMailboxService;
import bisq.network.p2p.messaging.DecryptedMailboxListener;
import bisq.network.p2p.network.CloseConnectionReason;
import bisq.network.p2p.network.Connection;
@ -50,6 +51,7 @@ import bisq.common.app.Capability;
import bisq.common.crypto.CryptoException;
import bisq.common.crypto.KeyRing;
import bisq.common.crypto.PubKeyRing;
import bisq.common.crypto.SealedAndSigned;
import bisq.common.persistence.PersistenceManager;
import bisq.common.proto.ProtobufferException;
import bisq.common.proto.network.NetworkEnvelope;
@ -110,6 +112,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
private final SeedNodeRepository seedNodeRepository;
private final EncryptionService encryptionService;
private final IgnoredMailboxService ignoredMailboxService;
private final PersistenceManager<MailboxMessageList> persistenceManager;
private final KeyRing keyRing;
@ -158,6 +161,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
SeedNodeRepository seedNodeRepository,
Socks5ProxyProvider socks5ProxyProvider,
EncryptionService encryptionService,
IgnoredMailboxService ignoredMailboxService,
PersistenceManager<MailboxMessageList> persistenceManager,
KeyRing keyRing) {
this.networkNode = networkNode;
@ -170,6 +174,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
this.seedNodeRepository = seedNodeRepository;
this.socks5ProxyProvider = socks5ProxyProvider;
this.encryptionService = encryptionService;
this.ignoredMailboxService = ignoredMailboxService;
this.persistenceManager = persistenceManager;
this.keyRing = keyRing;
@ -513,15 +518,23 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
@Nullable
private MailboxItem decryptProtectedMailboxStorageEntry(ProtectedMailboxStorageEntry protectedMailboxStorageEntry) {
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = protectedMailboxStorageEntry
.getMailboxStoragePayload()
.getPrefixedSealedAndSignedMessage();
SealedAndSigned sealedAndSigned = prefixedSealedAndSignedMessage.getSealedAndSigned();
String uid = prefixedSealedAndSignedMessage.getUid();
if (ignoredMailboxService.isIgnored(uid)) {
// We had persisted a past failed decryption attempt on that message so we don't try again and return early
return null;
}
try {
DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerify(protectedMailboxStorageEntry
.getMailboxStoragePayload()
.getPrefixedSealedAndSignedMessage()
.getSealedAndSigned());
DecryptedMessageWithPubKey decryptedMessageWithPubKey = encryptionService.decryptAndVerify(sealedAndSigned);
checkArgument(decryptedMessageWithPubKey.getNetworkEnvelope() instanceof MailboxMessage);
return new MailboxItem(protectedMailboxStorageEntry, decryptedMessageWithPubKey);
} catch (CryptoException ignore) {
// Expected if message was not intended for us
// We persist those entries so at the next startup we do not need to try to decrypt it anymore
ignoredMailboxService.ignore(uid, protectedMailboxStorageEntry.getCreationTimeStamp());
} catch (ProtobufferException e) {
log.error(e.toString());
e.getStackTrace();

View File

@ -0,0 +1,71 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.network.p2p.mailbox;
import bisq.common.proto.persistable.PersistableEnvelope;
import bisq.common.util.CollectionUtils;
import java.util.HashMap;
import java.util.Map;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@EqualsAndHashCode
public class IgnoredMailboxMap implements PersistableEnvelope {
@Getter
private final Map<String, Long> dataMap;
public IgnoredMailboxMap() {
this.dataMap = new HashMap<>();
}
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
public IgnoredMailboxMap(Map<String, Long> ignored) {
this.dataMap = ignored;
}
@Override
public protobuf.PersistableEnvelope toProtoMessage() {
return protobuf.PersistableEnvelope.newBuilder()
.setIgnoredMailboxMap(protobuf.IgnoredMailboxMap.newBuilder().putAllData(dataMap))
.build();
}
public static IgnoredMailboxMap fromProto(protobuf.IgnoredMailboxMap proto) {
return new IgnoredMailboxMap(CollectionUtils.isEmpty(proto.getDataMap()) ? new HashMap<>() : proto.getDataMap());
}
public void putAll(Map<String, Long> map) {
dataMap.putAll(map);
}
public boolean containsKey(String uid) {
return dataMap.containsKey(uid);
}
public void put(String uid, long creationTimeStamp) {
dataMap.put(uid, creationTimeStamp);
}
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.network.p2p.mailbox;
import bisq.network.p2p.storage.payload.MailboxStoragePayload;
import bisq.common.persistence.PersistenceManager;
import bisq.common.proto.persistable.PersistedDataHost;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* We persist failed attempts to decrypt mailbox messages (expected if mailbox message was not addressed to us).
* This improves performance at processing mailbox messages.
* On a fast 4 core machine 1000 mailbox messages take about 1.5 second. At second start-up using the persisted data
* it only takes about 30 ms.
*/
@Singleton
public class IgnoredMailboxService implements PersistedDataHost {
private final PersistenceManager<IgnoredMailboxMap> persistenceManager;
private final IgnoredMailboxMap ignoredMailboxMap = new IgnoredMailboxMap();
@Inject
public IgnoredMailboxService(PersistenceManager<IgnoredMailboxMap> persistenceManager) {
this.persistenceManager = persistenceManager;
this.persistenceManager.initialize(ignoredMailboxMap, PersistenceManager.Source.PRIVATE_LOW_PRIO);
}
///////////////////////////////////////////////////////////////////////////////////////////
// PersistedDataHost
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void readPersisted(Runnable completeHandler) {
persistenceManager.readPersisted(persisted -> {
// At each load we cleanup outdated entries
long expiredDate = System.currentTimeMillis() - MailboxStoragePayload.TTL;
persisted.getDataMap().entrySet().stream()
.filter(e -> e.getValue() > expiredDate)
.forEach(e -> ignoredMailboxMap.put(e.getKey(), e.getValue()));
persistenceManager.requestPersistence();
completeHandler.run();
},
completeHandler);
}
public boolean isIgnored(String uid) {
return ignoredMailboxMap.containsKey(uid);
}
public void ignore(String uid, long creationTimeStamp) {
ignoredMailboxMap.put(uid, creationTimeStamp);
persistenceManager.requestPersistence();
}
}

View File

@ -53,6 +53,8 @@ import javax.annotation.Nullable;
@EqualsAndHashCode
@Slf4j
public final class MailboxStoragePayload implements ProtectedStoragePayload, ExpirablePayload, AddOncePayload {
public static final long TTL = TimeUnit.DAYS.toMillis(15);
private final PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage;
private PublicKey senderPubKeyForAddOperation;
private final byte[] senderPubKeyForAddOperationBytes;
@ -118,6 +120,6 @@ public final class MailboxStoragePayload implements ProtectedStoragePayload, Exp
@Override
public long getTTL() {
return TimeUnit.DAYS.toMillis(15);
return TTL;
}
}

View File

@ -577,6 +577,10 @@ message MailboxMessageList {
repeated MailboxItem mailbox_item = 1;
}
message IgnoredMailboxMap {
map<string, uint64> data = 1;
}
message MailboxItem {
ProtectedMailboxStorageEntry protected_mailbox_storage_entry = 1;
DecryptedMessageWithPubKey decrypted_message_with_pub_key = 2;
@ -1215,6 +1219,7 @@ message PersistableEnvelope {
RefundDisputeList refund_dispute_list = 30;
TradeStatistics3Store trade_statistics3_store = 31;
MailboxMessageList mailbox_message_list = 32;
IgnoredMailboxMap ignored_mailbox_map = 33;
}
}