WIP: PRESENCE - TradeBot support, moved PresenceType enum, added Presence-only transaction deadline override

This commit is contained in:
catbref 2020-11-27 18:06:24 +00:00
parent cfacddcb36
commit e093520696
7 changed files with 99 additions and 24 deletions

View File

@ -3,7 +3,10 @@ package org.qortal.controller;
import java.awt.TrayIcon.MessageType;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.logging.log4j.LogManager;
@ -32,6 +35,7 @@ import org.qortal.data.crosschain.TradeBotData;
import org.qortal.data.transaction.BaseTransactionData;
import org.qortal.data.transaction.DeployAtTransactionData;
import org.qortal.data.transaction.MessageTransactionData;
import org.qortal.data.transaction.PresenceTransactionData;
import org.qortal.event.Event;
import org.qortal.event.EventBus;
import org.qortal.event.Listener;
@ -43,13 +47,18 @@ import org.qortal.repository.RepositoryManager;
import org.qortal.settings.Settings;
import org.qortal.transaction.DeployAtTransaction;
import org.qortal.transaction.MessageTransaction;
import org.qortal.transaction.PresenceTransaction;
import org.qortal.transaction.PresenceTransaction.PresenceType;
import org.qortal.transaction.Transaction.ValidationResult;
import org.qortal.transform.TransformationException;
import org.qortal.transform.transaction.DeployAtTransactionTransformer;
import org.qortal.transform.transaction.TransactionTransformer;
import org.qortal.utils.Amounts;
import org.qortal.utils.Base58;
import org.qortal.utils.NTP;
import com.google.common.primitives.Longs;
/**
* Performing cross-chain trading steps on behalf of user.
* <p>
@ -86,6 +95,8 @@ public class TradeBot implements Listener {
private static TradeBot instance;
private final Map<String, Long> presenceTimestampsByAtAddress = Collections.synchronizedMap(new HashMap<>());
private TradeBot() {
EventBus.INSTANCE.addListener(event -> TradeBot.getInstance().listen(event));
}
@ -348,26 +359,32 @@ public class TradeBot implements Listener {
break;
case ALICE_WAITING_FOR_P2SH_A:
updatePresence(repository, tradeBotData);
handleAliceWaitingForP2shA(repository, tradeBotData);
break;
case BOB_WAITING_FOR_MESSAGE:
updatePresence(repository, tradeBotData);
handleBobWaitingForMessage(repository, tradeBotData);
break;
case ALICE_WAITING_FOR_AT_LOCK:
updatePresence(repository, tradeBotData);
handleAliceWaitingForAtLock(repository, tradeBotData);
break;
case BOB_WAITING_FOR_P2SH_B:
updatePresence(repository, tradeBotData);
handleBobWaitingForP2shB(repository, tradeBotData);
break;
case ALICE_WATCH_P2SH_B:
updatePresence(repository, tradeBotData);
handleAliceWatchingP2shB(repository, tradeBotData);
break;
case BOB_WAITING_FOR_AT_REDEEM:
updatePresence(repository, tradeBotData);
handleBobWaitingForAtRedeem(repository, tradeBotData);
break;
@ -376,10 +393,12 @@ public class TradeBot implements Listener {
break;
case ALICE_REFUNDING_B:
updatePresence(repository, tradeBotData);
handleAliceRefundingP2shB(repository, tradeBotData);
break;
case ALICE_REFUNDING_A:
updatePresence(repository, tradeBotData);
handleAliceRefundingP2shA(repository, tradeBotData);
break;
@ -1249,4 +1268,41 @@ public class TradeBot implements Listener {
EventBus.INSTANCE.notify(stateChangeEvent);
}
// PRESENCE-related
private void updatePresence(Repository repository, TradeBotData tradeBotData) throws DataException {
String key = tradeBotData.getAtAddress();
long now = NTP.getTime();
long threshold = now - PresenceType.TRADE_BOT.getLifetime();
long timestamp = presenceTimestampsByAtAddress.compute(key, (k, v) -> (v == null || v < threshold) ? now : v);
// If timestamp hasn't been updated then nothing to do
if (timestamp != now)
return;
PrivateKeyAccount tradeNativeAccount = new PrivateKeyAccount(repository, tradeBotData.getTradePrivateKey());
int txGroupId = Group.NO_GROUP;
byte[] reference = new byte[TransactionTransformer.SIGNATURE_LENGTH];
byte[] creatorPublicKey = tradeNativeAccount.getPublicKey();
long fee = 0L;
BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, creatorPublicKey, fee, null);
int nonce = 0;
byte[] timestampSignature = tradeNativeAccount.sign(Longs.toByteArray(timestamp));
PresenceTransactionData transactionData = new PresenceTransactionData(baseTransactionData, nonce, PresenceType.TRADE_BOT, timestampSignature);
PresenceTransaction presenceTransaction = new PresenceTransaction(repository, transactionData);
presenceTransaction.computeNonce();
presenceTransaction.sign(tradeNativeAccount);
ValidationResult result = presenceTransaction.importAsUnconfirmed();
if (result != ValidationResult.OK)
LOGGER.debug(() -> String.format("Unable to build trade-bot PRESENCE transaction for %s: %s", tradeBotData.getAtAddress(), result.name()));
}
}

View File

@ -1,14 +1,10 @@
package org.qortal.data.transaction;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;
import java.util.Map;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import org.qortal.transaction.PresenceTransaction.PresenceType;
import org.qortal.transaction.Transaction.TransactionType;
import io.swagger.v3.oas.annotations.media.Schema;
@ -26,20 +22,6 @@ public class PresenceTransactionData extends TransactionData {
@Schema(accessMode = AccessMode.READ_ONLY)
private int nonce;
public enum PresenceType {
REWARD_SHARE(0), TRADE_BOT(1);
public final int value;
private static final Map<Integer, PresenceType> map = stream(PresenceType.values()).collect(toMap(type -> type.value, type -> type));
PresenceType(int value) {
this.value = value;
}
public static PresenceType valueOf(int value) {
return map.get(value);
}
}
private PresenceType presenceType;
@Schema(description = "timestamp signature", example = "2yGEbwRFyhPZZckKA")

View File

@ -40,7 +40,7 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
GroupApprovalTransactionData.class, SetGroupTransactionData.class,
UpdateAssetTransactionData.class,
AccountFlagsTransactionData.class, RewardShareTransactionData.class,
AccountLevelTransactionData.class, ChatTransactionData.class
AccountLevelTransactionData.class, ChatTransactionData.class, PresenceTransactionData.class
})
//All properties to be converted to JSON via JAXB
@XmlAccessorType(XmlAccessType.FIELD)

View File

@ -5,11 +5,11 @@ 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;
import org.qortal.transaction.PresenceTransaction.PresenceType;
public class HSQLDBPresenceTransactionRepository extends HSQLDBTransactionRepository {

View File

@ -1,11 +1,16 @@
package org.qortal.transaction;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.qortal.account.Account;
import org.qortal.controller.Controller;
import org.qortal.crosschain.BTCACCT;
import org.qortal.crypto.Crypto;
import org.qortal.crypto.MemoryPoW;
@ -13,7 +18,6 @@ import org.qortal.data.at.ATData;
import org.qortal.data.crosschain.CrossChainTradeData;
import org.qortal.data.transaction.PresenceTransactionData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
import org.qortal.group.Group;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
@ -35,6 +39,34 @@ public class PresenceTransaction extends Transaction {
public static final int POW_BUFFER_SIZE = 8 * 1024 * 1024; // bytes
public static final int POW_DIFFICULTY = 8; // leading zero bits
public enum PresenceType {
REWARD_SHARE(0) {
@Override
public long getLifetime() {
return Controller.ONLINE_TIMESTAMP_MODULUS;
}
},
TRADE_BOT(1) {
@Override
public long getLifetime() {
return 30 * 60 * 1000L; // 30 minutes in milliseconds
}
};
public final int value;
private static final Map<Integer, PresenceType> map = stream(PresenceType.values()).collect(toMap(type -> type.value, type -> type));
PresenceType(int value) {
this.value = value;
}
public abstract long getLifetime();
public static PresenceType valueOf(int value) {
return map.get(value);
}
}
// Constructors
public PresenceTransaction(Repository repository, TransactionData transactionData) {
@ -45,6 +77,11 @@ public class PresenceTransaction extends Transaction {
// More information
@Override
public long getDeadline() {
return this.transactionData.getTimestamp() + this.presenceTransactionData.getPresenceType().getLifetime();
}
@Override
public List<String> getRecipientAddresses() throws DataException {
return Collections.emptyList();

View File

@ -6,8 +6,8 @@ import java.nio.ByteBuffer;
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.transaction.PresenceTransaction.PresenceType;
import org.qortal.transaction.Transaction.TransactionType;
import org.qortal.transform.TransformationException;
import org.qortal.utils.Serialization;

View File

@ -10,7 +10,6 @@ import org.qortal.data.transaction.BaseTransactionData;
import org.qortal.data.transaction.DeployAtTransactionData;
import org.qortal.data.transaction.PresenceTransactionData;
import org.qortal.data.transaction.TransactionData;
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
import org.qortal.group.Group;
import org.qortal.repository.DataException;
import org.qortal.repository.Repository;
@ -20,6 +19,7 @@ import org.qortal.test.common.Common;
import org.qortal.test.common.TransactionUtils;
import org.qortal.transaction.DeployAtTransaction;
import org.qortal.transaction.PresenceTransaction;
import org.qortal.transaction.PresenceTransaction.PresenceType;
import org.qortal.transaction.Transaction;
import org.qortal.transaction.Transaction.ValidationResult;
import org.qortal.utils.NTP;