forked from Qortal/qortal
WIP: PRESENCE - TradeBot support, moved PresenceType enum, added Presence-only transaction deadline override
This commit is contained in:
parent
cfacddcb36
commit
e093520696
@ -3,7 +3,10 @@ package org.qortal.controller;
|
|||||||
import java.awt.TrayIcon.MessageType;
|
import java.awt.TrayIcon.MessageType;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
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.BaseTransactionData;
|
||||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||||
import org.qortal.data.transaction.MessageTransactionData;
|
import org.qortal.data.transaction.MessageTransactionData;
|
||||||
|
import org.qortal.data.transaction.PresenceTransactionData;
|
||||||
import org.qortal.event.Event;
|
import org.qortal.event.Event;
|
||||||
import org.qortal.event.EventBus;
|
import org.qortal.event.EventBus;
|
||||||
import org.qortal.event.Listener;
|
import org.qortal.event.Listener;
|
||||||
@ -43,13 +47,18 @@ import org.qortal.repository.RepositoryManager;
|
|||||||
import org.qortal.settings.Settings;
|
import org.qortal.settings.Settings;
|
||||||
import org.qortal.transaction.DeployAtTransaction;
|
import org.qortal.transaction.DeployAtTransaction;
|
||||||
import org.qortal.transaction.MessageTransaction;
|
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.transaction.Transaction.ValidationResult;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
import org.qortal.transform.transaction.DeployAtTransactionTransformer;
|
import org.qortal.transform.transaction.DeployAtTransactionTransformer;
|
||||||
|
import org.qortal.transform.transaction.TransactionTransformer;
|
||||||
import org.qortal.utils.Amounts;
|
import org.qortal.utils.Amounts;
|
||||||
import org.qortal.utils.Base58;
|
import org.qortal.utils.Base58;
|
||||||
import org.qortal.utils.NTP;
|
import org.qortal.utils.NTP;
|
||||||
|
|
||||||
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performing cross-chain trading steps on behalf of user.
|
* Performing cross-chain trading steps on behalf of user.
|
||||||
* <p>
|
* <p>
|
||||||
@ -86,6 +95,8 @@ public class TradeBot implements Listener {
|
|||||||
|
|
||||||
private static TradeBot instance;
|
private static TradeBot instance;
|
||||||
|
|
||||||
|
private final Map<String, Long> presenceTimestampsByAtAddress = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
private TradeBot() {
|
private TradeBot() {
|
||||||
EventBus.INSTANCE.addListener(event -> TradeBot.getInstance().listen(event));
|
EventBus.INSTANCE.addListener(event -> TradeBot.getInstance().listen(event));
|
||||||
}
|
}
|
||||||
@ -348,26 +359,32 @@ public class TradeBot implements Listener {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ALICE_WAITING_FOR_P2SH_A:
|
case ALICE_WAITING_FOR_P2SH_A:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleAliceWaitingForP2shA(repository, tradeBotData);
|
handleAliceWaitingForP2shA(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOB_WAITING_FOR_MESSAGE:
|
case BOB_WAITING_FOR_MESSAGE:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleBobWaitingForMessage(repository, tradeBotData);
|
handleBobWaitingForMessage(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALICE_WAITING_FOR_AT_LOCK:
|
case ALICE_WAITING_FOR_AT_LOCK:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleAliceWaitingForAtLock(repository, tradeBotData);
|
handleAliceWaitingForAtLock(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOB_WAITING_FOR_P2SH_B:
|
case BOB_WAITING_FOR_P2SH_B:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleBobWaitingForP2shB(repository, tradeBotData);
|
handleBobWaitingForP2shB(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALICE_WATCH_P2SH_B:
|
case ALICE_WATCH_P2SH_B:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleAliceWatchingP2shB(repository, tradeBotData);
|
handleAliceWatchingP2shB(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BOB_WAITING_FOR_AT_REDEEM:
|
case BOB_WAITING_FOR_AT_REDEEM:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleBobWaitingForAtRedeem(repository, tradeBotData);
|
handleBobWaitingForAtRedeem(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -376,10 +393,12 @@ public class TradeBot implements Listener {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ALICE_REFUNDING_B:
|
case ALICE_REFUNDING_B:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleAliceRefundingP2shB(repository, tradeBotData);
|
handleAliceRefundingP2shB(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALICE_REFUNDING_A:
|
case ALICE_REFUNDING_A:
|
||||||
|
updatePresence(repository, tradeBotData);
|
||||||
handleAliceRefundingP2shA(repository, tradeBotData);
|
handleAliceRefundingP2shA(repository, tradeBotData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1249,4 +1268,41 @@ public class TradeBot implements Listener {
|
|||||||
EventBus.INSTANCE.notify(stateChangeEvent);
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
package org.qortal.data.transaction;
|
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.Unmarshaller;
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
|
||||||
|
import org.qortal.transaction.PresenceTransaction.PresenceType;
|
||||||
import org.qortal.transaction.Transaction.TransactionType;
|
import org.qortal.transaction.Transaction.TransactionType;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
@ -26,20 +22,6 @@ public class PresenceTransactionData extends TransactionData {
|
|||||||
@Schema(accessMode = AccessMode.READ_ONLY)
|
@Schema(accessMode = AccessMode.READ_ONLY)
|
||||||
private int nonce;
|
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;
|
private PresenceType presenceType;
|
||||||
|
|
||||||
@Schema(description = "timestamp signature", example = "2yGEbwRFyhPZZckKA")
|
@Schema(description = "timestamp signature", example = "2yGEbwRFyhPZZckKA")
|
||||||
|
@ -40,7 +40,7 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
|
|||||||
GroupApprovalTransactionData.class, SetGroupTransactionData.class,
|
GroupApprovalTransactionData.class, SetGroupTransactionData.class,
|
||||||
UpdateAssetTransactionData.class,
|
UpdateAssetTransactionData.class,
|
||||||
AccountFlagsTransactionData.class, RewardShareTransactionData.class,
|
AccountFlagsTransactionData.class, RewardShareTransactionData.class,
|
||||||
AccountLevelTransactionData.class, ChatTransactionData.class
|
AccountLevelTransactionData.class, ChatTransactionData.class, PresenceTransactionData.class
|
||||||
})
|
})
|
||||||
//All properties to be converted to JSON via JAXB
|
//All properties to be converted to JSON via JAXB
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
@ -5,11 +5,11 @@ import java.sql.SQLException;
|
|||||||
|
|
||||||
import org.qortal.data.transaction.BaseTransactionData;
|
import org.qortal.data.transaction.BaseTransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData;
|
import org.qortal.data.transaction.PresenceTransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
|
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.repository.hsqldb.HSQLDBRepository;
|
import org.qortal.repository.hsqldb.HSQLDBRepository;
|
||||||
import org.qortal.repository.hsqldb.HSQLDBSaver;
|
import org.qortal.repository.hsqldb.HSQLDBSaver;
|
||||||
|
import org.qortal.transaction.PresenceTransaction.PresenceType;
|
||||||
|
|
||||||
public class HSQLDBPresenceTransactionRepository extends HSQLDBTransactionRepository {
|
public class HSQLDBPresenceTransactionRepository extends HSQLDBTransactionRepository {
|
||||||
|
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
package org.qortal.transaction;
|
package org.qortal.transaction;
|
||||||
|
|
||||||
|
import static java.util.Arrays.stream;
|
||||||
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.qortal.account.Account;
|
import org.qortal.account.Account;
|
||||||
|
import org.qortal.controller.Controller;
|
||||||
import org.qortal.crosschain.BTCACCT;
|
import org.qortal.crosschain.BTCACCT;
|
||||||
import org.qortal.crypto.Crypto;
|
import org.qortal.crypto.Crypto;
|
||||||
import org.qortal.crypto.MemoryPoW;
|
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.crosschain.CrossChainTradeData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData;
|
import org.qortal.data.transaction.PresenceTransactionData;
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
|
|
||||||
import org.qortal.group.Group;
|
import org.qortal.group.Group;
|
||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.repository.Repository;
|
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_BUFFER_SIZE = 8 * 1024 * 1024; // bytes
|
||||||
public static final int POW_DIFFICULTY = 8; // leading zero bits
|
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
|
// Constructors
|
||||||
|
|
||||||
public PresenceTransaction(Repository repository, TransactionData transactionData) {
|
public PresenceTransaction(Repository repository, TransactionData transactionData) {
|
||||||
@ -45,6 +77,11 @@ public class PresenceTransaction extends Transaction {
|
|||||||
|
|
||||||
// More information
|
// More information
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDeadline() {
|
||||||
|
return this.transactionData.getTimestamp() + this.presenceTransactionData.getPresenceType().getLifetime();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRecipientAddresses() throws DataException {
|
public List<String> getRecipientAddresses() throws DataException {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -6,8 +6,8 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import org.qortal.data.transaction.BaseTransactionData;
|
import org.qortal.data.transaction.BaseTransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData;
|
import org.qortal.data.transaction.PresenceTransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
|
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
|
import org.qortal.transaction.PresenceTransaction.PresenceType;
|
||||||
import org.qortal.transaction.Transaction.TransactionType;
|
import org.qortal.transaction.Transaction.TransactionType;
|
||||||
import org.qortal.transform.TransformationException;
|
import org.qortal.transform.TransformationException;
|
||||||
import org.qortal.utils.Serialization;
|
import org.qortal.utils.Serialization;
|
||||||
|
@ -10,7 +10,6 @@ import org.qortal.data.transaction.BaseTransactionData;
|
|||||||
import org.qortal.data.transaction.DeployAtTransactionData;
|
import org.qortal.data.transaction.DeployAtTransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData;
|
import org.qortal.data.transaction.PresenceTransactionData;
|
||||||
import org.qortal.data.transaction.TransactionData;
|
import org.qortal.data.transaction.TransactionData;
|
||||||
import org.qortal.data.transaction.PresenceTransactionData.PresenceType;
|
|
||||||
import org.qortal.group.Group;
|
import org.qortal.group.Group;
|
||||||
import org.qortal.repository.DataException;
|
import org.qortal.repository.DataException;
|
||||||
import org.qortal.repository.Repository;
|
import org.qortal.repository.Repository;
|
||||||
@ -20,6 +19,7 @@ import org.qortal.test.common.Common;
|
|||||||
import org.qortal.test.common.TransactionUtils;
|
import org.qortal.test.common.TransactionUtils;
|
||||||
import org.qortal.transaction.DeployAtTransaction;
|
import org.qortal.transaction.DeployAtTransaction;
|
||||||
import org.qortal.transaction.PresenceTransaction;
|
import org.qortal.transaction.PresenceTransaction;
|
||||||
|
import org.qortal.transaction.PresenceTransaction.PresenceType;
|
||||||
import org.qortal.transaction.Transaction;
|
import org.qortal.transaction.Transaction;
|
||||||
import org.qortal.transaction.Transaction.ValidationResult;
|
import org.qortal.transaction.Transaction.ValidationResult;
|
||||||
import org.qortal.utils.NTP;
|
import org.qortal.utils.NTP;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user