forked from Qortal/qortal
Rework of arbitraryRelayMap to keep track of multiple responses.
Previously, only one peer's response for a hash would be remembered, even if multiple others reported back too. This would cause useful mapping to be lost.
This commit is contained in:
parent
cd5ce6dd5e
commit
84e4f9a1c1
@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.arbitrary.ArbitraryDataFile;
|
||||
import org.qortal.arbitrary.ArbitraryDataFileChunk;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.arbitrary.ArbitraryRelayInfo;
|
||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.network.Network;
|
||||
@ -477,10 +478,8 @@ public class ArbitraryDataFileListManager {
|
||||
Long now = NTP.getTime();
|
||||
for (byte[] hash : hashes) {
|
||||
String hash58 = Base58.encode(hash);
|
||||
Triple<String, Peer, Long> value = new Triple<>(signature58, peer, now);
|
||||
if (arbitraryDataFileManager.arbitraryRelayMap.putIfAbsent(hash58, value) == null) {
|
||||
LOGGER.debug("Added {} to relay map: {}, {}, {}", hash58, signature58, peer, now);
|
||||
}
|
||||
ArbitraryRelayInfo relayMap = new ArbitraryRelayInfo(hash58, signature58, peer, now);
|
||||
ArbitraryDataFileManager.getInstance().addToRelayMap(relayMap);
|
||||
}
|
||||
|
||||
// Forward to requesting peer
|
||||
|
@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.arbitrary.ArbitraryDataFile;
|
||||
import org.qortal.controller.Controller;
|
||||
import org.qortal.data.arbitrary.ArbitraryRelayInfo;
|
||||
import org.qortal.data.network.ArbitraryPeerData;
|
||||
import org.qortal.data.network.PeerData;
|
||||
import org.qortal.data.transaction.ArbitraryTransactionData;
|
||||
@ -39,10 +40,9 @@ public class ArbitraryDataFileManager extends Thread {
|
||||
private Map<String, Long> arbitraryDataFileRequests = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* Map to keep track of hashes that we might need to relay, keyed by the hash of the file (base58 encoded).
|
||||
* Value is comprised of the base58-encoded signature, the peer that is hosting it, and the timestamp that it was added
|
||||
* Map to keep track of hashes that we might need to relay
|
||||
*/
|
||||
public Map<String, Triple<String, Peer, Long>> arbitraryRelayMap = Collections.synchronizedMap(new HashMap<>());
|
||||
public List<ArbitraryRelayInfo> arbitraryRelayMap = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
/**
|
||||
* Map to keep track of any arbitrary data file hash responses
|
||||
@ -97,7 +97,7 @@ public class ArbitraryDataFileManager extends Thread {
|
||||
arbitraryDataFileRequests.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue() < requestMinimumTimestamp);
|
||||
|
||||
final long relayMinimumTimestamp = now - ArbitraryDataManager.getInstance().ARBITRARY_RELAY_TIMEOUT;
|
||||
arbitraryRelayMap.entrySet().removeIf(entry -> entry.getValue().getC() == null || entry.getValue().getC() < relayMinimumTimestamp);
|
||||
arbitraryRelayMap.removeIf(entry -> entry == null || entry.getTimestamp() == null || entry.getTimestamp() < relayMinimumTimestamp);
|
||||
arbitraryDataFileHashResponses.entrySet().removeIf(entry -> entry.getValue().getC() == null || entry.getValue().getC() < relayMinimumTimestamp);
|
||||
}
|
||||
|
||||
@ -391,6 +391,48 @@ public class ArbitraryDataFileManager extends Thread {
|
||||
}
|
||||
|
||||
|
||||
// Relays
|
||||
|
||||
private List<ArbitraryRelayInfo> getRelayInfoListForHash(String hash58) {
|
||||
synchronized (arbitraryRelayMap) {
|
||||
return arbitraryRelayMap.stream()
|
||||
.filter(relayInfo -> Objects.equals(relayInfo.getHash58(), hash58))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private ArbitraryRelayInfo getRandomRelayInfoEntryForHash(String hash58) {
|
||||
LOGGER.info("Fetching random relay info for hash: {}", hash58);
|
||||
List<ArbitraryRelayInfo> relayInfoList = this.getRelayInfoListForHash(hash58);
|
||||
if (relayInfoList != null && !relayInfoList.isEmpty()) {
|
||||
|
||||
// Pick random item
|
||||
int index = new SecureRandom().nextInt(relayInfoList.size());
|
||||
LOGGER.info("Returning random relay info for hash: {} (index {})", hash58, index);
|
||||
return relayInfoList.get(index);
|
||||
}
|
||||
LOGGER.info("No relay info exists for hash: {}", hash58);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addToRelayMap(ArbitraryRelayInfo newEntry) {
|
||||
if (newEntry == null || !newEntry.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove existing entry for this peer if it exists, to renew the timestamp
|
||||
this.removeFromRelayMap(newEntry);
|
||||
|
||||
// Re-add
|
||||
arbitraryRelayMap.add(newEntry);
|
||||
LOGGER.debug("Added entry to relay map: {}", newEntry);
|
||||
}
|
||||
|
||||
private void removeFromRelayMap(ArbitraryRelayInfo entry) {
|
||||
arbitraryRelayMap.removeIf(relayInfo -> relayInfo.equals(entry));
|
||||
}
|
||||
|
||||
|
||||
// Network handlers
|
||||
|
||||
public void onNetworkGetArbitraryDataFileMessage(Peer peer, Message message) {
|
||||
@ -409,7 +451,7 @@ public class ArbitraryDataFileManager extends Thread {
|
||||
|
||||
try {
|
||||
ArbitraryDataFile arbitraryDataFile = ArbitraryDataFile.fromHash(hash, signature);
|
||||
Triple<String, Peer, Long> relayInfo = this.arbitraryRelayMap.get(hash58);
|
||||
ArbitraryRelayInfo relayInfo = this.getRandomRelayInfoEntryForHash(hash58);
|
||||
|
||||
if (arbitraryDataFile.exists()) {
|
||||
LOGGER.trace("Hash {} exists", hash58);
|
||||
@ -426,7 +468,7 @@ public class ArbitraryDataFileManager extends Thread {
|
||||
else if (relayInfo != null) {
|
||||
LOGGER.debug("We have relay info for hash {}", Base58.encode(hash));
|
||||
// We need to ask this peer for the file
|
||||
Peer peerToAsk = relayInfo.getB();
|
||||
Peer peerToAsk = relayInfo.getPeer();
|
||||
if (peerToAsk != null) {
|
||||
|
||||
// Forward the message to this peer
|
||||
|
@ -0,0 +1,60 @@
|
||||
package org.qortal.data.arbitrary;
|
||||
|
||||
import org.qortal.network.Peer;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ArbitraryRelayInfo {
|
||||
|
||||
private final String hash58;
|
||||
private final String signature58;
|
||||
private final Peer peer;
|
||||
private final Long timestamp;
|
||||
|
||||
public ArbitraryRelayInfo(String hash58, String signature58, Peer peer, Long timestamp) {
|
||||
this.hash58 = hash58;
|
||||
this.signature58 = signature58;
|
||||
this.peer = peer;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.getHash58() != null && this.getSignature58() != null
|
||||
&& this.getPeer() != null && this.getTimestamp() != null;
|
||||
}
|
||||
|
||||
public String getHash58() {
|
||||
return this.hash58;
|
||||
}
|
||||
|
||||
public String getSignature58() {
|
||||
return signature58;
|
||||
}
|
||||
|
||||
public Peer getPeer() {
|
||||
return peer;
|
||||
}
|
||||
|
||||
public Long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s = %s, %s, %d", this.hash58, this.signature58, this.peer, this.timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
if (!(other instanceof ArbitraryRelayInfo))
|
||||
return false;
|
||||
|
||||
ArbitraryRelayInfo otherRelayInfo = (ArbitraryRelayInfo) other;
|
||||
|
||||
return this.peer == otherRelayInfo.getPeer()
|
||||
&& Objects.equals(this.hash58, otherRelayInfo.getHash58())
|
||||
&& Objects.equals(this.signature58, otherRelayInfo.getSignature58());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user