diff --git a/src/main/java/org/qortal/crosschain/BTCACCT.java b/src/main/java/org/qortal/crosschain/BTCACCT.java index 404c9fb0..1adacfb8 100644 --- a/src/main/java/org/qortal/crosschain/BTCACCT.java +++ b/src/main/java/org/qortal/crosschain/BTCACCT.java @@ -105,7 +105,7 @@ public class BTCACCT { public static final int SECRET_LENGTH = 32; public static final int MIN_LOCKTIME = 1500000000; - public static final byte[] CODE_BYTES_HASH = HashCode.fromString("a472f32a6799ff85ed99567701b42fa228c58a09d38485ab208ad78d0f2cc813").asBytes(); // SHA256 of AT code bytes + public static final byte[] CODE_BYTES_HASH = HashCode.fromString("f7f419522a9aaa3c671149878f8c1374dfc59d4fd86ca43ff2a4d913cfbc9e89").asBytes(); // SHA256 of AT code bytes /** Value offset into AT segment where 'mode' variable (long) is stored. (Multiply by MachineState.VALUE_SIZE for byte offset). */ private static final int MODE_VALUE_OFFSET = 68; @@ -343,7 +343,8 @@ public class BTCACCT { Integer labelTradeTxnLoop = null; Integer labelCheckTradeTxn = null; - + Integer labelCheckCancelTxn = null; + Integer labelNotTradeNorCancelTxn = null; Integer labelCheckNonRefundTradeTxn = null; Integer labelTradeTxnExtract = null; Integer labelRedeemTxnLoop = null; @@ -395,38 +396,43 @@ public class BTCACCT { // If transaction type is not MESSAGE type then go look for another transaction codeByteBuffer.put(OpCode.BNE_DAT.compile(addrTxnType, addrMessageTxnType, calcOffset(codeByteBuffer, labelTradeTxnLoop))); - /* Check transaction's sender. We're expecting AT creator's trade address. */ + /* Check transaction's sender. We're expecting AT creator's trade address for 'trade' message, or AT creator's own address for 'cancel' message. */ // Extract sender address from transaction into B register codeByteBuffer.put(OpCode.EXT_FUN.compile(FunctionCode.PUT_ADDRESS_FROM_TX_IN_A_INTO_B)); // Save B register into data segment starting at addrMessageSender1 (as pointed to by addrMessageSenderPointer) codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.GET_B_IND, addrMessageSenderPointer)); - // Compare each part of transaction's sender's address with expected address. If they don't match, look for another transaction. - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender1, addrCreatorTradeAddress1, calcOffset(codeByteBuffer, labelTradeTxnLoop))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender2, addrCreatorTradeAddress2, calcOffset(codeByteBuffer, labelTradeTxnLoop))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender3, addrCreatorTradeAddress3, calcOffset(codeByteBuffer, labelTradeTxnLoop))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender4, addrCreatorTradeAddress4, calcOffset(codeByteBuffer, labelTradeTxnLoop))); + // Compare each part of message sender's address with AT creator's trade address. If they don't match, check for cancel situation. + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender1, addrCreatorTradeAddress1, calcOffset(codeByteBuffer, labelCheckCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender2, addrCreatorTradeAddress2, calcOffset(codeByteBuffer, labelCheckCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender3, addrCreatorTradeAddress3, calcOffset(codeByteBuffer, labelCheckCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender4, addrCreatorTradeAddress4, calcOffset(codeByteBuffer, labelCheckCancelTxn))); + // Message sender's address matches AT creator's trade address so go process 'trade' message + codeByteBuffer.put(OpCode.JMP_ADR.compile(labelCheckNonRefundTradeTxn == null ? 0 : labelCheckNonRefundTradeTxn)); - /* Extract trade partner info from message */ + /* Checking message sender for possible cancel message */ + labelCheckCancelTxn = codeByteBuffer.position(); - // Extract message from transaction into B register - codeByteBuffer.put(OpCode.EXT_FUN.compile(FunctionCode.PUT_MESSAGE_FROM_TX_IN_A_INTO_B)); - // Save B register into data segment starting at addrQortalPartnerAddress1 (as pointed to by addrQortalPartnerAddressPointer) - codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.GET_B_IND, addrQortalPartnerAddressPointer)); - // Compare each of partner address with creator's address (for offer-cancel scenario). If they don't match, assume address is trade partner. - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrQortalPartnerAddress1, addrCreatorAddress1, calcOffset(codeByteBuffer, labelCheckNonRefundTradeTxn))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrQortalPartnerAddress2, addrCreatorAddress2, calcOffset(codeByteBuffer, labelCheckNonRefundTradeTxn))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrQortalPartnerAddress3, addrCreatorAddress3, calcOffset(codeByteBuffer, labelCheckNonRefundTradeTxn))); - codeByteBuffer.put(OpCode.BNE_DAT.compile(addrQortalPartnerAddress4, addrCreatorAddress4, calcOffset(codeByteBuffer, labelCheckNonRefundTradeTxn))); + // Compare each part of message sender's address with AT creator's address. If they don't match, look for another transaction. + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender1, addrCreatorAddress1, calcOffset(codeByteBuffer, labelNotTradeNorCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender2, addrCreatorAddress2, calcOffset(codeByteBuffer, labelNotTradeNorCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender3, addrCreatorAddress3, calcOffset(codeByteBuffer, labelNotTradeNorCancelTxn))); + codeByteBuffer.put(OpCode.BNE_DAT.compile(addrMessageSender4, addrCreatorAddress4, calcOffset(codeByteBuffer, labelNotTradeNorCancelTxn))); // Partner address is AT creator's address, so cancel offer and finish. codeByteBuffer.put(OpCode.SET_VAL.compile(addrMode, Mode.CANCELLED.value)); // We're finished forever (finishing auto-refunds remaining balance to AT creator) codeByteBuffer.put(OpCode.FIN_IMD.compile()); + /* Not trade nor cancel message */ + labelNotTradeNorCancelTxn = codeByteBuffer.position(); + + // Loop to find another transaction + codeByteBuffer.put(OpCode.JMP_ADR.compile(labelTradeTxnLoop == null ? 0 : labelTradeTxnLoop)); + /* Possible switch-to-trade-mode message */ labelCheckNonRefundTradeTxn = codeByteBuffer.position(); - // Not offer-cancel scenario so check we received expected number of message bytes + // Check 'trade' message we received has expected number of message bytes codeByteBuffer.put(OpCode.EXT_FUN_RET.compile(QortalFunctionCode.GET_MESSAGE_LENGTH_FROM_TX_IN_A.value, addrMessageLength)); // If message length matches, branch to info extraction code codeByteBuffer.put(OpCode.BEQ_DAT.compile(addrMessageLength, addrExpectedTradeMessageLength, calcOffset(codeByteBuffer, labelTradeTxnExtract))); @@ -436,9 +442,13 @@ public class BTCACCT { /* Extracting info from 'trade' MESSAGE transaction */ labelTradeTxnExtract = codeByteBuffer.position(); - // Message is expected length, grab next 32 bytes - codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(QortalFunctionCode.PUT_PARTIAL_MESSAGE_FROM_TX_IN_A_INTO_B.value, addrTradeMessagePartnerBitcoinPKHOffset)); + // Extract message from transaction into B register + codeByteBuffer.put(OpCode.EXT_FUN.compile(FunctionCode.PUT_MESSAGE_FROM_TX_IN_A_INTO_B)); + // Save B register into data segment starting at addrQortalPartnerAddress1 (as pointed to by addrQortalPartnerAddressPointer) + codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.GET_B_IND, addrQortalPartnerAddressPointer)); + // Extract trade partner's Bitcoin public key hash (PKH) + codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(QortalFunctionCode.PUT_PARTIAL_MESSAGE_FROM_TX_IN_A_INTO_B.value, addrTradeMessagePartnerBitcoinPKHOffset)); // Extract partner's Bitcoin PKH (we only really use values from B1-B3) codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.GET_B_IND, addrPartnerBitcoinPKHPointer)); // Also extract lockTimeB diff --git a/src/test/java/org/qortal/test/btcacct/AtTests.java b/src/test/java/org/qortal/test/btcacct/AtTests.java index b271075c..fd187938 100644 --- a/src/test/java/org/qortal/test/btcacct/AtTests.java +++ b/src/test/java/org/qortal/test/btcacct/AtTests.java @@ -52,7 +52,6 @@ public class AtTests extends Common { public static final long redeemAmount = 80_40200000L; public static final long fundingAmount = 123_45600000L; public static final long bitcoinAmount = 864200L; - public static final byte[] bitcoinReceivePublicKeyHash = HashCode.fromString("00112233445566778899aabbccddeeff").asBytes(); private static final Random RANDOM = new Random(); @@ -63,9 +62,9 @@ public class AtTests extends Common { @Test public void testCompile() { - Account deployer = Common.getTestAccount(null, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(null); - byte[] creationBytes = BTCACCT.buildQortalAT(deployer.getAddress(), bitcoinPublicKeyHash, hashOfSecretB, redeemAmount, bitcoinAmount, tradeTimeout); + byte[] creationBytes = BTCACCT.buildQortalAT(tradeAccount.getAddress(), bitcoinPublicKeyHash, hashOfSecretB, redeemAmount, bitcoinAmount, tradeTimeout); System.out.println("CIYAM AT creation bytes: " + HashCode.fromBytes(creationBytes).toString()); } @@ -73,12 +72,14 @@ public class AtTests extends Common { public void testDeploy() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); long expectedBalance = deployersInitialBalance - fundingAmount - deployAtTransaction.getTransactionData().getFee(); long actualBalance = deployer.getConfirmedBalance(Asset.QORT); @@ -120,12 +121,14 @@ public class AtTests extends Common { public void testOfferCancel() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -140,14 +143,6 @@ public class AtTests extends Common { // AT should process 'cancel' message in next block BlockUtils.mintBlock(repository); - long expectedMinimumBalance = deployersPostDeploymentBalance; - long expectedMaximumBalance = deployersInitialBalance - deployAtFee - messageFee; - - long actualBalance = deployer.getConfirmedBalance(Asset.QORT); - - assertTrue(String.format("Deployer's balance %s should be above minimum %s", actualBalance, expectedMinimumBalance), actualBalance > expectedMinimumBalance); - assertTrue(String.format("Deployer's balance %s should be below maximum %s", actualBalance, expectedMaximumBalance), actualBalance < expectedMaximumBalance); - describeAt(repository, atAddress); // Check AT is finished @@ -158,9 +153,19 @@ public class AtTests extends Common { CrossChainTradeData tradeData = BTCACCT.populateTradeData(repository, atData); assertEquals(BTCACCT.Mode.CANCELLED, tradeData.mode); + // Check balances + long expectedMinimumBalance = deployersPostDeploymentBalance; + long expectedMaximumBalance = deployersInitialBalance - deployAtFee - messageFee; + + long actualBalance = deployer.getConfirmedBalance(Asset.QORT); + + assertTrue(String.format("Deployer's balance %s should be above minimum %s", actualBalance, expectedMinimumBalance), actualBalance > expectedMinimumBalance); + assertTrue(String.format("Deployer's balance %s should be below maximum %s", actualBalance, expectedMaximumBalance), actualBalance < expectedMaximumBalance); + // Test orphaning BlockUtils.orphanLastBlock(repository); + // Check balances long expectedBalance = deployersPostDeploymentBalance - messageFee; actualBalance = deployer.getConfirmedBalance(Asset.QORT); @@ -173,12 +178,14 @@ public class AtTests extends Common { public void testOfferCancelInvalidLength() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -192,18 +199,18 @@ public class AtTests extends Common { long messageFee = messageTransaction.getTransactionData().getFee(); // AT should process 'cancel' message in next block - // As message is too short, it will be padded to 32bytes and (probably) contain incorrect sender to be valid cancel + // As message is too short, it will be padded to 32bytes but cancel code doesn't care about message content, so should be ok BlockUtils.mintBlock(repository); describeAt(repository, atAddress); - // Check AT is NOT finished + // Check AT is finished ATData atData = repository.getATRepository().fromATAddress(atAddress); - assertFalse(atData.getIsFinished()); + assertTrue(atData.getIsFinished()); - // AT should still be in OFFERING mode + // AT should be in CANCELLED mode CrossChainTradeData tradeData = BTCACCT.populateTradeData(repository, atData); - assertEquals(BTCACCT.Mode.OFFERING, tradeData.mode); + assertEquals(BTCACCT.Mode.CANCELLED, tradeData.mode); } } @@ -212,12 +219,14 @@ public class AtTests extends Common { public void testTradingInfoProcessing() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -227,14 +236,13 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); Block postDeploymentBlock = BlockUtils.mintBlock(repository); int postDeploymentBlockHeight = postDeploymentBlock.getBlockData().getHeight(); long deployAtFee = deployAtTransaction.getTransactionData().getFee(); - long messageFee = messageTransaction.getTransactionData().getFee(); - long deployersPostDeploymentBalance = deployersInitialBalance - fundingAmount - deployAtFee - messageFee; + long deployersPostDeploymentBalance = deployersInitialBalance - fundingAmount - deployAtFee; describeAt(repository, atAddress); @@ -256,6 +264,7 @@ public class AtTests extends Common { // Test orphaning BlockUtils.orphanToBlock(repository, postDeploymentBlockHeight); + // Check balances long expectedBalance = deployersPostDeploymentBalance; long actualBalance = deployer.getConfirmedBalance(Asset.QORT); @@ -269,13 +278,16 @@ public class AtTests extends Common { public void testIncorrectTradeSender() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); + PrivateKeyAccount bystander = Common.getTestAccount(repository, "bob"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -309,12 +321,14 @@ public class AtTests extends Common { public void testAutomaticTradeRefund() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -324,14 +338,14 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); Block postDeploymentBlock = BlockUtils.mintBlock(repository); int postDeploymentBlockHeight = postDeploymentBlock.getBlockData().getHeight(); + // Check refund long deployAtFee = deployAtTransaction.getTransactionData().getFee(); - long messageFee = messageTransaction.getTransactionData().getFee(); - long deployersPostDeploymentBalance = deployersInitialBalance - fundingAmount - deployAtFee - messageFee; + long deployersPostDeploymentBalance = deployersInitialBalance - fundingAmount - deployAtFee; checkTradeRefund(repository, deployer, deployersInitialBalance, deployAtFee); @@ -348,6 +362,7 @@ public class AtTests extends Common { // Test orphaning BlockUtils.orphanToBlock(repository, postDeploymentBlockHeight); + // Check balances long expectedBalance = deployersPostDeploymentBalance; long actualBalance = deployer.getConfirmedBalance(Asset.QORT); @@ -360,12 +375,14 @@ public class AtTests extends Common { public void testCorrectSecretsCorrectSender() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -375,7 +392,7 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); // Give AT time to process message BlockUtils.mintBlock(repository); @@ -398,6 +415,7 @@ public class AtTests extends Common { CrossChainTradeData tradeData = BTCACCT.populateTradeData(repository, atData); assertEquals(BTCACCT.Mode.REDEEMED, tradeData.mode); + // Check balances long expectedBalance = partnersInitialBalance - messageTransaction.getTransactionData().getFee() + redeemAmount; long actualBalance = partner.getConfirmedBalance(Asset.QORT); @@ -406,6 +424,7 @@ public class AtTests extends Common { // Orphan redeem BlockUtils.orphanLastBlock(repository); + // Check balances expectedBalance = partnersInitialBalance - messageTransaction.getTransactionData().getFee(); actualBalance = partner.getConfirmedBalance(Asset.QORT); @@ -423,13 +442,16 @@ public class AtTests extends Common { public void testCorrectSecretsIncorrectSender() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); + PrivateKeyAccount bystander = Common.getTestAccount(repository, "bob"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); long deployAtFee = deployAtTransaction.getTransactionData().getFee(); Account at = deployAtTransaction.getATAccount(); @@ -441,7 +463,7 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); // Give AT time to process message BlockUtils.mintBlock(repository); @@ -464,11 +486,13 @@ public class AtTests extends Common { CrossChainTradeData tradeData = BTCACCT.populateTradeData(repository, atData); assertEquals(BTCACCT.Mode.TRADING, tradeData.mode); + // Check balances long expectedBalance = partnersInitialBalance; long actualBalance = partner.getConfirmedBalance(Asset.QORT); assertEquals("Partner's balance incorrect", expectedBalance, actualBalance); + // Check eventual refund checkTradeRefund(repository, deployer, deployersInitialBalance, deployAtFee); } } @@ -478,12 +502,14 @@ public class AtTests extends Common { public void testIncorrectSecretsCorrectSender() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); long deployAtFee = deployAtTransaction.getTransactionData().getFee(); Account at = deployAtTransaction.getATAccount(); @@ -495,7 +521,7 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); // Give AT time to process message BlockUtils.mintBlock(repository); @@ -542,11 +568,13 @@ public class AtTests extends Common { tradeData = BTCACCT.populateTradeData(repository, atData); assertEquals(BTCACCT.Mode.TRADING, tradeData.mode); + // Check balances expectedBalance = partnersInitialBalance - messageTransaction.getTransactionData().getFee() * 2; actualBalance = partner.getConfirmedBalance(Asset.QORT); assertEquals("Partner's balance incorrect", expectedBalance, actualBalance); + // Check eventual refund checkTradeRefund(repository, deployer, deployersInitialBalance, deployAtFee); } } @@ -556,12 +584,14 @@ public class AtTests extends Common { public void testCorrectSecretsCorrectSenderInvalidMessageLength() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); Account at = deployAtTransaction.getATAccount(); String atAddress = at.getAddress(); @@ -571,7 +601,7 @@ public class AtTests extends Common { // Send trade info to AT byte[] messageData = BTCACCT.buildTradeMessage(partner.getAddress(), bitcoinPublicKeyHash, hashOfSecretA, lockTimeA, lockTimeB); - MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress); + MessageTransaction messageTransaction = sendMessage(repository, tradeAccount, messageData, atAddress); // Give AT time to process message BlockUtils.mintBlock(repository); @@ -601,12 +631,14 @@ public class AtTests extends Common { public void testDescribeDeployed() throws DataException { try (final Repository repository = RepositoryManager.getRepository()) { PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = createTradeAccount(repository); + PrivateKeyAccount partner = Common.getTestAccount(repository, "dilbert"); long deployersInitialBalance = deployer.getConfirmedBalance(Asset.QORT); long partnersInitialBalance = partner.getConfirmedBalance(Asset.QORT); - DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer); + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); List executableAts = repository.getATRepository().getAllExecutableATs(); @@ -634,8 +666,8 @@ public class AtTests extends Common { return (int) (messageTimestamp / 1000L + tradeTimeout * 60); } - private DeployAtTransaction doDeploy(Repository repository, PrivateKeyAccount deployer) throws DataException { - byte[] creationBytes = BTCACCT.buildQortalAT(deployer.getAddress(), bitcoinPublicKeyHash, hashOfSecretB, redeemAmount, bitcoinAmount, tradeTimeout); + private DeployAtTransaction doDeploy(Repository repository, PrivateKeyAccount deployer, String tradeAddress) throws DataException { + byte[] creationBytes = BTCACCT.buildQortalAT(tradeAddress, bitcoinPublicKeyHash, hashOfSecretB, redeemAmount, bitcoinAmount, tradeTimeout); long txTimestamp = System.currentTimeMillis(); byte[] lastReference = deployer.getLastReference(); @@ -752,4 +784,9 @@ public class AtTests extends Common { } } + private PrivateKeyAccount createTradeAccount(Repository repository) { + // We actually use a known test account with funds to avoid PoW compute + return Common.getTestAccount(repository, "alice"); + } + }