API modifications, remove blockchain defaultGroupId, Eclipse/git

GET /assets/trades/recent expanded to allow multiple otherAssetIds

When GET /assets/balances is called with address(es) but no assetIDs
then it will return balances for all assets, including zero balances
for assets the addresses don't own.

GET /addresses/{address} no long fakes a default groupID - in fact
defaultGroupId now removed from blockchain config.

Some Eclipse IDE files now hidden/removed from git repo.
This commit is contained in:
catbref
2019-03-11 11:17:34 +00:00
parent 43eec116b5
commit cdd1f5e966
16 changed files with 123 additions and 462 deletions

View File

@@ -22,7 +22,6 @@ import org.qora.api.ApiErrors;
import org.qora.api.ApiException;
import org.qora.api.ApiExceptionFactory;
import org.qora.asset.Asset;
import org.qora.block.BlockChain;
import org.qora.crypto.Crypto;
import org.qora.data.account.AccountData;
import org.qora.group.Group;
@@ -62,11 +61,7 @@ public class AddressesResource {
// Not found?
if (accountData == null)
accountData = new AccountData(address, null, null, BlockChain.getInstance().getDefaultGroupId());
// If Blockchain config doesn't allow NO_GROUP for approval-needing tx type then change this to blockchain's default groupID
if (accountData.getDefaultGroupId() == Group.NO_GROUP && BlockChain.getInstance().getRequireGroupForApproval())
accountData.setDefaultGroupId(BlockChain.getInstance().getDefaultGroupId());
accountData = new AccountData(address, null, null, Group.NO_GROUP);
return accountData;
} catch (ApiException e) {

View File

@@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -300,7 +301,7 @@ public class AssetsResource {
@ApiErrors({
ApiError.INVALID_ASSET_ID, ApiError.REPOSITORY_ISSUE
})
public List<RecentTradeData> getRecentTrades(@QueryParam("assetid") List<Long> assetIds, @QueryParam("otherassetid") Long otherAssetId, @Parameter(
public List<RecentTradeData> getRecentTrades(@QueryParam("assetid") List<Long> assetIds, @QueryParam("otherassetid") List<Long> otherAssetIds, @Parameter(
ref = "limit"
) @QueryParam("limit") Integer limit, @Parameter(
ref = "offset"
@@ -308,17 +309,21 @@ public class AssetsResource {
ref = "reverse"
) @QueryParam("reverse") Boolean reverse) {
try (final Repository repository = RepositoryManager.getRepository()) {
for (long assetId : assetIds)
if (!repository.getAssetRepository().assetExists(assetId))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID);
if (otherAssetId == null)
otherAssetId = Asset.QORA;
if (assetIds.isEmpty())
assetIds = Collections.singletonList(Asset.QORA);
else
if (!repository.getAssetRepository().assetExists(otherAssetId))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID);
for (long assetId : assetIds)
if (!repository.getAssetRepository().assetExists(assetId))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID);
return repository.getAssetRepository().getRecentTrades(assetIds, otherAssetId, limit, offset, reverse);
if (otherAssetIds.isEmpty())
otherAssetIds = Collections.singletonList(Asset.QORA);
else
for (long assetId : otherAssetIds)
if (!repository.getAssetRepository().assetExists(assetId))
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID);
return repository.getAssetRepository().getRecentTrades(assetIds, otherAssetIds, limit, offset, reverse);
} catch (DataException e) {
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
}

View File

@@ -24,7 +24,6 @@ import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import org.qora.data.block.BlockData;
import org.qora.group.Group;
import org.qora.repository.BlockRepository;
import org.qora.repository.DataException;
import org.qora.repository.Repository;
@@ -65,8 +64,6 @@ public class BlockChain {
/** Whether transactions with txGroupId of NO_GROUP are allowed */
private boolean requireGroupForApproval;
/** Default groupID when account's default groupID isn't set */
private int defaultGroupId = Group.NO_GROUP;
private GenesisBlock.GenesisInfo genesisInfo;
@@ -216,10 +213,6 @@ public class BlockChain {
return this.requireGroupForApproval;
}
public int getDefaultGroupId() {
return this.defaultGroupId;
}
public boolean getUseBrokenMD160ForAddresses() {
return this.useBrokenMD160ForAddresses;
}
@@ -276,14 +269,6 @@ public class BlockChain {
LOGGER.error(String.format("Missing feature trigger \"%s\" in blockchain config", featureTrigger.name()));
throw new RuntimeException("Missing feature trigger in blockchain config");
}
// If approval-needing transactions require a group the defaultGroupId needs to be set
// XXX we could also check groupID exists, or at least created in genesis block, or in blockchain config
if (this.requireGroupForApproval && this.defaultGroupId == Group.NO_GROUP) {
LOGGER.error("defaultGroupId must be set to valid groupID in blockchain config if approval-needing transactions require a group");
throw new RuntimeException(
"defaultGroupId must be set to valid groupID in blockchain config if approval-needing transactions require a group");
}
}
/**

View File

@@ -37,6 +37,7 @@ public interface AssetRepository {
public List<OrderData> getOpenOrders(long haveAssetId, long wantAssetId, Integer limit, Integer offset, Boolean reverse) throws DataException;
// Internal, non-API use
public default List<OrderData> getOpenOrders(long haveAssetId, long wantAssetId) throws DataException {
return getOpenOrders(haveAssetId, wantAssetId, null, null, null);
}
@@ -49,6 +50,7 @@ public interface AssetRepository {
public List<OrderData> getAccountsOrders(byte[] publicKey, long haveAssetId, long wantAssetId, Boolean optIsClosed, Boolean optIsFulfilled,
Integer limit, Integer offset, Boolean reverse) throws DataException;
// Internal, non-API use
public default List<OrderData> getAccountsOrders(byte[] publicKey, Boolean optIsClosed, Boolean optIsFulfilled) throws DataException {
return getAccountsOrders(publicKey, optIsClosed, optIsFulfilled, null, null, null);
}
@@ -61,15 +63,17 @@ public interface AssetRepository {
public List<TradeData> getTrades(long haveAssetId, long wantAssetId, Integer limit, Integer offset, Boolean reverse) throws DataException;
// Internal, non-API use
public default List<TradeData> getTrades(long haveAssetId, long wantAssetId) throws DataException {
return getTrades(haveAssetId, wantAssetId, null, null, null);
}
public List<RecentTradeData> getRecentTrades(List<Long> assetIds, Long otherAssetId, Integer limit, Integer offset, Boolean reverse) throws DataException;
public List<RecentTradeData> getRecentTrades(List<Long> assetIds, List<Long> otherAssetIds, Integer limit, Integer offset, Boolean reverse) throws DataException;
/** Returns TradeData for trades where orderId was involved, i.e. either initiating OR target order */
public List<TradeData> getOrdersTrades(byte[] orderId, Integer limit, Integer offset, Boolean reverse) throws DataException;
// Internal, non-API use
public default List<TradeData> getOrdersTrades(byte[] orderId) throws DataException {
return getOrdersTrades(orderId, null, null, null);
}

View File

@@ -145,16 +145,19 @@ public class HSQLDBAccountRepository implements AccountRepository {
@Override
public List<AccountBalanceData> getAssetBalances(List<String> addresses, List<Long> assetIds, Integer limit, Integer offset, Boolean reverse)
throws DataException {
String sql = "SELECT account, asset_id, balance, asset_name FROM AccountBalances NATURAL JOIN Assets " + "WHERE ";
String sql = "SELECT account, asset_id, IFNULL(balance, 0), asset_name FROM ";
if (!addresses.isEmpty())
sql += "account IN (" + String.join(", ", Collections.nCopies(addresses.size(), "?")) + ") ";
if (!addresses.isEmpty() && !assetIds.isEmpty())
sql += "AND ";
if (!addresses.isEmpty()) {
sql += "(VALUES " + String.join(", ", Collections.nCopies(addresses.size(), "(?)")) + ") AS Accounts (account) ";
sql += "CROSS JOIN Assets LEFT OUTER JOIN AccountBalances USING (asset_id, account) ";
} else {
// Simplier, no-address query
sql += "AccountBalances NATURAL JOIN Assets ";
}
if (!assetIds.isEmpty())
sql += "asset_id IN (" + String.join(", ", assetIds.stream().map(assetId -> assetId.toString()).collect(Collectors.toList())) + ") ";
// longs are safe enough to use literally
sql += "WHERE asset_id IN (" + String.join(", ", assetIds.stream().map(assetId -> assetId.toString()).collect(Collectors.toList())) + ") ";
sql += "ORDER BY account";
if (reverse != null && reverse)

View File

@@ -6,8 +6,8 @@ import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.qora.data.asset.AssetData;
import org.qora.data.asset.OrderData;
@@ -379,17 +379,19 @@ public class HSQLDBAssetRepository implements AssetRepository {
}
@Override
public List<RecentTradeData> getRecentTrades(List<Long> assetIds, Long otherAssetId, Integer limit, Integer offset, Boolean reverse) throws DataException {
public List<RecentTradeData> getRecentTrades(List<Long> assetIds, List<Long> otherAssetIds, Integer limit, Integer offset, Boolean reverse) throws DataException {
// Find assetID pairs that have actually been traded
String tradedAssetsSubquery = "SELECT have_asset_id, want_asset_id " + "FROM AssetTrades JOIN AssetOrders ON asset_order_id = initiating_order_id ";
// Optionally limit traded assetID pairs
if (!assetIds.isEmpty())
tradedAssetsSubquery += "WHERE have_asset_id IN (" + String.join(", ", Collections.nCopies(assetIds.size(), "?")) + ")";
// longs are safe enough to use literally
tradedAssetsSubquery += "WHERE have_asset_id IN (" + String.join(", ", assetIds.stream().map(assetId -> assetId.toString()).collect(Collectors.toList())) + ")";
if (otherAssetId != null) {
if (!otherAssetIds.isEmpty()) {
tradedAssetsSubquery += assetIds.isEmpty() ? " WHERE " : " AND ";
tradedAssetsSubquery += "want_asset_id = " + otherAssetId.toString();
// longs are safe enough to use literally
tradedAssetsSubquery += "want_asset_id IN (" + String.join(", ", otherAssetIds.stream().map(assetId -> assetId.toString()).collect(Collectors.toList())) + ")";
}
tradedAssetsSubquery += " GROUP BY have_asset_id, want_asset_id";
@@ -414,10 +416,9 @@ public class HSQLDBAssetRepository implements AssetRepository {
sql += HSQLDBRepository.limitOffsetSql(limit, offset);
Long[] assetIdsArray = assetIds.toArray(new Long[assetIds.size()]);
List<RecentTradeData> recentTrades = new ArrayList<>();
try (ResultSet resultSet = this.repository.checkedExecute(sql, (Object[]) assetIdsArray)) {
try (ResultSet resultSet = this.repository.checkedExecute(sql)) {
if (resultSet == null)
return recentTrades;