diff --git a/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java b/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java index 7f31961519c..76660fbaa1a 100755 --- a/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java +++ b/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java @@ -3,13 +3,13 @@ import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.util.Arrays; import lombok.extern.slf4j.Slf4j; import org.tron.common.utils.StringUtil; import org.tron.core.Wallet; import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.ExchangeCapsule; import org.tron.core.capsule.TransactionResultCapsule; -import org.tron.core.config.Parameter.ChainParameters; import org.tron.core.db.Manager; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -39,13 +39,15 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException long newBalance = accountCapsule.getBalance() - calcFee(); - if (firstTokenID == "_".getBytes()) { + accountCapsule.setBalance(newBalance); + + if (Arrays.equals(firstTokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance - firstTokenBalance); } else { accountCapsule.reduceAssetAmount(firstTokenID, firstTokenBalance); } - if (secondTokenID == "_".getBytes()) { + if (Arrays.equals(secondTokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance - secondTokenBalance); } else { accountCapsule.reduceAssetAmount(secondTokenID, secondTokenBalance); @@ -119,7 +121,7 @@ public boolean validate() throws ContractValidateException { long firstTokenBalance = contract.getFirstTokenBalance(); long secondTokenBalance = contract.getSecondTokenBalance(); - if (firstTokenID == secondTokenID) { + if (Arrays.equals(firstTokenID, secondTokenID)) { throw new ContractValidateException("cannot exchange same tokens"); } @@ -132,7 +134,7 @@ public boolean validate() throws ContractValidateException { throw new ContractValidateException("token balance must less than " + balanceLimit); } - if (firstTokenID == "_".getBytes()) { + if (Arrays.equals(firstTokenID, "_".getBytes())) { if (accountCapsule.getBalance() < (firstTokenBalance + calcFee())) { throw new ContractValidateException("balance is not enough"); } @@ -142,7 +144,7 @@ public boolean validate() throws ContractValidateException { } } - if (secondTokenID == "_".getBytes()) { + if (Arrays.equals(secondTokenID, "_".getBytes())) { if (accountCapsule.getBalance() < (secondTokenBalance + calcFee())) { throw new ContractValidateException("balance is not enough"); } @@ -166,8 +168,4 @@ public long calcFee() { return dbManager.getDynamicPropertiesStore().getExchangeCreateFee(); } - private boolean validKey(long idx) { - return idx >= 0 && idx < ChainParameters.values().length; - } - } diff --git a/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java b/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java index 24b97b11e3b..50fe7459b17 100755 --- a/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java +++ b/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java @@ -3,6 +3,7 @@ import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.math.BigInteger; import java.util.Arrays; import lombok.extern.slf4j.Slf4j; import org.tron.common.utils.ByteArray; @@ -11,7 +12,6 @@ import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.ExchangeCapsule; import org.tron.core.capsule.TransactionResultCapsule; -import org.tron.core.config.Parameter.ChainParameters; import org.tron.core.db.Manager; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -65,13 +65,13 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException long newBalance = accountCapsule.getBalance() - calcFee(); - if (tokenID == "_".getBytes()) { + if (Arrays.equals(tokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance - tokenQuant); } else { accountCapsule.reduceAssetAmount(tokenID, tokenQuant); } - if (anotherTokenID == "_".getBytes()) { + if (Arrays.equals(anotherTokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance - anotherTokenQuant); } else { accountCapsule.reduceAssetAmount(anotherTokenID, anotherTokenQuant); @@ -164,26 +164,33 @@ public boolean validate() throws ContractValidateException { } if (tokenQuant <= 0) { - throw new ContractValidateException("injected token balance must greater than zero"); + throw new ContractValidateException("injected token quant must greater than zero"); } + BigInteger bigFirstTokenBalance = new BigInteger(String.valueOf(firstTokenBalance)); + BigInteger bigSecondTokenBalance = new BigInteger(String.valueOf(secondTokenBalance)); + BigInteger bigTokenQuant = new BigInteger(String.valueOf(tokenQuant)); long newTokenBalance, newAnotherTokenBalance; if (Arrays.equals(tokenID, firstTokenID)) { anotherTokenID = secondTokenID; - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); + anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant) + .divide(bigFirstTokenBalance).longValueExact(); newTokenBalance = firstTokenBalance + tokenQuant; newAnotherTokenBalance = secondTokenBalance + anotherTokenQuant; } else { anotherTokenID = firstTokenID; - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); + anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant) + .divide(bigSecondTokenBalance).longValueExact(); newTokenBalance = secondTokenBalance + tokenQuant; newAnotherTokenBalance = firstTokenBalance + anotherTokenQuant; } if (anotherTokenQuant <= 0) { - throw new ContractValidateException(" The calculated Token Quant must be larger than 0"); + throw new ContractValidateException("the calculated token quant must be greater than 0"); } long balanceLimit = dbManager.getDynamicPropertiesStore().getExchangeBalanceLimit(); @@ -191,7 +198,7 @@ public boolean validate() throws ContractValidateException { throw new ContractValidateException("token balance must less than " + balanceLimit); } - if (tokenID == "_".getBytes()) { + if (Arrays.equals(tokenID, "_".getBytes())) { if (accountCapsule.getBalance() < (tokenQuant + calcFee())) { throw new ContractValidateException("balance is not enough"); } @@ -201,7 +208,7 @@ public boolean validate() throws ContractValidateException { } } - if (anotherTokenID == "_".getBytes()) { + if (Arrays.equals(anotherTokenID, "_".getBytes())) { if (accountCapsule.getBalance() < (anotherTokenQuant + calcFee())) { throw new ContractValidateException("balance is not enough"); } @@ -225,8 +232,4 @@ public long calcFee() { return 0; } - private boolean validKey(long idx) { - return idx >= 0 && idx < ChainParameters.values().length; - } - } diff --git a/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java b/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java index 3361ca973d3..481fae4dc0d 100755 --- a/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java +++ b/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java @@ -11,7 +11,6 @@ import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.ExchangeCapsule; import org.tron.core.capsule.TransactionResultCapsule; -import org.tron.core.config.Parameter.ChainParameters; import org.tron.core.db.Manager; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -55,13 +54,13 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException long newBalance = accountCapsule.getBalance() - calcFee(); - if (tokenID == "_".getBytes()) { + if (Arrays.equals(tokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance - tokenQuant); } else { accountCapsule.reduceAssetAmount(tokenID, tokenQuant); } - if (anotherTokenID == "_".getBytes()) { + if (Arrays.equals(anotherTokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance + anotherTokenQuant); } else { accountCapsule.addAssetAmount(anotherTokenID, anotherTokenQuant); @@ -145,14 +144,20 @@ public boolean validate() throws ContractValidateException { throw new ContractValidateException("transaction token balance must greater than zero"); } + if (firstTokenBalance == 0 || secondTokenBalance == 0) { + throw new ContractValidateException("Token balance in exchange is equal with 0," + + "the exchange has been closed"); + } + long balanceLimit = dbManager.getDynamicPropertiesStore().getExchangeBalanceLimit(); - long tokenBalance = (tokenID == firstTokenID ? firstTokenBalance : secondTokenBalance); + long tokenBalance = (Arrays.equals(tokenID, firstTokenID) ? firstTokenBalance + : secondTokenBalance); tokenBalance += tokenQuant; if (tokenBalance > balanceLimit) { throw new ContractValidateException("token balance must less than " + balanceLimit); } - if (tokenID == "_".getBytes()) { + if (Arrays.equals(tokenID, "_".getBytes())) { if (accountCapsule.getBalance() < (tokenQuant + calcFee())) { throw new ContractValidateException("balance is not enough"); } @@ -181,8 +186,4 @@ public long calcFee() { return 0; } - private boolean validKey(long idx) { - return idx >= 0 && idx < ChainParameters.values().length; - } - } diff --git a/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java b/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java index 301931445cd..dfdf42cdb55 100755 --- a/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java +++ b/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java @@ -3,6 +3,7 @@ import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import java.math.BigInteger; import java.util.Arrays; import lombok.extern.slf4j.Slf4j; import org.tron.common.utils.ByteArray; @@ -11,7 +12,6 @@ import org.tron.core.capsule.AccountCapsule; import org.tron.core.capsule.ExchangeCapsule; import org.tron.core.capsule.TransactionResultCapsule; -import org.tron.core.config.Parameter.ChainParameters; import org.tron.core.db.Manager; import org.tron.core.exception.ContractExeException; import org.tron.core.exception.ContractValidateException; @@ -49,29 +49,36 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException byte[] anotherTokenID; long anotherTokenQuant; + BigInteger bigFirstTokenBalance = new BigInteger(String.valueOf(firstTokenBalance)); + BigInteger bigSecondTokenBalance = new BigInteger(String.valueOf(secondTokenBalance)); + BigInteger bigTokenQuant = new BigInteger(String.valueOf(tokenQuant)); if (Arrays.equals(tokenID, firstTokenID)) { anotherTokenID = secondTokenID; - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); + anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant) + .divide(bigFirstTokenBalance).longValueExact(); exchangeCapsule.setBalance(firstTokenBalance - tokenQuant, secondTokenBalance - anotherTokenQuant); } else { anotherTokenID = firstTokenID; - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); + anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant) + .divide(bigSecondTokenBalance).longValueExact(); exchangeCapsule.setBalance(firstTokenBalance - anotherTokenQuant, secondTokenBalance - tokenQuant); } long newBalance = accountCapsule.getBalance() - calcFee(); - if (tokenID == "_".getBytes()) { + if (Arrays.equals(tokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance + tokenQuant); } else { accountCapsule.addAssetAmount(tokenID, tokenQuant); } - if (anotherTokenID == "_".getBytes()) { + if (Arrays.equals(anotherTokenID, "_".getBytes())) { accountCapsule.setBalance(newBalance + anotherTokenQuant); } else { accountCapsule.addAssetAmount(anotherTokenID, anotherTokenQuant); @@ -158,22 +165,30 @@ public boolean validate() throws ContractValidateException { } if (tokenQuant <= 0) { - throw new ContractValidateException("withdraw token balance must greater than zero"); + throw new ContractValidateException("withdraw token quant must greater than zero"); } if (firstTokenBalance == 0 || secondTokenBalance == 0) { - throw new ContractValidateException("Token balance in exchange is equal with 0,the exchange has been closed"); + throw new ContractValidateException("Token balance in exchange is equal with 0," + + "the exchange has been closed"); } + BigInteger bigFirstTokenBalance = new BigInteger(String.valueOf(firstTokenBalance)); + BigInteger bigSecondTokenBalance = new BigInteger(String.valueOf(secondTokenBalance)); + BigInteger bigTokenQuant = new BigInteger(String.valueOf(tokenQuant)); if (Arrays.equals(tokenID, firstTokenID)) { - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance); + anotherTokenQuant = bigSecondTokenBalance.multiply(bigTokenQuant) + .divide(bigFirstTokenBalance).longValueExact(); if (firstTokenBalance < tokenQuant || secondTokenBalance < anotherTokenQuant) { throw new ContractValidateException("exchange balance is not enough"); } } else { - anotherTokenQuant = Math - .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); +// anotherTokenQuant = Math +// .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance); + anotherTokenQuant = bigFirstTokenBalance.multiply(bigTokenQuant) + .divide(bigSecondTokenBalance).longValueExact(); if (secondTokenBalance < tokenQuant || firstTokenBalance < anotherTokenQuant) { throw new ContractValidateException("exchange balance is not enough"); } @@ -193,8 +208,4 @@ public long calcFee() { return 0; } - private boolean validKey(long idx) { - return idx >= 0 && idx < ChainParameters.values().length; - } - } diff --git a/src/test/java/org/tron/core/actuator/ExchangeCreateActuatorTest.java b/src/test/java/org/tron/core/actuator/ExchangeCreateActuatorTest.java new file mode 100644 index 00000000000..f4284ca91e4 --- /dev/null +++ b/src/test/java/org/tron/core/actuator/ExchangeCreateActuatorTest.java @@ -0,0 +1,573 @@ +package org.tron.core.actuator; + +import static org.testng.Assert.fail; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.Wallet; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.capsule.ExchangeCapsule; +import org.tron.core.capsule.TransactionResultCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.Manager; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ItemNotFoundException; +import org.tron.protos.Contract; +import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Transaction.Result.code; + +@Slf4j + +public class ExchangeCreateActuatorTest { + + private static AnnotationConfigApplicationContext context; + private static Manager dbManager; + private static final String dbPath = "output_ExchangeCreate_test"; + private static final String ACCOUNT_NAME_FIRST = "ownerF"; + private static final String OWNER_ADDRESS_FIRST; + private static final String ACCOUNT_NAME_SECOND = "ownerS"; + private static final String OWNER_ADDRESS_SECOND; + private static final String URL = "https://tron.network"; + private static final String OWNER_ADDRESS_INVALID = "aaaa"; + private static final String OWNER_ADDRESS_NOACCOUNT; + private static final String OWNER_ADDRESS_BALANCENOTSUFFIENT; + + static { + Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF); + context = new AnnotationConfigApplicationContext(DefaultConfig.class); + OWNER_ADDRESS_FIRST = + Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc"; + OWNER_ADDRESS_SECOND = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc"; + OWNER_ADDRESS_NOACCOUNT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1aed"; + OWNER_ADDRESS_BALANCENOTSUFFIENT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e06d4271a1ced"; + } + + /** + * Init data. + */ + @BeforeClass + public static void init() { + dbManager = context.getBean(Manager.class); + } + + /** + * Release resources. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + context.destroy(); + } + + /** + * create temp Capsule test need. + */ + @Before + public void initTest() { + AccountCapsule ownerAccountFirstCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_FIRST), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + AccountType.Normal, + 300_000_000L); + AccountCapsule ownerAccountSecondCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_SECOND), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_SECOND)), + AccountType.Normal, + 200_000_000_000L); + + dbManager.getAccountStore() + .put(ownerAccountFirstCapsule.getAddress().toByteArray(), ownerAccountFirstCapsule); + dbManager.getAccountStore() + .put(ownerAccountSecondCapsule.getAddress().toByteArray(), ownerAccountSecondCapsule); + + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1000000); + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(10); + dbManager.getDynamicPropertiesStore().saveNextMaintenanceTime(2000000); + dbManager.getDynamicPropertiesStore().saveLatestExchangeNum(0); + + } + + private Any getContract(String address, String firstTokenId, long firstTokenBalance, + String secondTokenId, long secondTokenBalance) { + return Any.pack( + Contract.ExchangeCreateContract.newBuilder() + .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(address))) + .setFirstTokenId(ByteString.copyFrom(firstTokenId.getBytes())) + .setFirstTokenBalance(firstTokenBalance) + .setSecondTokenId(ByteString.copyFrom(secondTokenId.getBytes())) + .setSecondTokenBalance(secondTokenBalance) + .build()); + } + + /** + * first createExchange,result is success. + */ + @Test + public void successExchangeCreate() { + String firstTokenId = "abc"; + long firstTokenBalance = 100000000L; + String secondTokenId = "def"; + long secondTokenBalance = 100000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenBalance); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + long id = 1; + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(id)); + Assert.assertNotNull(exchangeCapsule); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), id); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(id, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); +// Assert.assertEquals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId()); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenBalance, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(secondTokenBalance, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L - 1024_000000L, accountCapsule.getBalance()); + Assert.assertEquals(0L, assetMap.get(firstTokenId).longValue()); + Assert.assertEquals(0L, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * second create Exchange, result is success. + */ + @Test + public void successExchangeCreate2() { + String firstTokenId = "_"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "abc"; + long secondTokenBalance = 100_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.setBalance(200_000_000_000000L); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), 200_000_000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + long id = 1; + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(id)); + Assert.assertNotNull(exchangeCapsule); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), id); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(id, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); +// Assert.assertEquals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId()); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenBalance, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(secondTokenBalance, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(200_000_000_000000L - 1024_000000L - firstTokenBalance, + accountCapsule.getBalance()); + Assert.assertEquals(100_000_000L, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * use Invalid Address, result is failed, exception is "Invalid address". + */ + @Test + public void invalidAddress() { + String firstTokenId = "_"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "abc"; + long secondTokenBalance = 100_000_000L; + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_INVALID, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Invalid address"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Invalid address", e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * use AccountStore not exists, result is failed, exception is "account not exists". + */ + @Test + public void noAccount() { + String firstTokenId = "_"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "abc"; + long secondTokenBalance = 100_000_000L; + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_NOACCOUNT, firstTokenId, firstTokenBalance, secondTokenId, + secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + + try { + actuator.validate(); + actuator.execute(ret); + fail("account[+OWNER_ADDRESS_NOACCOUNT+] not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[" + OWNER_ADDRESS_NOACCOUNT + "] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * No enough balance + */ + @Test + public void noEnoughBalance() { + String firstTokenId = "abc"; + long firstTokenBalance = 100000000L; + String secondTokenId = "def"; + long secondTokenBalance = 100000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenBalance); + accountCapsule.setBalance(1000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("No enough balance for exchange create fee!", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * exchange same tokens + */ + @Test + public void sameTokens() { + String firstTokenId = "abc"; + long firstTokenBalance = 100000000L; + String secondTokenId = "abc"; + long secondTokenBalance = 100000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenBalance); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("cannot exchange same tokens", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token balance less than zero + */ + @Test + public void lessToken() { + String firstTokenId = "abc"; + long firstTokenBalance = 0L; + String secondTokenId = "def"; + long secondTokenBalance = 0L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), 1000); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), 1000); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance must greater than zero", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token balance must less than balanceLimit + */ + @Test + public void moreThanBalanceLimit() { + String firstTokenId = "abc"; + long firstTokenBalance = 1_000_000_000_000_001L; + String secondTokenId = "def"; + long secondTokenBalance = 100000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenBalance); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance must less than 1000000000000000", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * balance is not enough + */ + @Test + public void balanceNotEnough() { + String firstTokenId = "_"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "abc"; + long secondTokenBalance = 100_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.setBalance(firstTokenBalance + 1000L); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), 200_000_000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * first token balance is not enough + */ + @Test + public void firstTokenBalanceNotEnough() { + String firstTokenId = "abc"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "def"; + long secondTokenBalance = 100_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance - 1000L); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), 200_000_000L); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("first token balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * balance is not enough + */ + @Test + public void balanceNotEnough2() { + String firstTokenId = "abc"; + long firstTokenBalance = 100_000_000L; + String secondTokenId = "_"; + long secondTokenBalance = 100_000_000_000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.setBalance(secondTokenBalance + 1000L); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), 200_000_000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * first token balance is not enough + */ + @Test + public void secondTokenBalanceNotEnough() { + String firstTokenId = "abc"; + long firstTokenBalance = 100_000_000_000000L; + String secondTokenId = "def"; + long secondTokenBalance = 100_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenBalance); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), 90_000_000L); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeCreateActuator actuator = new ExchangeCreateActuator(getContract( + OWNER_ADDRESS_FIRST, firstTokenId, firstTokenBalance, secondTokenId, secondTokenBalance), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + Assert.assertEquals(dbManager.getDynamicPropertiesStore().getLatestExchangeNum(), 0); + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("second token balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/tron/core/actuator/ExchangeInjectActuatorTest.java b/src/test/java/org/tron/core/actuator/ExchangeInjectActuatorTest.java new file mode 100644 index 00000000000..5f852cb8d04 --- /dev/null +++ b/src/test/java/org/tron/core/actuator/ExchangeInjectActuatorTest.java @@ -0,0 +1,704 @@ +package org.tron.core.actuator; + +import static org.testng.Assert.fail; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.Wallet; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.capsule.ExchangeCapsule; +import org.tron.core.capsule.TransactionResultCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.Manager; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ItemNotFoundException; +import org.tron.protos.Contract; +import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Transaction.Result.code; + +@Slf4j + +public class ExchangeInjectActuatorTest { + + private static AnnotationConfigApplicationContext context; + private static Manager dbManager; + private static final String dbPath = "output_ExchangeInject_test"; + private static final String ACCOUNT_NAME_FIRST = "ownerF"; + private static final String OWNER_ADDRESS_FIRST; + private static final String ACCOUNT_NAME_SECOND = "ownerS"; + private static final String OWNER_ADDRESS_SECOND; + private static final String URL = "https://tron.network"; + private static final String OWNER_ADDRESS_INVALID = "aaaa"; + private static final String OWNER_ADDRESS_NOACCOUNT; + private static final String OWNER_ADDRESS_BALANCENOTSUFFIENT; + + static { + Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF); + context = new AnnotationConfigApplicationContext(DefaultConfig.class); + OWNER_ADDRESS_FIRST = + Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc"; + OWNER_ADDRESS_SECOND = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc"; + OWNER_ADDRESS_NOACCOUNT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1aed"; + OWNER_ADDRESS_BALANCENOTSUFFIENT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e06d4271a1ced"; + } + + /** + * Init data. + */ + @BeforeClass + public static void init() { + dbManager = context.getBean(Manager.class); + } + + /** + * Release resources. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + context.destroy(); + } + + /** + * create temp Capsule test need. + */ + @Before + public void initTest() { + AccountCapsule ownerAccountFirstCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_FIRST), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + AccountType.Normal, + 300_000_000L); + AccountCapsule ownerAccountSecondCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_SECOND), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_SECOND)), + AccountType.Normal, + 200_000_000_000L); + ExchangeCapsule exchangeCapsule = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 1, + 1000000, + "abc".getBytes(), + "def".getBytes()); + exchangeCapsule.setBalance(100000000L, 200000000L); + ExchangeCapsule exchangeCapsule2 = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 2, + 1000000, + "_".getBytes(), + "def".getBytes()); + exchangeCapsule2.setBalance(1_000_000_000000L, 10_000_000L); + + dbManager.getAccountStore() + .put(ownerAccountFirstCapsule.getAddress().toByteArray(), ownerAccountFirstCapsule); + dbManager.getAccountStore() + .put(ownerAccountSecondCapsule.getAddress().toByteArray(), ownerAccountSecondCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule.createDbKey(), exchangeCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule2.createDbKey(), exchangeCapsule2); + + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1000000); + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(10); + dbManager.getDynamicPropertiesStore().saveNextMaintenanceTime(2000000); + } + + private Any getContract(String address, long exchangeId, String tokenId, long quant) { + return Any.pack( + Contract.ExchangeInjectContract.newBuilder() + .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(address))) + .setExchangeId(exchangeId) + .setTokenId(ByteString.copyFrom(tokenId.getBytes())) + .setQuant(quant) + .build()); + } + + /** + * first inject Exchange,result is success. + */ + @Test + public void successExchangeInject() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + long id = 1; + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(id)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(id, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(300000000L, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(600000000L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(0L, assetMap.get(firstTokenId).longValue()); + Assert.assertEquals(0L, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * second inject Exchange,result is success. + */ + @Test + public void successExchangeInject2() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 100_000_000000L; + String secondTokenId = "def"; + long secondTokenQuant = 4_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(1_100_000_000000L, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(11_000_000L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(0L, accountCapsule.getBalance()); + Assert.assertEquals(3_000_000L, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * use Invalid Address, result is failed, exception is "Invalid address". + */ + @Test + public void invalidAddress() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_INVALID, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Invalid address"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Invalid address", e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * use AccountStore not exists, result is failed, exception is "account not exists". + */ + @Test + public void noAccount() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_NOACCOUNT, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("account[+OWNER_ADDRESS_NOACCOUNT+] not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[" + OWNER_ADDRESS_NOACCOUNT + "] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Exchange not exists + */ + @Test + public void exchangeNotExist() { + long exchangeId = 3; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Exchange not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Exchange[3] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * account[" + readableOwnerAddress + "] is not creator + */ + @Test + public void accountIsNotCreator() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[a0548794500882809695a8a687866e76d4271a1abc]" + + " is not creator", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token is not in exchange + */ + @Test + public void tokenIsNotInExchange() { + long exchangeId = 1; + String firstTokenId = "_"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token is not in exchange", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Token balance in exchange is equal with 0, the exchange has been closed" + */ + @Test + public void tokenBalanceZero() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + exchangeCapsule.setBalance(0, 0); + dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule); + + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Token balance in exchange is equal with 0," + + "the exchange has been closed", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * injected token quant must greater than zero + */ + @Test + public void tokenQuantLessThanZero() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = -1L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), 1000L); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("injected token quant must greater than zero", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * "the calculated token quant must be greater than 0" + */ + @Test + public void calculatedTokenQuantLessThanZero() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 100L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("the calculated token quant must be greater than 0", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token balance must less than balanceLimit + */ + @Test + public void tokenBalanceGreaterThanBalanceLimit() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 1_000_000_000_000_001L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance must less than 1000000000000000", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * balance is not enough + */ + @Test + public void balanceNotEnough() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 100_000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant - 1); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * first token balance is not enough + */ + @Test + public void tokenBalanceNotEnough() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant - 1); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * balance is not enough2 + */ + @Test + public void balanceNotEnough2() { + long exchangeId = 2; + String secondTokenId = "def"; + long secondTokenQuant = 4000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(399_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, secondTokenId, secondTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * first token balance is not enough + */ + @Test + public void anotherTokenBalanceNotEnough() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant - 1); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeInjectActuator actuator = new ExchangeInjectActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, secondTokenId, secondTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("another token balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + +} \ No newline at end of file diff --git a/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java b/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java new file mode 100644 index 00000000000..edea2de6f39 --- /dev/null +++ b/src/test/java/org/tron/core/actuator/ExchangeTransactionActuatorTest.java @@ -0,0 +1,599 @@ +package org.tron.core.actuator; + +import static org.testng.Assert.fail; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.Wallet; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.capsule.ExchangeCapsule; +import org.tron.core.capsule.TransactionResultCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.Manager; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ItemNotFoundException; +import org.tron.protos.Contract; +import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Transaction.Result.code; + +@Slf4j + +public class ExchangeTransactionActuatorTest { + + private static AnnotationConfigApplicationContext context; + private static Manager dbManager; + private static final String dbPath = "output_ExchangeTransaction_test"; + private static final String ACCOUNT_NAME_FIRST = "ownerF"; + private static final String OWNER_ADDRESS_FIRST; + private static final String ACCOUNT_NAME_SECOND = "ownerS"; + private static final String OWNER_ADDRESS_SECOND; + private static final String URL = "https://tron.network"; + private static final String OWNER_ADDRESS_INVALID = "aaaa"; + private static final String OWNER_ADDRESS_NOACCOUNT; + private static final String OWNER_ADDRESS_BALANCENOTSUFFIENT; + + static { + Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF); + context = new AnnotationConfigApplicationContext(DefaultConfig.class); + OWNER_ADDRESS_FIRST = + Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc"; + OWNER_ADDRESS_SECOND = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc"; + OWNER_ADDRESS_NOACCOUNT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1aed"; + OWNER_ADDRESS_BALANCENOTSUFFIENT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e06d4271a1ced"; + } + + /** + * Init data. + */ + @BeforeClass + public static void init() { + dbManager = context.getBean(Manager.class); + } + + /** + * Release resources. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + context.destroy(); + } + + /** + * create temp Capsule test need. + */ + @Before + public void initTest() { + AccountCapsule ownerAccountFirstCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_FIRST), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + AccountType.Normal, + 10000_000_000L); + AccountCapsule ownerAccountSecondCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_SECOND), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_SECOND)), + AccountType.Normal, + 20000_000_000L); + ExchangeCapsule exchangeCapsule = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 1, + 1000000, + "_".getBytes(), + "abc".getBytes()); + exchangeCapsule.setBalance(1_000_000_000_000L, 10_000_000L); // 1M TRX == 10M abc + ExchangeCapsule exchangeCapsule2 = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 2, + 1000000, + "abc".getBytes(), + "def".getBytes()); + exchangeCapsule2.setBalance(100000000L, 200000000L); + + dbManager.getAccountStore() + .put(ownerAccountFirstCapsule.getAddress().toByteArray(), ownerAccountFirstCapsule); + dbManager.getAccountStore() + .put(ownerAccountSecondCapsule.getAddress().toByteArray(), ownerAccountSecondCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule.createDbKey(), exchangeCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule2.createDbKey(), exchangeCapsule2); + + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1000000); + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(10); + dbManager.getDynamicPropertiesStore().saveNextMaintenanceTime(2000000); + } + + private Any getContract(String address, long exchangeId, String tokenId, long quant) { + return Any.pack( + Contract.ExchangeTransactionContract.newBuilder() + .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(address))) + .setExchangeId(exchangeId) + .setTokenId(ByteString.copyFrom(tokenId.getBytes())) + .setQuant(quant) + .build()); + } + + /** + * first transaction Exchange,result is success. + */ + @Test + public void successExchangeTransaction() { + long exchangeId = 1; + String tokenId = "_"; + long quant = 100_000_000L; // use 100 TRX to buy abc + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get("def")); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + long firstTokenBalance = exchangeCapsule.getFirstTokenBalance(); + long secondTokenBalance = exchangeCapsule.getSecondTokenBalance(); + + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(tokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(1_000_000_000_000L, firstTokenBalance); + Assert.assertEquals("abc", ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(10_000_000L, secondTokenBalance); + + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(tokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(tokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenBalance + quant, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals("abc", ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(9999001L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L - quant, accountCapsule.getBalance()); + Assert.assertEquals(999L, assetMap.get("abc").longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * second transaction Exchange,result is success. + */ + @Test + public void successExchangeTransaction2() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + long firstTokenBalance = exchangeCapsule.getFirstTokenBalance(); + long secondTokenBalance = exchangeCapsule.getSecondTokenBalance(); + + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(tokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(100000000L, firstTokenBalance); + Assert.assertEquals("def", ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(200000000L, secondTokenBalance); + + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(tokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(tokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenBalance + quant, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals("def", ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(199998001L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(9000L, assetMap.get("abc").longValue()); + Assert.assertEquals(1999L, assetMap.get("def").longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * use Invalid Address, result is failed, exception is "Invalid address". + */ + @Test + public void invalidAddress() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_INVALID, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Invalid address"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Invalid address", e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * use AccountStore not exists, result is failed, exception is "account not exists". + */ + @Test + public void noAccount() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_NOACCOUNT, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("account[+OWNER_ADDRESS_NOACCOUNT+] not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[" + OWNER_ADDRESS_NOACCOUNT + "] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Exchange not exists + */ + @Test + public void exchangeNotExist() { + long exchangeId = 3; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Exchange not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Exchange[3] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token is not in exchange + */ + @Test + public void tokenIsNotInExchange() { + long exchangeId = 1; + String tokenId = "ddd"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token is not in exchange", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Token balance in exchange is equal with 0, the exchange has been closed" + */ + @Test + public void tokenBalanceZero() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + exchangeCapsule.setBalance(0, 0); + dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule); + + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Token balance in exchange is equal with 0," + + "the exchange has been closed", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * withdraw token quant must greater than zero + */ + @Test + public void tokenQuantLessThanZero() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = -1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("transaction token balance must greater than zero", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token balance must less than balanceLimit + */ + @Test + public void tokenBalanceGreaterThanBalanceLimit() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000_000_000_000_001L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), 10000); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance must less than 1000000000000000", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * balance is not enough + */ + @Test + public void balanceNotEnough() { + long exchangeId = 1; + String tokenId = "_"; + long quant = 100_000000L; + String buyTokenId = "abc"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + accountCapsule.setBalance(quant - 1); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * first token balance is not enough + */ + @Test + public void tokenBalanceNotEnough() { + long exchangeId = 2; + String tokenId = "abc"; + long quant = 1_000L; + String buyTokenId = "def"; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(tokenId.getBytes(), quant - 1); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(20000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(buyTokenId)); + dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule); + + ExchangeTransactionActuator actuator = new ExchangeTransactionActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, tokenId, quant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/tron/core/actuator/ExchangeWithdrawActuatorTest.java b/src/test/java/org/tron/core/actuator/ExchangeWithdrawActuatorTest.java new file mode 100644 index 00000000000..3a0bcfea2ba --- /dev/null +++ b/src/test/java/org/tron/core/actuator/ExchangeWithdrawActuatorTest.java @@ -0,0 +1,582 @@ +package org.tron.core.actuator; + +import static org.testng.Assert.fail; + +import com.google.protobuf.Any; +import com.google.protobuf.ByteString; +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.tron.common.utils.ByteArray; +import org.tron.common.utils.FileUtil; +import org.tron.core.Constant; +import org.tron.core.Wallet; +import org.tron.core.capsule.AccountCapsule; +import org.tron.core.capsule.ExchangeCapsule; +import org.tron.core.capsule.TransactionResultCapsule; +import org.tron.core.config.DefaultConfig; +import org.tron.core.config.args.Args; +import org.tron.core.db.Manager; +import org.tron.core.exception.ContractExeException; +import org.tron.core.exception.ContractValidateException; +import org.tron.core.exception.ItemNotFoundException; +import org.tron.protos.Contract; +import org.tron.protos.Protocol.AccountType; +import org.tron.protos.Protocol.Transaction.Result.code; + +@Slf4j + +public class ExchangeWithdrawActuatorTest { + + private static AnnotationConfigApplicationContext context; + private static Manager dbManager; + private static final String dbPath = "output_ExchangeWithdraw_test"; + private static final String ACCOUNT_NAME_FIRST = "ownerF"; + private static final String OWNER_ADDRESS_FIRST; + private static final String ACCOUNT_NAME_SECOND = "ownerS"; + private static final String OWNER_ADDRESS_SECOND; + private static final String URL = "https://tron.network"; + private static final String OWNER_ADDRESS_INVALID = "aaaa"; + private static final String OWNER_ADDRESS_NOACCOUNT; + private static final String OWNER_ADDRESS_BALANCENOTSUFFIENT; + + static { + Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF); + context = new AnnotationConfigApplicationContext(DefaultConfig.class); + OWNER_ADDRESS_FIRST = + Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc"; + OWNER_ADDRESS_SECOND = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc"; + OWNER_ADDRESS_NOACCOUNT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1aed"; + OWNER_ADDRESS_BALANCENOTSUFFIENT = + Wallet.getAddressPreFixString() + "548794500882809695a8a687866e06d4271a1ced"; + } + + /** + * Init data. + */ + @BeforeClass + public static void init() { + dbManager = context.getBean(Manager.class); + } + + /** + * Release resources. + */ + @AfterClass + public static void destroy() { + Args.clearParam(); + if (FileUtil.deleteDir(new File(dbPath))) { + logger.info("Release resources successful."); + } else { + logger.info("Release resources failure."); + } + context.destroy(); + } + + /** + * create temp Capsule test need. + */ + @Before + public void initTest() { + AccountCapsule ownerAccountFirstCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_FIRST), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + AccountType.Normal, + 10000_000_000L); + AccountCapsule ownerAccountSecondCapsule = + new AccountCapsule( + ByteString.copyFromUtf8(ACCOUNT_NAME_SECOND), + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_SECOND)), + AccountType.Normal, + 20000_000_000L); + ExchangeCapsule exchangeCapsule = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 1, + 1000000, + "abc".getBytes(), + "def".getBytes()); + exchangeCapsule.setBalance(100000000L, 200000000L); + ExchangeCapsule exchangeCapsule2 = + new ExchangeCapsule( + ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_FIRST)), + 2, + 1000000, + "_".getBytes(), + "def".getBytes()); + exchangeCapsule2.setBalance(1_000_000_000000L, 10_000_000L); + + dbManager.getAccountStore() + .put(ownerAccountFirstCapsule.getAddress().toByteArray(), ownerAccountFirstCapsule); + dbManager.getAccountStore() + .put(ownerAccountSecondCapsule.getAddress().toByteArray(), ownerAccountSecondCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule.createDbKey(), exchangeCapsule); + dbManager.getExchangeStore() + .put(exchangeCapsule2.createDbKey(), exchangeCapsule2); + + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1000000); + dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(10); + dbManager.getDynamicPropertiesStore().saveNextMaintenanceTime(2000000); + } + + private Any getContract(String address, long exchangeId, String tokenId, long quant) { + return Any.pack( + Contract.ExchangeWithdrawContract.newBuilder() + .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(address))) + .setExchangeId(exchangeId) + .setTokenId(ByteString.copyFrom(tokenId.getBytes())) + .setQuant(quant) + .build()); + } + + /** + * first withdraw Exchange,result is success. + */ + @Test + public void successExchangeWithdraw() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 100000000L; + String secondTokenId = "def"; + long secondTokenQuant = 200000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(firstTokenId)); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + long id = 1; + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().get(ByteArray.fromLong(id)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(id, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(0L, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(0L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(firstTokenQuant, assetMap.get(firstTokenId).longValue()); + Assert.assertEquals(secondTokenQuant, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * second withdraw Exchange,result is success. + */ + @Test + public void successExchangeWithdraw2() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 1_000_000_000000L; + String secondTokenId = "def"; + long secondTokenQuant = 4_000_000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS); + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + Assert.assertNotNull(exchangeCapsule); + + Assert.assertEquals(ByteString.copyFrom(ownerAddress), exchangeCapsule.getCreatorAddress()); + Assert.assertEquals(exchangeId, exchangeCapsule.getID()); + Assert.assertEquals(1000000, exchangeCapsule.getCreateTime()); + Assert.assertTrue(Arrays.equals(firstTokenId.getBytes(), exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(firstTokenId, ByteArray.toStr(exchangeCapsule.getFirstTokenId())); + Assert.assertEquals(0L, exchangeCapsule.getFirstTokenBalance()); + Assert.assertEquals(secondTokenId, ByteArray.toStr(exchangeCapsule.getSecondTokenId())); + Assert.assertEquals(0L, exchangeCapsule.getSecondTokenBalance()); + + accountCapsule = dbManager.getAccountStore().get(ownerAddress); + assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(firstTokenQuant + 10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(10_000_000L, assetMap.get(secondTokenId).longValue()); + + } catch (ContractValidateException e) { + logger.info(e.getMessage()); + Assert.assertFalse(e instanceof ContractValidateException); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * use Invalid Address, result is failed, exception is "Invalid address". + */ + @Test + public void invalidAddress() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 100000000L; + String secondTokenId = "def"; + long secondTokenQuant = 200000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(firstTokenId)); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_INVALID, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Invalid address"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Invalid address", e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * use AccountStore not exists, result is failed, exception is "account not exists". + */ + @Test + public void noAccount() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 100000000L; + String secondTokenId = "def"; + long secondTokenQuant = 200000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(firstTokenId)); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_NOACCOUNT, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("account[+OWNER_ADDRESS_NOACCOUNT+] not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[" + OWNER_ADDRESS_NOACCOUNT + "] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Exchange not exists + */ + @Test + public void exchangeNotExist() { + long exchangeId = 3; + String firstTokenId = "abc"; + long firstTokenQuant = 100000000L; + String secondTokenId = "def"; + long secondTokenQuant = 200000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(firstTokenId)); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail("Exchange not exists"); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Exchange[3] not exists", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * account is not creator + */ + @Test + public void accountIsNotCreator() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_SECOND); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_SECOND, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("account[a0548794500882809695a8a687866e76d4271a1abc]" + + " is not creator", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * token is not in exchange + */ + @Test + public void tokenIsNotInExchange() { + long exchangeId = 1; + String firstTokenId = "_"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(firstTokenQuant); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("token is not in exchange", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * Token balance in exchange is equal with 0, the exchange has been closed" + */ + @Test + public void tokenBalanceZero() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 200000000L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), firstTokenQuant); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore() + .get(ByteArray.fromLong(exchangeId)); + exchangeCapsule.setBalance(0, 0); + dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule); + + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("Token balance in exchange is equal with 0," + + "the exchange has been closed", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } catch (ItemNotFoundException e) { + Assert.assertFalse(e instanceof ItemNotFoundException); + } + } + + /** + * withdraw token quant must greater than zero + */ + @Test + public void tokenQuantLessThanZero() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = -1L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + accountCapsule.addAssetAmount(firstTokenId.getBytes(), 1000L); + accountCapsule.addAssetAmount(secondTokenId.getBytes(), secondTokenQuant); + accountCapsule.setBalance(10000_000000L); + dbManager.getAccountStore().put(ownerAddress, accountCapsule); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("withdraw token quant must greater than zero", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * exchange balance is not enough + */ + @Test + public void exchangeBalanceIsNotEnough() { + long exchangeId = 1; + String firstTokenId = "abc"; + long firstTokenQuant = 100_000_001L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(firstTokenId)); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("exchange balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } + + /** + * exchange balance is not enough + */ + @Test + public void exchangeBalanceIsNotEnough2() { + long exchangeId = 2; + String firstTokenId = "_"; + long firstTokenQuant = 1000_000_000001L; + String secondTokenId = "def"; + long secondTokenQuant = 400000000L; + + byte[] ownerAddress = ByteArray.fromHexString(OWNER_ADDRESS_FIRST); + AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress); + Map assetMap = accountCapsule.getAssetMap(); + Assert.assertEquals(10000_000000L, accountCapsule.getBalance()); + Assert.assertEquals(null, assetMap.get(secondTokenId)); + + ExchangeWithdrawActuator actuator = new ExchangeWithdrawActuator(getContract( + OWNER_ADDRESS_FIRST, exchangeId, firstTokenId, firstTokenQuant), + dbManager); + TransactionResultCapsule ret = new TransactionResultCapsule(); + + try { + actuator.validate(); + actuator.execute(ret); + fail(); + } catch (ContractValidateException e) { + Assert.assertTrue(e instanceof ContractValidateException); + Assert.assertEquals("exchange balance is not enough", + e.getMessage()); + } catch (ContractExeException e) { + Assert.assertFalse(e instanceof ContractExeException); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java b/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java index c9839b8dc1a..6d8522b6a59 100644 --- a/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java +++ b/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java @@ -131,5 +131,41 @@ public void testSellAndBuy2() { } + @Test + public void testInject() { + long sellBalance = 1_000_000_000000L; + long buyBalance = 10_000_000L; + long sellQuant = 10_000_000L; // 10 trx + + long result = processor.exchange(sellBalance, buyBalance, sellQuant); + Assert.assertEquals(99L, result); + + // inject + sellBalance += 100_000_000000L; + buyBalance += 1_000_000L; + + long result2 = processor.exchange(sellBalance, buyBalance, sellQuant); + Assert.assertEquals(99L, result2); + + } + + @Test + public void testWithdraw() { + long sellBalance = 1_000_000_000000L; + long buyBalance = 10_000_000L; + long sellQuant = 10_000_000L; // 10 trx + + long result = processor.exchange(sellBalance, buyBalance, sellQuant); + Assert.assertEquals(99L, result); + + // inject + sellBalance -= 800_000_000000L; + buyBalance -= 8_000_000L; + + long result2 = processor.exchange(sellBalance, buyBalance, sellQuant); + Assert.assertEquals(99L, result2); + + } + }