diff --git a/src/main/java/org/qortal/transaction/PresenceTransaction.java b/src/main/java/org/qortal/transaction/PresenceTransaction.java index 755c31a5..4a2ba67a 100644 --- a/src/main/java/org/qortal/transaction/PresenceTransaction.java +++ b/src/main/java/org/qortal/transaction/PresenceTransaction.java @@ -6,10 +6,14 @@ import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.account.Account; +import org.qortal.crosschain.BTCACCT; import org.qortal.crypto.Crypto; import org.qortal.crypto.MemoryPoW; +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; @@ -104,13 +108,32 @@ public class PresenceTransaction extends Transaction { if (this.repository.getTransactionRepository().exists(this.presenceTransactionData.getSignature())) return ValidationResult.INVALID_BUT_OK; + // We only support TRADE_BOT-type PRESENCE at this time + if (PresenceType.TRADE_BOT != this.presenceTransactionData.getPresenceType()) + return ValidationResult.NOT_YET_RELEASED; + // Check timestamp signature byte[] timestampSignature = this.presenceTransactionData.getTimestampSignature(); byte[] timestampBytes = Longs.toByteArray(this.presenceTransactionData.getTimestamp()); if (!Crypto.verify(this.transactionData.getCreatorPublicKey(), timestampSignature, timestampBytes)) return ValidationResult.INVALID_TIMESTAMP_SIGNATURE; - return ValidationResult.OK; + // Check signer is known trade address + String signerAddress = Crypto.toAddress(this.transactionData.getCreatorPublicKey()); + + byte[] codeHash = BTCACCT.CODE_BYTES_HASH; + boolean isExecutable = true; + + List atsData = repository.getATRepository().getATsByFunctionality(codeHash, isExecutable, null, null, null); + + for (ATData atData : atsData) { + CrossChainTradeData crossChainTradeData = BTCACCT.populateTradeData(repository, atData); + + if (crossChainTradeData.qortalCreatorTradeAddress.equals(signerAddress)) + return ValidationResult.OK; + } + + return ValidationResult.AT_UNKNOWN; } @Override diff --git a/src/test/java/org/qortal/test/PresenceTests.java b/src/test/java/org/qortal/test/PresenceTests.java index 96cdc98c..228a543b 100644 --- a/src/test/java/org/qortal/test/PresenceTests.java +++ b/src/test/java/org/qortal/test/PresenceTests.java @@ -4,18 +4,25 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.qortal.account.PrivateKeyAccount; +import org.qortal.asset.Asset; +import org.qortal.crosschain.BTCACCT; 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; import org.qortal.repository.RepositoryManager; +import org.qortal.test.common.BlockUtils; 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.Transaction; import org.qortal.transaction.Transaction.ValidationResult; +import org.qortal.utils.NTP; import com.google.common.primitives.Longs; @@ -23,6 +30,9 @@ import static org.junit.Assert.*; public class PresenceTests extends Common { + private static final byte[] BITCOIN_PKH = new byte[20]; + private static final byte[] HASH_OF_SECRET_B = new byte[32]; + private PrivateKeyAccount signer; private Repository repository; @@ -32,6 +42,31 @@ public class PresenceTests extends Common { this.repository = RepositoryManager.getRepository(); this.signer = Common.getTestAccount(this.repository, "bob"); + + // We need to create corresponding test trade offer + byte[] creationBytes = BTCACCT.buildQortalAT(this.signer.getAddress(), BITCOIN_PKH, HASH_OF_SECRET_B, + 0L, 0L, + 7 * 24 * 60 * 60); + + long txTimestamp = NTP.getTime(); + byte[] lastReference = this.signer.getLastReference(); + + long fee = 0; + String name = "QORT-BTC cross-chain trade"; + String description = "Qortal-Bitcoin cross-chain trade"; + String atType = "ACCT"; + String tags = "QORT-BTC ACCT"; + + BaseTransactionData baseTransactionData = new BaseTransactionData(txTimestamp, Group.NO_GROUP, lastReference, this.signer.getPublicKey(), fee, null); + TransactionData deployAtTransactionData = new DeployAtTransactionData(baseTransactionData, name, description, atType, tags, creationBytes, 1L, Asset.QORT); + + Transaction deployAtTransaction = new DeployAtTransaction(repository, deployAtTransactionData); + + fee = deployAtTransaction.calcRecommendedFee(); + deployAtTransactionData.setFee(fee); + + TransactionUtils.signAndImportValid(this.repository, deployAtTransactionData, this.signer); + BlockUtils.mintBlock(this.repository); } @After @@ -50,6 +85,9 @@ public class PresenceTests extends Common { byte[] timestampSignature = this.signer.sign(timestampBytes); assertTrue(isValid(Group.NO_GROUP, this.signer, timestamp, timestampSignature)); + + PrivateKeyAccount nonTrader = Common.getTestAccount(repository, "alice"); + assertFalse(isValid(Group.NO_GROUP, nonTrader, timestamp, timestampSignature)); } @Test @@ -87,7 +125,7 @@ public class PresenceTests extends Common { timestampSignature = this.signer.sign(Longs.toByteArray(timestamp)); BaseTransactionData baseTransactionData = new BaseTransactionData(timestamp, txGroupId, reference, creatorPublicKey, fee, null); - PresenceTransactionData transactionData = new PresenceTransactionData(baseTransactionData, nonce, PresenceType.REWARD_SHARE, timestampSignature); + PresenceTransactionData transactionData = new PresenceTransactionData(baseTransactionData, nonce, PresenceType.TRADE_BOT, timestampSignature); return new PresenceTransaction(this.repository, transactionData); }