hostedTransactions = this.listAllHostedTransactions(repository, null, null);
- for (ArbitraryTransactionData transactionData : hostedTransactions) {
- String transactionName = transactionData.getName();
- if (!Objects.equals(name, transactionName)) {
- // Transaction relates to a different name
- continue;
- }
-
- totalSizeForName += transactionData.getSize();
- }
-
- // Have we reached the limit for this name?
- if (totalSizeForName > maxStoragePerName) {
- return false;
- }
-
- return true;
- }
-
public long storageCapacityPerName(double threshold) {
int followedNamesCount = ListUtils.followedNamesCount();
if (followedNamesCount == 0) {
diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryTransactionDataHashWrapper.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryTransactionDataHashWrapper.java
new file mode 100644
index 00000000..9ff40771
--- /dev/null
+++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryTransactionDataHashWrapper.java
@@ -0,0 +1,48 @@
+package org.qortal.controller.arbitrary;
+
+import org.qortal.arbitrary.misc.Service;
+import org.qortal.data.transaction.ArbitraryTransactionData;
+
+import java.util.Objects;
+
+public class ArbitraryTransactionDataHashWrapper {
+
+ private ArbitraryTransactionData data;
+
+ private int service;
+
+ private String name;
+
+ private String identifier;
+
+ public ArbitraryTransactionDataHashWrapper(ArbitraryTransactionData data) {
+ this.data = data;
+
+ this.service = data.getService().value;
+ this.name = data.getName();
+ this.identifier = data.getIdentifier();
+ }
+
+ public ArbitraryTransactionDataHashWrapper(int service, String name, String identifier) {
+ this.service = service;
+ this.name = name;
+ this.identifier = identifier;
+ }
+
+ public ArbitraryTransactionData getData() {
+ return data;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ArbitraryTransactionDataHashWrapper that = (ArbitraryTransactionDataHashWrapper) o;
+ return service == that.service && name.equals(that.name) && Objects.equals(identifier, that.identifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(service, name, identifier);
+ }
+}
diff --git a/src/main/java/org/qortal/controller/arbitrary/RebuildArbitraryResourceCacheTask.java b/src/main/java/org/qortal/controller/arbitrary/RebuildArbitraryResourceCacheTask.java
new file mode 100644
index 00000000..d7472325
--- /dev/null
+++ b/src/main/java/org/qortal/controller/arbitrary/RebuildArbitraryResourceCacheTask.java
@@ -0,0 +1,33 @@
+package org.qortal.controller.arbitrary;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.qortal.repository.DataException;
+import org.qortal.repository.Repository;
+import org.qortal.repository.RepositoryManager;
+
+import java.util.TimerTask;
+
+public class RebuildArbitraryResourceCacheTask extends TimerTask {
+
+ private static final Logger LOGGER = LogManager.getLogger(RebuildArbitraryResourceCacheTask.class);
+
+ public static final long MILLIS_IN_HOUR = 60 * 60 * 1000;
+
+ public static final long MILLIS_IN_MINUTE = 60 * 1000;
+
+ private static final String REBUILD_ARBITRARY_RESOURCE_CACHE_TASK = "Rebuild Arbitrary Resource Cache Task";
+
+ @Override
+ public void run() {
+
+ Thread.currentThread().setName(REBUILD_ARBITRARY_RESOURCE_CACHE_TASK);
+
+ try (final Repository repository = RepositoryManager.getRepository()) {
+ ArbitraryDataCacheManager.getInstance().buildArbitraryResourcesCache(repository, true);
+ }
+ catch( DataException e ) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+}
diff --git a/src/main/java/org/qortal/crosschain/Bitcoiny.java b/src/main/java/org/qortal/crosschain/Bitcoiny.java
index a4f5a2af..d93fa65f 100644
--- a/src/main/java/org/qortal/crosschain/Bitcoiny.java
+++ b/src/main/java/org/qortal/crosschain/Bitcoiny.java
@@ -83,6 +83,7 @@ public abstract class Bitcoiny implements ForeignBlockchain {
return this.bitcoinjContext;
}
+ @Override
public String getCurrencyCode() {
return this.currencyCode;
}
diff --git a/src/main/java/org/qortal/crosschain/ElectrumX.java b/src/main/java/org/qortal/crosschain/ElectrumX.java
index 6c917659..82c7b89d 100644
--- a/src/main/java/org/qortal/crosschain/ElectrumX.java
+++ b/src/main/java/org/qortal/crosschain/ElectrumX.java
@@ -644,8 +644,10 @@ public class ElectrumX extends BitcoinyBlockchainProvider {
}
/**
- * Performs RPC call, with automatic reconnection to different server if needed.
- *
+ *
Performs RPC call, with automatic reconnection to different server if needed.
+ *
+ * @param method String representation of the RPC call value
+ * @param params a list of Objects passed to the method of the Remote Server
* @return "result" object from within JSON output
* @throws ForeignBlockchainException if server returns error or something goes wrong
*/
diff --git a/src/main/java/org/qortal/crosschain/ForeignBlockchain.java b/src/main/java/org/qortal/crosschain/ForeignBlockchain.java
index fe64ab83..c66f2719 100644
--- a/src/main/java/org/qortal/crosschain/ForeignBlockchain.java
+++ b/src/main/java/org/qortal/crosschain/ForeignBlockchain.java
@@ -2,6 +2,8 @@ package org.qortal.crosschain;
public interface ForeignBlockchain {
+ public String getCurrencyCode();
+
public boolean isValidAddress(String address);
public boolean isValidWalletKey(String walletKey);
diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndex.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndex.java
new file mode 100644
index 00000000..9b6bf415
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndex.java
@@ -0,0 +1,34 @@
+package org.qortal.data.arbitrary;
+
+import org.qortal.arbitrary.misc.Service;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ArbitraryDataIndex {
+
+ public String t;
+ public String n;
+ public int c;
+ public String l;
+
+ public ArbitraryDataIndex() {}
+
+ public ArbitraryDataIndex(String t, String n, int c, String l) {
+ this.t = t;
+ this.n = n;
+ this.c = c;
+ this.l = l;
+ }
+
+ @Override
+ public String toString() {
+ return "ArbitraryDataIndex{" +
+ "t='" + t + '\'' +
+ ", n='" + n + '\'' +
+ ", c=" + c +
+ ", l='" + l + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexDetail.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexDetail.java
new file mode 100644
index 00000000..d073c736
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexDetail.java
@@ -0,0 +1,41 @@
+package org.qortal.data.arbitrary;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ArbitraryDataIndexDetail {
+
+ public String issuer;
+ public int rank;
+ public String term;
+ public String name;
+ public int category;
+ public String link;
+ public String indexIdentifer;
+
+ public ArbitraryDataIndexDetail() {}
+
+ public ArbitraryDataIndexDetail(String issuer, int rank, ArbitraryDataIndex index, String indexIdentifer) {
+ this.issuer = issuer;
+ this.rank = rank;
+ this.term = index.t;
+ this.name = index.n;
+ this.category = index.c;
+ this.link = index.l;
+ this.indexIdentifer = indexIdentifer;
+ }
+
+ @Override
+ public String toString() {
+ return "ArbitraryDataIndexDetail{" +
+ "issuer='" + issuer + '\'' +
+ ", rank=" + rank +
+ ", term='" + term + '\'' +
+ ", name='" + name + '\'' +
+ ", category=" + category +
+ ", link='" + link + '\'' +
+ ", indexIdentifer='" + indexIdentifer + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScoreKey.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScoreKey.java
new file mode 100644
index 00000000..46a661e5
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScoreKey.java
@@ -0,0 +1,38 @@
+package org.qortal.data.arbitrary;
+
+import org.qortal.arbitrary.misc.Service;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import java.util.Objects;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ArbitraryDataIndexScoreKey {
+
+ public String name;
+ public int category;
+ public String link;
+
+ public ArbitraryDataIndexScoreKey() {}
+
+ public ArbitraryDataIndexScoreKey(String name, int category, String link) {
+ this.name = name;
+ this.category = category;
+ this.link = link;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ArbitraryDataIndexScoreKey that = (ArbitraryDataIndexScoreKey) o;
+ return category == that.category && Objects.equals(name, that.name) && Objects.equals(link, that.link);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, category, link);
+ }
+
+
+}
diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScorecard.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScorecard.java
new file mode 100644
index 00000000..1888a4a5
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryDataIndexScorecard.java
@@ -0,0 +1,38 @@
+package org.qortal.data.arbitrary;
+
+import org.qortal.arbitrary.misc.Service;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ArbitraryDataIndexScorecard {
+
+ public double score;
+ public String name;
+ public int category;
+ public String link;
+
+ public ArbitraryDataIndexScorecard() {}
+
+ public ArbitraryDataIndexScorecard(double score, String name, int category, String link) {
+ this.score = score;
+ this.name = name;
+ this.category = category;
+ this.link = link;
+ }
+
+ public double getScore() {
+ return score;
+ }
+
+ @Override
+ public String toString() {
+ return "ArbitraryDataIndexScorecard{" +
+ "score=" + score +
+ ", name='" + name + '\'' +
+ ", category=" + category +
+ ", link='" + link + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/org/qortal/data/arbitrary/DataMonitorInfo.java b/src/main/java/org/qortal/data/arbitrary/DataMonitorInfo.java
new file mode 100644
index 00000000..5ee76c29
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/DataMonitorInfo.java
@@ -0,0 +1,57 @@
+package org.qortal.data.arbitrary;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class DataMonitorInfo {
+ private long timestamp;
+ private String identifier;
+ private String name;
+ private String service;
+ private String description;
+ private long transactionTimestamp;
+ private long latestPutTimestamp;
+
+ public DataMonitorInfo() {
+ }
+
+ public DataMonitorInfo(long timestamp, String identifier, String name, String service, String description, long transactionTimestamp, long latestPutTimestamp) {
+
+ this.timestamp = timestamp;
+ this.identifier = identifier;
+ this.name = name;
+ this.service = service;
+ this.description = description;
+ this.transactionTimestamp = transactionTimestamp;
+ this.latestPutTimestamp = latestPutTimestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public long getTransactionTimestamp() {
+ return transactionTimestamp;
+ }
+
+ public long getLatestPutTimestamp() {
+ return latestPutTimestamp;
+ }
+}
diff --git a/src/main/java/org/qortal/data/arbitrary/IndexCache.java b/src/main/java/org/qortal/data/arbitrary/IndexCache.java
new file mode 100644
index 00000000..dd5c12ab
--- /dev/null
+++ b/src/main/java/org/qortal/data/arbitrary/IndexCache.java
@@ -0,0 +1,23 @@
+package org.qortal.data.arbitrary;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class IndexCache {
+
+ public static final IndexCache SINGLETON = new IndexCache();
+ private ConcurrentHashMap> indicesByTerm = new ConcurrentHashMap<>();
+ private ConcurrentHashMap> indicesByIssuer = new ConcurrentHashMap<>();
+
+ public static IndexCache getInstance() {
+ return SINGLETON;
+ }
+
+ public ConcurrentHashMap> getIndicesByTerm() {
+ return indicesByTerm;
+ }
+
+ public ConcurrentHashMap> getIndicesByIssuer() {
+ return indicesByIssuer;
+ }
+}
diff --git a/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java b/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java
index f3828de8..81cfaa68 100644
--- a/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java
+++ b/src/main/java/org/qortal/data/transaction/ArbitraryTransactionData.java
@@ -200,4 +200,26 @@ public class ArbitraryTransactionData extends TransactionData {
return this.payments;
}
+ @Override
+ public String toString() {
+ return "ArbitraryTransactionData{" +
+ "version=" + version +
+ ", service=" + service +
+ ", nonce=" + nonce +
+ ", size=" + size +
+ ", name='" + name + '\'' +
+ ", identifier='" + identifier + '\'' +
+ ", method=" + method +
+ ", compression=" + compression +
+ ", dataType=" + dataType +
+ ", type=" + type +
+ ", timestamp=" + timestamp +
+ ", fee=" + fee +
+ ", txGroupId=" + txGroupId +
+ ", blockHeight=" + blockHeight +
+ ", blockSequence=" + blockSequence +
+ ", approvalStatus=" + approvalStatus +
+ ", approvalHeight=" + approvalHeight +
+ '}';
+ }
}
diff --git a/src/main/java/org/qortal/event/DataMonitorEvent.java b/src/main/java/org/qortal/event/DataMonitorEvent.java
new file mode 100644
index 00000000..c62d9acf
--- /dev/null
+++ b/src/main/java/org/qortal/event/DataMonitorEvent.java
@@ -0,0 +1,57 @@
+package org.qortal.event;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+public class DataMonitorEvent implements Event{
+ private long timestamp;
+ private String identifier;
+ private String name;
+ private String service;
+ private String description;
+ private long transactionTimestamp;
+ private long latestPutTimestamp;
+
+ public DataMonitorEvent() {
+ }
+
+ public DataMonitorEvent(long timestamp, String identifier, String name, String service, String description, long transactionTimestamp, long latestPutTimestamp) {
+
+ this.timestamp = timestamp;
+ this.identifier = identifier;
+ this.name = name;
+ this.service = service;
+ this.description = description;
+ this.transactionTimestamp = transactionTimestamp;
+ this.latestPutTimestamp = latestPutTimestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getService() {
+ return service;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public long getTransactionTimestamp() {
+ return transactionTimestamp;
+ }
+
+ public long getLatestPutTimestamp() {
+ return latestPutTimestamp;
+ }
+}
diff --git a/src/main/java/org/qortal/group/Group.java b/src/main/java/org/qortal/group/Group.java
index 765b86de..a6b4f3a6 100644
--- a/src/main/java/org/qortal/group/Group.java
+++ b/src/main/java/org/qortal/group/Group.java
@@ -674,8 +674,8 @@ public class Group {
public void uninvite(GroupInviteTransactionData groupInviteTransactionData) throws DataException {
String invitee = groupInviteTransactionData.getInvitee();
- // If member exists then they were added when invite matched join request
- if (this.memberExists(invitee)) {
+ // If member exists and the join request is present then they were added when invite matched join request
+ if (this.memberExists(invitee) && groupInviteTransactionData.getJoinReference() != null) {
// Rebuild join request using cached reference to transaction that created join request.
this.rebuildJoinRequest(invitee, groupInviteTransactionData.getJoinReference());
diff --git a/src/main/java/org/qortal/repository/ATRepository.java b/src/main/java/org/qortal/repository/ATRepository.java
index fe001137..2b653ab5 100644
--- a/src/main/java/org/qortal/repository/ATRepository.java
+++ b/src/main/java/org/qortal/repository/ATRepository.java
@@ -76,9 +76,9 @@ public interface ATRepository {
* Although expectedValue, if provided, is natively an unsigned long,
* the data segment comparison is done via unsigned hex string.
*/
- public List getMatchingFinalATStates(byte[] codeHash, String buyerAddress, String sellerAddress, Boolean isFinished,
- Integer dataByteOffset, Long expectedValue, Integer minimumFinalHeight,
- Integer limit, Integer offset, Boolean reverse) throws DataException;
+ public List getMatchingFinalATStates(byte[] codeHash, byte[] buyerPublicKey, byte[] sellerPublicKey, Boolean isFinished,
+ Integer dataByteOffset, Long expectedValue, Integer minimumFinalHeight,
+ Integer limit, Integer offset, Boolean reverse) throws DataException;
/**
* Returns final ATStateData for ATs matching codeHash (required)
diff --git a/src/main/java/org/qortal/repository/ArbitraryRepository.java b/src/main/java/org/qortal/repository/ArbitraryRepository.java
index 1c0e84e2..4770d29b 100644
--- a/src/main/java/org/qortal/repository/ArbitraryRepository.java
+++ b/src/main/java/org/qortal/repository/ArbitraryRepository.java
@@ -27,6 +27,10 @@ public interface ArbitraryRepository {
public List getArbitraryTransactions(String name, Service service, String identifier, long since) throws DataException;
+ List getLatestArbitraryTransactions() throws DataException;
+
+ List getLatestArbitraryTransactionsByName(String name) throws DataException;
+
public ArbitraryTransactionData getInitialTransaction(String name, Service service, Method method, String identifier) throws DataException;
public ArbitraryTransactionData getLatestTransaction(String name, Service service, Method method, String identifier) throws DataException;
@@ -42,7 +46,7 @@ public interface ArbitraryRepository {
public List getArbitraryResources(Service service, String identifier, List names, boolean defaultResource, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Integer limit, Integer offset, Boolean reverse) throws DataException;
- public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, boolean prefixOnly, List namesFilter, boolean defaultResource, SearchMode mode, Integer minLevel, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException;
+ public List searchArbitraryResources(Service service, String query, String identifier, List names, String title, String description, List keywords, boolean prefixOnly, List namesFilter, boolean defaultResource, SearchMode mode, Integer minLevel, Boolean followedOnly, Boolean excludeBlocked, Boolean includeMetadata, Boolean includeStatus, Long before, Long after, Integer limit, Integer offset, Boolean reverse) throws DataException;
List searchArbitraryResourcesSimple(
Service service,
diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java
index 71a95428..6310ec02 100644
--- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java
+++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java
@@ -5,6 +5,7 @@ import com.google.common.primitives.Longs;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.qortal.controller.Controller;
+import org.qortal.crypto.Crypto;
import org.qortal.data.at.ATData;
import org.qortal.data.at.ATStateData;
import org.qortal.repository.ATRepository;
@@ -403,9 +404,9 @@ public class HSQLDBATRepository implements ATRepository {
}
@Override
- public List getMatchingFinalATStates(byte[] codeHash, String buyerAddress, String sellerAddress, Boolean isFinished,
- Integer dataByteOffset, Long expectedValue, Integer minimumFinalHeight,
- Integer limit, Integer offset, Boolean reverse) throws DataException {
+ public List getMatchingFinalATStates(byte[] codeHash, byte[] buyerPublicKey, byte[] sellerPublicKey, Boolean isFinished,
+ Integer dataByteOffset, Long expectedValue, Integer minimumFinalHeight,
+ Integer limit, Integer offset, Boolean reverse) throws DataException {
StringBuilder sql = new StringBuilder(1024);
List