mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-22 20:26:50 +00:00
WIP: PRESENCE transactions - repository support, removing older versions, tests
This commit is contained in:
@@ -23,9 +23,6 @@ public class PresenceTransactionData extends TransactionData {
|
||||
@Schema(description = "sender's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
||||
private byte[] senderPublicKey;
|
||||
|
||||
@Schema(accessMode = AccessMode.READ_ONLY)
|
||||
private String sender;
|
||||
|
||||
@Schema(accessMode = AccessMode.READ_ONLY)
|
||||
private int nonce;
|
||||
|
||||
|
@@ -771,6 +771,13 @@ public class HSQLDBDatabaseUpdates {
|
||||
stmt.execute("CHECKPOINT");
|
||||
break;
|
||||
|
||||
case 31:
|
||||
// PRESENCE transactions
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS PresenceTransactions ("
|
||||
+ "signature Signature, nonce INT NOT NULL, presence_type INT NOT NULL, "
|
||||
+ "timestamp_signature Signature NOT NULL, " + TRANSACTION_KEYS + ")");
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing to do
|
||||
return false;
|
||||
|
@@ -0,0 +1,57 @@
|
||||
package org.qortal.repository.hsqldb.transaction;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.qortal.data.transaction.BaseTransactionData;
|
||||
import org.qortal.data.transaction.PresenceTransactionData;
|
||||
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
|
||||
import org.qortal.data.transaction.TransactionData;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.repository.hsqldb.HSQLDBRepository;
|
||||
import org.qortal.repository.hsqldb.HSQLDBSaver;
|
||||
|
||||
public class HSQLDBPresenceTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBPresenceTransactionRepository(HSQLDBRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
TransactionData fromBase(BaseTransactionData baseTransactionData) throws DataException {
|
||||
String sql = "SELECT nonce, presence_type, timestamp_signature FROM PresenceTransactions WHERE signature = ?";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, baseTransactionData.getSignature())) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
int nonce = resultSet.getInt(1);
|
||||
int presenceTypeValue = resultSet.getInt(2);
|
||||
PresenceType presenceType = PresenceType.valueOf(presenceTypeValue);
|
||||
|
||||
byte[] timestampSignature = resultSet.getBytes(3);
|
||||
|
||||
return new PresenceTransactionData(baseTransactionData, nonce, presenceType, timestampSignature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch presence transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
PresenceTransactionData presenceTransactionData = (PresenceTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("PresenceTransactions");
|
||||
|
||||
saveHelper.bind("signature", presenceTransactionData.getSignature())
|
||||
.bind("nonce", presenceTransactionData.getNonce())
|
||||
.bind("presence_type", presenceTransactionData.getPresenceType().value)
|
||||
.bind("timestamp_signature", presenceTransactionData.getTimestampSignature());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save chat transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -3,8 +3,9 @@ package org.qortal.transaction;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.account.Account;
|
||||
import org.qortal.asset.Asset;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.crypto.MemoryPoW;
|
||||
import org.qortal.data.transaction.PresenceTransactionData;
|
||||
@@ -15,19 +16,20 @@ import org.qortal.repository.Repository;
|
||||
import org.qortal.transform.TransformationException;
|
||||
import org.qortal.transform.transaction.PresenceTransactionTransformer;
|
||||
import org.qortal.transform.transaction.TransactionTransformer;
|
||||
import org.qortal.utils.Base58;
|
||||
|
||||
import com.google.common.primitives.Longs;
|
||||
|
||||
public class PresenceTransaction extends Transaction {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(PresenceTransaction.class);
|
||||
|
||||
// Properties
|
||||
private PresenceTransactionData presenceTransactionData;
|
||||
|
||||
// Other useful constants
|
||||
public static final int MAX_DATA_SIZE = 256;
|
||||
public static final int POW_BUFFER_SIZE = 8 * 1024 * 1024; // bytes
|
||||
public static final int POW_DIFFICULTY_WITH_QORT = 8; // leading zero bits
|
||||
public static final int POW_DIFFICULTY_NO_QORT = 14; // leading zero bits
|
||||
public static final int POW_DIFFICULTY = 8; // leading zero bits
|
||||
|
||||
// Constructors
|
||||
|
||||
@@ -64,10 +66,8 @@ public class PresenceTransaction extends Transaction {
|
||||
// Clear nonce from transactionBytes
|
||||
PresenceTransactionTransformer.clearNonce(transactionBytes);
|
||||
|
||||
int difficulty = this.getSender().getConfirmedBalance(Asset.QORT) > 0 ? POW_DIFFICULTY_WITH_QORT : POW_DIFFICULTY_NO_QORT;
|
||||
|
||||
// Calculate nonce
|
||||
this.presenceTransactionData.setNonce(MemoryPoW.compute2(transactionBytes, POW_BUFFER_SIZE, difficulty));
|
||||
this.presenceTransactionData.setNonce(MemoryPoW.compute2(transactionBytes, POW_BUFFER_SIZE, POW_DIFFICULTY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,15 +135,27 @@ public class PresenceTransaction extends Transaction {
|
||||
// Clear nonce from transactionBytes
|
||||
PresenceTransactionTransformer.clearNonce(transactionBytes);
|
||||
|
||||
int difficulty;
|
||||
try {
|
||||
difficulty = this.getSender().getConfirmedBalance(Asset.QORT) > 0 ? POW_DIFFICULTY_WITH_QORT : POW_DIFFICULTY_NO_QORT;
|
||||
} catch (DataException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check nonce
|
||||
return MemoryPoW.verify2(transactionBytes, POW_BUFFER_SIZE, difficulty, nonce);
|
||||
return MemoryPoW.verify2(transactionBytes, POW_BUFFER_SIZE, POW_DIFFICULTY, nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any PRESENCE transactions by the same signer that have older timestamps.
|
||||
*/
|
||||
@Override
|
||||
protected void onImportAsUnconfirmed() throws DataException {
|
||||
byte[] creatorPublicKey = this.transactionData.getCreatorPublicKey();
|
||||
List<TransactionData> creatorsPresenceTransactions = this.repository.getTransactionRepository().getUnconfirmedTransactions(TransactionType.PRESENCE, creatorPublicKey);
|
||||
|
||||
if (creatorsPresenceTransactions.isEmpty())
|
||||
return;
|
||||
|
||||
// List should contain oldest transaction first, so remove all but last from repository.
|
||||
creatorsPresenceTransactions.remove(creatorsPresenceTransactions.size() - 1);
|
||||
for (TransactionData transactionData : creatorsPresenceTransactions) {
|
||||
LOGGER.info(() -> String.format("Deleting older PRESENCE transaction %s", Base58.encode(transactionData.getSignature())));
|
||||
this.repository.getTransactionRepository().delete(transactionData);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user