forked from Qortal/qortal
API, HSQLDB
Added more global parameters to /admin/unused API endpoint (formally /admin/dud) and also managed to remove /admin/unused from API documentation UI. Added results slicing to /assets/all Added /assets/orderbook API call that returns open asset orders Added /assets/trades that returns successful asset trades Added POST /assets/issue stub Unified HSQLDB connectionUrl to public variable inside Controller class. Can't deploy v1 ATs with isFinished=true flag as that prevents later transactions sending messages (during import of v1 chain). Some future hard-fork code will need to set all v1 ATs to "finished". Changed DB's "TransactionRecipients" to "TransactionParticipants" to properly support API call to find all transactions 'involving' a specific address. Support code needed in Block and Transaction with some transaction-specific overrides for Genesis and AT transactions. Removed old, deprecated calls from Transaction/TransactionRepository Moved HSQLDB database properties from connection URL to explicit SQL statements in HSQLDBDatabaseUpdates. They didn't work in connection URL during DB creation anyway. Retrofitted HSQLDB Accounts table with public_key column instead of rebuilding it later. Fixed incorrect comments in IssueAssetTransactionTransformer regarding v1 serialization for signing. Re-imported v1 chain to test latest changes.
This commit is contained in:
parent
2aaa199c86
commit
cfd8b53fc1
@ -26,7 +26,6 @@ import javax.ws.rs.core.MediaType;
|
|||||||
import data.account.AccountBalanceData;
|
import data.account.AccountBalanceData;
|
||||||
import data.account.AccountData;
|
import data.account.AccountData;
|
||||||
import qora.account.Account;
|
import qora.account.Account;
|
||||||
import qora.account.PublicKeyAccount;
|
|
||||||
import qora.assets.Asset;
|
import qora.assets.Asset;
|
||||||
import qora.crypto.Crypto;
|
import qora.crypto.Crypto;
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
@ -82,9 +81,7 @@ public class AddressesResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public String getLastReference(
|
public String getLastReference(@Parameter(ref = "address") @PathParam("address") String address) {
|
||||||
@Parameter(description = "a base64-encoded address", required = true) @PathParam("address") String address
|
|
||||||
) {
|
|
||||||
if (!Crypto.isValidAddress(address))
|
if (!Crypto.isValidAddress(address))
|
||||||
throw this.apiErrorFactory.createError(ApiError.INVALID_ADDRESS);
|
throw this.apiErrorFactory.createError(ApiError.INVALID_ADDRESS);
|
||||||
|
|
||||||
|
@ -32,13 +32,17 @@ public class AdminResource {
|
|||||||
HttpServletRequest request;
|
HttpServletRequest request;
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/dud")
|
@Path("/unused")
|
||||||
@Parameter(name = "blockSignature", description = "Block signature", schema = @Schema(type = "string", format = "byte", minLength = 84, maxLength=88))
|
@Parameter(in = ParameterIn.PATH, name = "blockSignature", description = "Block signature", schema = @Schema(type = "string", format = "byte"), example = "ZZZZ==")
|
||||||
@Parameter(in = ParameterIn.QUERY, name = "count", description = "Maximum number of entries to return", schema = @Schema(type = "integer", defaultValue = "10"))
|
@Parameter(in = ParameterIn.PATH, name = "assetId", description = "Asset ID, 0 is native coin", schema = @Schema(type = "string", format = "byte"))
|
||||||
@Parameter(in = ParameterIn.QUERY, name = "limit", description = "Maximum number of entries to return, 0 means unlimited", schema = @Schema(type = "integer", defaultValue = "10"))
|
@Parameter(in = ParameterIn.PATH, name = "otherAssetId", description = "Asset ID, 0 is native coin", schema = @Schema(type = "string", format = "byte"))
|
||||||
@Parameter(in = ParameterIn.QUERY, name = "offset", description = "Starting entry in results", schema = @Schema(type = "integer"))
|
@Parameter(in = ParameterIn.PATH, name = "address", description = "an account address", example = "QRHDHASWAXarqTvB2X4SNtJCWbxGf68M2o")
|
||||||
|
@Parameter(in = ParameterIn.QUERY, name = "count", description = "Maximum number of entries to return, 0 means none", schema = @Schema(type = "integer", defaultValue = "20"))
|
||||||
|
@Parameter(in = ParameterIn.QUERY, name = "limit", description = "Maximum number of entries to return, 0 means unlimited", schema = @Schema(type = "integer", defaultValue = "20"))
|
||||||
|
@Parameter(in = ParameterIn.QUERY, name = "offset", description = "Starting entry in results, 0 is first entry", schema = @Schema(type = "integer"))
|
||||||
@Parameter(in = ParameterIn.QUERY, name = "includeTransactions", description = "Include associated transactions in results", schema = @Schema(type = "boolean"))
|
@Parameter(in = ParameterIn.QUERY, name = "includeTransactions", description = "Include associated transactions in results", schema = @Schema(type = "boolean"))
|
||||||
@Parameter(in = ParameterIn.QUERY, name = "includeHolders", description = "Include asset holders in results", schema = @Schema(type = "boolean"))
|
@Parameter(in = ParameterIn.QUERY, name = "includeHolders", description = "Include asset holders in results", schema = @Schema(type = "boolean"))
|
||||||
|
@Parameter(in = ParameterIn.QUERY, name = "queryAssetId", description = "Asset ID, 0 is native coin", schema = @Schema(type = "string", format = "byte"))
|
||||||
public String globalParameters() {
|
public String globalParameters() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -55,12 +55,14 @@ public class AnnotationPostProcessor implements ReaderListener {
|
|||||||
@Override
|
@Override
|
||||||
public void afterScan(Reader reader, OpenAPI openAPI) {
|
public void afterScan(Reader reader, OpenAPI openAPI) {
|
||||||
// Populate Components section with reusable parameters, like "limit" and "offset"
|
// Populate Components section with reusable parameters, like "limit" and "offset"
|
||||||
// We take the reusable parameters from AdminResource.globalParameters path "/admin/dud"
|
// We take the reusable parameters from AdminResource.globalParameters path "/admin/unused"
|
||||||
Components components = openAPI.getComponents();
|
Components components = openAPI.getComponents();
|
||||||
PathItem globalParametersPathItem = openAPI.getPaths().get("/admin/dud");
|
PathItem globalParametersPathItem = openAPI.getPaths().get("/admin/unused");
|
||||||
if (globalParametersPathItem != null)
|
if (globalParametersPathItem != null) {
|
||||||
for (Parameter parameter : globalParametersPathItem.getGet().getParameters())
|
for (Parameter parameter : globalParametersPathItem.getGet().getParameters())
|
||||||
components.addParameters(parameter.getName(), parameter);
|
components.addParameters(parameter.getName(), parameter);
|
||||||
|
openAPI.getPaths().remove("/admin/unused");
|
||||||
|
}
|
||||||
|
|
||||||
// use context path and keys from "x-translation" extension annotations
|
// use context path and keys from "x-translation" extension annotations
|
||||||
// to translate supported annotations and finally remove "x-translation" extensions
|
// to translate supported annotations and finally remove "x-translation" extensions
|
||||||
|
@ -5,24 +5,32 @@ import io.swagger.v3.oas.annotations.Parameter;
|
|||||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
import repository.Repository;
|
import repository.Repository;
|
||||||
import repository.RepositoryManager;
|
import repository.RepositoryManager;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import api.models.AssetWithHolders;
|
import api.models.AssetWithHolders;
|
||||||
|
import api.models.IssueAssetRequest;
|
||||||
|
import api.models.TradeWithOrderInfo;
|
||||||
import data.assets.AssetData;
|
import data.assets.AssetData;
|
||||||
|
import data.assets.OrderData;
|
||||||
|
import data.assets.TradeData;
|
||||||
|
|
||||||
@Path("/assets")
|
@Path("/assets")
|
||||||
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
|
@Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN})
|
||||||
@ -43,9 +51,16 @@ public class AssetsResource {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public List<AssetData> getAllAssets() {
|
public List<AssetData> getAllAssets(@Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) {
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
return repository.getAssetRepository().getAllAssets();
|
List<AssetData> assets = repository.getAssetRepository().getAllAssets();
|
||||||
|
|
||||||
|
// Pagination would take effect here (or as part of the repository access)
|
||||||
|
int fromIndex = Integer.min(offset, assets.size());
|
||||||
|
int toIndex = limit == 0 ? assets.size() : Integer.min(fromIndex + limit, assets.size());
|
||||||
|
assets = assets.subList(fromIndex, toIndex);
|
||||||
|
|
||||||
|
return assets;
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e);
|
throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e);
|
||||||
}
|
}
|
||||||
@ -55,24 +70,25 @@ public class AssetsResource {
|
|||||||
@Path("/info")
|
@Path("/info")
|
||||||
@Operation(
|
@Operation(
|
||||||
summary = "Info on specific asset",
|
summary = "Info on specific asset",
|
||||||
|
description = "Supply either assetId OR assetName. (If both supplied, assetId takes priority).",
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "asset info",
|
description = "asset info",
|
||||||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetData.class)))
|
content = @Content(array = @ArraySchema(schema = @Schema(implementation = AssetWithHolders.class)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
public AssetWithHolders getAssetInfo(@QueryParam("key") Integer key, @QueryParam("name") String name, @Parameter(ref = "includeHolders") @QueryParam("withHolders") boolean includeHolders) {
|
public AssetWithHolders getAssetInfo(@QueryParam("assetId") Integer assetId, @QueryParam("assetName") String assetName, @Parameter(ref = "includeHolders") @QueryParam("withHolders") boolean includeHolders) {
|
||||||
if (key == null && (name == null || name.isEmpty()))
|
if (assetId == null && (assetName == null || assetName.isEmpty()))
|
||||||
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_CRITERIA);
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_CRITERIA);
|
||||||
|
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
AssetData assetData = null;
|
AssetData assetData = null;
|
||||||
|
|
||||||
if (key != null)
|
if (assetId != null)
|
||||||
assetData = repository.getAssetRepository().fromAssetId(key);
|
assetData = repository.getAssetRepository().fromAssetId(assetId);
|
||||||
else
|
else
|
||||||
assetData = repository.getAssetRepository().fromAssetName(name);
|
assetData = repository.getAssetRepository().fromAssetName(assetName);
|
||||||
|
|
||||||
if (assetData == null)
|
if (assetData == null)
|
||||||
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
||||||
@ -83,4 +99,98 @@ public class AssetsResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/orderbook/{assetId}/{otherAssetId}")
|
||||||
|
@Operation(
|
||||||
|
summary = "Asset order book",
|
||||||
|
description = "Returns open orders, offering {assetId} for {otherAssetId} in return.",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(
|
||||||
|
description = "asset orders",
|
||||||
|
content = @Content(array = @ArraySchema(schema = @Schema(implementation = OrderData.class)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public List<OrderData> getAssetOrders(@Parameter(ref = "assetId") @PathParam("assetId") int assetId, @Parameter(ref = "otherAssetId") @PathParam("otherAssetId") int otherAssetId,
|
||||||
|
@Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
if (!repository.getAssetRepository().assetExists(assetId))
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
||||||
|
|
||||||
|
if (!repository.getAssetRepository().assetExists(otherAssetId))
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
||||||
|
|
||||||
|
List<OrderData> orders = repository.getAssetRepository().getOpenOrders(assetId, otherAssetId);
|
||||||
|
|
||||||
|
// Pagination would take effect here (or as part of the repository access)
|
||||||
|
int fromIndex = Integer.min(offset, orders.size());
|
||||||
|
int toIndex = limit == 0 ? orders.size() : Integer.min(fromIndex + limit, orders.size());
|
||||||
|
orders = orders.subList(fromIndex, toIndex);
|
||||||
|
|
||||||
|
return orders;
|
||||||
|
} catch (DataException e) {
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/trades/{assetId}/{otherAssetId}")
|
||||||
|
@Operation(
|
||||||
|
summary = "Asset trades",
|
||||||
|
description = "Returns successful trades of {assetId} for {otherAssetId}.<br>" +
|
||||||
|
"Does NOT include trades of {otherAssetId} for {assetId}!<br>" +
|
||||||
|
"\"Initiating\" order is the order that caused the actual trade by matching up with the \"target\" order.",
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(
|
||||||
|
description = "asset trades",
|
||||||
|
content = @Content(array = @ArraySchema(schema = @Schema(implementation = TradeWithOrderInfo.class)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public List<TradeWithOrderInfo> getAssetTrades(@Parameter(ref = "assetId") @PathParam("assetId") int assetId, @Parameter(ref = "otherAssetId") @PathParam("otherAssetId") int otherAssetId,
|
||||||
|
@Parameter(ref = "limit") @QueryParam("limit") int limit, @Parameter(ref = "offset") @QueryParam("offset") int offset) {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
if (!repository.getAssetRepository().assetExists(assetId))
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
||||||
|
|
||||||
|
if (!repository.getAssetRepository().assetExists(otherAssetId))
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.INVALID_ASSET_ID);
|
||||||
|
|
||||||
|
List<TradeData> trades = repository.getAssetRepository().getTrades(assetId, otherAssetId);
|
||||||
|
|
||||||
|
// Pagination would take effect here (or as part of the repository access)
|
||||||
|
int fromIndex = Integer.min(offset, trades.size());
|
||||||
|
int toIndex = limit == 0 ? trades.size() : Integer.min(fromIndex + limit, trades.size());
|
||||||
|
trades = trades.subList(fromIndex, toIndex);
|
||||||
|
|
||||||
|
// Expanding remaining entries
|
||||||
|
List<TradeWithOrderInfo> fullTrades = new ArrayList<>();
|
||||||
|
for (TradeData trade : trades)
|
||||||
|
fullTrades.add(new TradeWithOrderInfo(repository, trade));
|
||||||
|
|
||||||
|
return fullTrades;
|
||||||
|
} catch (DataException e) {
|
||||||
|
throw ApiErrorFactory.getInstance().createError(ApiError.REPOSITORY_ISSUE, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/issue")
|
||||||
|
@Operation(
|
||||||
|
summary = "Issue new asset",
|
||||||
|
requestBody = @RequestBody(
|
||||||
|
required = true,
|
||||||
|
content = @Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = IssueAssetRequest.class)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public String issueAsset(IssueAssetRequest issueAssetRequest) {
|
||||||
|
// required: issuer (pubkey), name, description, quantity, isDivisible, fee
|
||||||
|
// optional: reference
|
||||||
|
// returns: raw tx
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package api;
|
|||||||
import globalization.Translator;
|
import globalization.Translator;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
|
||||||
import io.swagger.v3.oas.annotations.extensions.Extension;
|
import io.swagger.v3.oas.annotations.extensions.Extension;
|
||||||
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
|
import io.swagger.v3.oas.annotations.extensions.ExtensionProperty;
|
||||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
@ -11,7 +10,6 @@ import io.swagger.v3.oas.annotations.media.Content;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import qora.crypto.Crypto;
|
|
||||||
import qora.transaction.Transaction.TransactionType;
|
import qora.transaction.Transaction.TransactionType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package api.models;
|
package api.models;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
@ -9,10 +8,7 @@ import api.ApiError;
|
|||||||
import api.ApiErrorFactory;
|
import api.ApiErrorFactory;
|
||||||
import data.account.AccountBalanceData;
|
import data.account.AccountBalanceData;
|
||||||
import data.assets.AssetData;
|
import data.assets.AssetData;
|
||||||
import data.block.BlockData;
|
|
||||||
import data.transaction.TransactionData;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import qora.block.Block;
|
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
import repository.Repository;
|
import repository.Repository;
|
||||||
|
|
||||||
|
26
src/api/models/IssueAssetRequest.java
Normal file
26
src/api/models/IssueAssetRequest.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package api.models;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
public class IssueAssetRequest {
|
||||||
|
|
||||||
|
@Schema(description = "asset issuer's public key")
|
||||||
|
public byte[] issuer;
|
||||||
|
|
||||||
|
@Schema(description = "asset name - must be lowercase", example = "my-asset123")
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
@Schema(description = "asset description")
|
||||||
|
public String description;
|
||||||
|
|
||||||
|
public BigDecimal quantity;
|
||||||
|
|
||||||
|
public boolean isDivisible;
|
||||||
|
|
||||||
|
public BigDecimal fee;
|
||||||
|
|
||||||
|
public byte[] reference;
|
||||||
|
|
||||||
|
}
|
37
src/api/models/TradeWithOrderInfo.java
Normal file
37
src/api/models/TradeWithOrderInfo.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package api.models;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
import data.assets.OrderData;
|
||||||
|
import data.assets.TradeData;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import repository.DataException;
|
||||||
|
import repository.Repository;
|
||||||
|
|
||||||
|
@Schema(description = "Asset trade, with order info")
|
||||||
|
public class TradeWithOrderInfo {
|
||||||
|
|
||||||
|
@Schema(implementation = TradeData.class, name = "trade", title = "trade data")
|
||||||
|
@XmlElement(name = "trade")
|
||||||
|
public TradeData tradeData;
|
||||||
|
|
||||||
|
@Schema(implementation = OrderData.class, name = "order", title = "order data")
|
||||||
|
@XmlElement(name = "initiatingOrder")
|
||||||
|
public OrderData initiatingOrderData;
|
||||||
|
|
||||||
|
@Schema(implementation = OrderData.class, name = "order", title = "order data")
|
||||||
|
@XmlElement(name = "targetOrder")
|
||||||
|
public OrderData targetOrderData;
|
||||||
|
|
||||||
|
// For JAX-RS
|
||||||
|
protected TradeWithOrderInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TradeWithOrderInfo(Repository repository, TradeData tradeData) throws DataException {
|
||||||
|
this.tradeData = tradeData;
|
||||||
|
|
||||||
|
this.initiatingOrderData = repository.getAssetRepository().fromOrderId(tradeData.getInitiator());
|
||||||
|
this.targetOrderData = repository.getAssetRepository().fromOrderId(tradeData.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,7 +14,7 @@ import utils.Base58;
|
|||||||
public class blockgenerator {
|
public class blockgenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(blockgenerator.class);
|
private static final Logger LOGGER = LogManager.getLogger(blockgenerator.class);
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
public static final String connectionUrl = "jdbc:hsqldb:file:db/blockchain;create=true";
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length != 1) {
|
if (args.length != 1) {
|
||||||
|
@ -13,7 +13,7 @@ public class Controller {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(Controller.class);
|
private static final Logger LOGGER = LogManager.getLogger(Controller.class);
|
||||||
|
|
||||||
private static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
public static final String connectionUrl = "jdbc:hsqldb:file:db/blockchain;create=true";
|
||||||
|
|
||||||
public static final long startTime = System.currentTimeMillis();
|
public static final long startTime = System.currentTimeMillis();
|
||||||
private static final Object shutdownLock = new Object();
|
private static final Object shutdownLock = new Object();
|
||||||
|
@ -3,7 +3,7 @@ package data.assets;
|
|||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
|
||||||
//All properties to be converted to JSON via JAX-RS
|
// All properties to be converted to JSON via JAX-RS
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public class AssetData {
|
public class AssetData {
|
||||||
|
|
||||||
@ -16,6 +16,8 @@ public class AssetData {
|
|||||||
private boolean isDivisible;
|
private boolean isDivisible;
|
||||||
private byte[] reference;
|
private byte[] reference;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
// necessary for JAX-RS serialization
|
// necessary for JAX-RS serialization
|
||||||
protected AssetData() {
|
protected AssetData() {
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,48 @@ package data.assets;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
// All properties to be converted to JSON via JAX-RS
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public class OrderData implements Comparable<OrderData> {
|
public class OrderData implements Comparable<OrderData> {
|
||||||
|
|
||||||
|
// Properties
|
||||||
private byte[] orderId;
|
private byte[] orderId;
|
||||||
private byte[] creatorPublicKey;
|
private byte[] creatorPublicKey;
|
||||||
|
|
||||||
|
@Schema(description = "asset on offer to give by order creator")
|
||||||
private long haveAssetId;
|
private long haveAssetId;
|
||||||
|
|
||||||
|
@Schema(description = "asset wanted to receive by order creator")
|
||||||
private long wantAssetId;
|
private long wantAssetId;
|
||||||
|
|
||||||
|
@Schema(description = "amount of \"have\" asset to trade")
|
||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
private BigDecimal fulfilled;
|
|
||||||
|
@Schema(description = "amount of \"want\" asset to receive per unit of \"have\" asset traded")
|
||||||
private BigDecimal price;
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "how much \"have\" asset has traded")
|
||||||
|
private BigDecimal fulfilled;
|
||||||
|
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
|
|
||||||
|
@Schema(description = "has this order been cancelled for further trades?")
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
|
|
||||||
|
@Schema(description = "has this order been fully traded?")
|
||||||
private boolean isFulfilled;
|
private boolean isFulfilled;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
// necessary for JAX-RS serialization
|
||||||
|
protected OrderData() {
|
||||||
|
}
|
||||||
|
|
||||||
public OrderData(byte[] orderId, byte[] creatorPublicKey, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal fulfilled, BigDecimal price,
|
public OrderData(byte[] orderId, byte[] creatorPublicKey, long haveAssetId, long wantAssetId, BigDecimal amount, BigDecimal fulfilled, BigDecimal price,
|
||||||
long timestamp, boolean isClosed, boolean isFulfilled) {
|
long timestamp, boolean isClosed, boolean isFulfilled) {
|
||||||
this.orderId = orderId;
|
this.orderId = orderId;
|
||||||
@ -33,6 +62,8 @@ public class OrderData implements Comparable<OrderData> {
|
|||||||
this(orderId, creatorPublicKey, haveAssetId, wantAssetId, amount, BigDecimal.ZERO.setScale(8), price, timestamp, false, false);
|
this(orderId, creatorPublicKey, haveAssetId, wantAssetId, amount, BigDecimal.ZERO.setScale(8), price, timestamp, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getters/setters
|
||||||
|
|
||||||
public byte[] getOrderId() {
|
public byte[] getOrderId() {
|
||||||
return this.orderId;
|
return this.orderId;
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,42 @@ package data.assets;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
// All properties to be converted to JSON via JAX-RS
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
public class TradeData {
|
public class TradeData {
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
|
@Schema(name = "initiatingOrderId", description = "ID of order that caused trade")
|
||||||
|
@XmlElement(name = "initiatingOrderId")
|
||||||
private byte[] initiator;
|
private byte[] initiator;
|
||||||
|
|
||||||
|
@Schema(name = "targetOrderId", description = "ID of order that matched")
|
||||||
|
@XmlElement(name = "targetOrderId")
|
||||||
private byte[] target;
|
private byte[] target;
|
||||||
|
|
||||||
|
@Schema(name = "targetAmount", description = "amount traded from target order")
|
||||||
|
@XmlElement(name = "targetAmount")
|
||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
@Schema(name = "initiatorAmount", description = "amount traded from initiating order")
|
||||||
|
@XmlElement(name = "initiatorAmount")
|
||||||
private BigDecimal price;
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "when trade happened")
|
||||||
private long timestamp;
|
private long timestamp;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
|
// necessary for JAX-RS serialization
|
||||||
|
protected TradeData() {
|
||||||
|
}
|
||||||
|
|
||||||
public TradeData(byte[] initiator, byte[] target, BigDecimal amount, BigDecimal price, long timestamp) {
|
public TradeData(byte[] initiator, byte[] target, BigDecimal amount, BigDecimal price, long timestamp) {
|
||||||
this.initiator = initiator;
|
this.initiator = initiator;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import controller.Controller;
|
||||||
import data.block.BlockData;
|
import data.block.BlockData;
|
||||||
import qora.block.Block;
|
import qora.block.Block;
|
||||||
import qora.block.BlockChain;
|
import qora.block.BlockChain;
|
||||||
@ -9,8 +10,6 @@ import repository.hsqldb.HSQLDBRepositoryFactory;
|
|||||||
|
|
||||||
public class orphan {
|
public class orphan {
|
||||||
|
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
System.err.println("usage: orphan <new-blockchain-tip-height>");
|
System.err.println("usage: orphan <new-blockchain-tip-height>");
|
||||||
@ -20,7 +19,7 @@ public class orphan {
|
|||||||
int targetHeight = Integer.parseInt(args[0]);
|
int targetHeight = Integer.parseInt(args[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl);
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
System.err.println("Couldn't connect to repository: " + e.getMessage());
|
System.err.println("Couldn't connect to repository: " + e.getMessage());
|
||||||
|
@ -61,7 +61,8 @@ public class AT {
|
|||||||
this.atStateData = new ATStateData(atAddress, height, creation, stateData, stateHash, BigDecimal.ZERO.setScale(8));
|
this.atStateData = new ATStateData(atAddress, height, creation, stateData, stateHash, BigDecimal.ZERO.setScale(8));
|
||||||
} else {
|
} else {
|
||||||
// Legacy v1 AT
|
// Legacy v1 AT
|
||||||
// We deploy these in 'dead' state as they will never be run on Qora2
|
// We would deploy these in 'dead' state as they will never be run on Qora2
|
||||||
|
// but this breaks import from Qora1 so something else will have to mark them dead at hard-fork
|
||||||
|
|
||||||
// Extract code bytes length
|
// Extract code bytes length
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(deployATTransactionData.getCreationBytes());
|
ByteBuffer byteBuffer = ByteBuffer.wrap(deployATTransactionData.getCreationBytes());
|
||||||
@ -89,10 +90,10 @@ public class AT {
|
|||||||
byte[] codeBytes = new byte[codeLen];
|
byte[] codeBytes = new byte[codeLen];
|
||||||
byteBuffer.get(codeBytes);
|
byteBuffer.get(codeBytes);
|
||||||
|
|
||||||
// Create AT but in dead state
|
// Create AT
|
||||||
boolean isSleeping = false;
|
boolean isSleeping = false;
|
||||||
Integer sleepUntilHeight = null;
|
Integer sleepUntilHeight = null;
|
||||||
boolean isFinished = true;
|
boolean isFinished = false;
|
||||||
boolean hadFatalError = false;
|
boolean hadFatalError = false;
|
||||||
boolean isFrozen = false;
|
boolean isFrozen = false;
|
||||||
Long frozenBalance = null;
|
Long frozenBalance = null;
|
||||||
|
@ -9,6 +9,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -887,6 +888,7 @@ public class Block {
|
|||||||
this.repository.getBlockRepository().save(this.blockData);
|
this.repository.getBlockRepository().save(this.blockData);
|
||||||
|
|
||||||
// Link transactions to this block, thus removing them from unconfirmed transactions list.
|
// Link transactions to this block, thus removing them from unconfirmed transactions list.
|
||||||
|
// Also update "transaction participants" in repository for "transactions involving X" support in API
|
||||||
for (int sequence = 0; sequence < transactions.size(); ++sequence) {
|
for (int sequence = 0; sequence < transactions.size(); ++sequence) {
|
||||||
Transaction transaction = transactions.get(sequence);
|
Transaction transaction = transactions.get(sequence);
|
||||||
|
|
||||||
@ -897,6 +899,10 @@ public class Block {
|
|||||||
|
|
||||||
// No longer unconfirmed
|
// No longer unconfirmed
|
||||||
this.repository.getTransactionRepository().confirmTransaction(transaction.getTransactionData().getSignature());
|
this.repository.getTransactionRepository().confirmTransaction(transaction.getTransactionData().getSignature());
|
||||||
|
|
||||||
|
List<Account> participants = transaction.getInvolvedAccounts();
|
||||||
|
List<String> participantAddresses = participants.stream().map(account -> account.getAddress()).collect(Collectors.toList());
|
||||||
|
this.repository.getTransactionRepository().saveParticipants(transaction.getTransactionData(), participantAddresses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -918,6 +924,8 @@ public class Block {
|
|||||||
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
BlockTransactionData blockTransactionData = new BlockTransactionData(this.getSignature(), sequence,
|
||||||
transaction.getTransactionData().getSignature());
|
transaction.getTransactionData().getSignature());
|
||||||
this.repository.getBlockRepository().delete(blockTransactionData);
|
this.repository.getBlockRepository().delete(blockTransactionData);
|
||||||
|
|
||||||
|
this.repository.getTransactionRepository().deleteParticipants(transaction.getTransactionData());
|
||||||
}
|
}
|
||||||
|
|
||||||
// If fees are non-zero then remove fees from generator's balance
|
// If fees are non-zero then remove fees from generator's balance
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package qora.transaction;
|
package qora.transaction;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -53,6 +54,14 @@ public class ATTransaction extends Transaction {
|
|||||||
return Collections.singletonList(new Account(this.repository, this.atTransactionData.getRecipient()));
|
return Collections.singletonList(new Account(this.repository, this.atTransactionData.getRecipient()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** For AT-Transactions, the use the AT address instead of transaction creator (which is genesis account) */
|
||||||
|
@Override
|
||||||
|
public List<Account> getInvolvedAccounts() throws DataException {
|
||||||
|
List<Account> participants = new ArrayList<Account>(getRecipientAccounts());
|
||||||
|
participants.add(getATAccount());
|
||||||
|
return participants;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvolved(Account account) throws DataException {
|
public boolean isInvolved(Account account) throws DataException {
|
||||||
String address = account.getAddress();
|
String address = account.getAddress();
|
||||||
|
@ -41,6 +41,12 @@ public class GenesisTransaction extends Transaction {
|
|||||||
return Collections.singletonList(new Account(this.repository, genesisTransactionData.getRecipient()));
|
return Collections.singletonList(new Account(this.repository, genesisTransactionData.getRecipient()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** For Genesis Transactions, do not include transaction creator (which is genesis account) */
|
||||||
|
@Override
|
||||||
|
public List<Account> getInvolvedAccounts() throws DataException {
|
||||||
|
return getRecipientAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvolved(Account account) throws DataException {
|
public boolean isInvolved(Account account) throws DataException {
|
||||||
String address = account.getAddress();
|
String address = account.getAddress();
|
||||||
|
@ -3,6 +3,7 @@ package qora.transaction;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -10,7 +11,6 @@ import java.util.Map;
|
|||||||
import static java.util.Arrays.stream;
|
import static java.util.Arrays.stream;
|
||||||
import static java.util.stream.Collectors.toMap;
|
import static java.util.stream.Collectors.toMap;
|
||||||
|
|
||||||
import data.block.BlockData;
|
|
||||||
import data.transaction.TransactionData;
|
import data.transaction.TransactionData;
|
||||||
import qora.account.Account;
|
import qora.account.Account;
|
||||||
import qora.account.PrivateKeyAccount;
|
import qora.account.PrivateKeyAccount;
|
||||||
@ -314,6 +314,21 @@ public abstract class Transaction {
|
|||||||
*/
|
*/
|
||||||
public abstract List<Account> getRecipientAccounts() throws DataException;
|
public abstract List<Account> getRecipientAccounts() throws DataException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of involved accounts for this transaction.
|
||||||
|
* <p>
|
||||||
|
* "Involved" means sender or recipient.
|
||||||
|
*
|
||||||
|
* @return list of involved accounts, or empty list if none
|
||||||
|
* @throws DataException
|
||||||
|
*/
|
||||||
|
public List<Account> getInvolvedAccounts() throws DataException {
|
||||||
|
// Typically this is all the recipients plus the transaction creator/sender
|
||||||
|
List<Account> participants = new ArrayList<Account>(getRecipientAccounts());
|
||||||
|
participants.add(getCreator());
|
||||||
|
return participants;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether passed account is an involved party in this transaction.
|
* Returns whether passed account is an involved party in this transaction.
|
||||||
* <p>
|
* <p>
|
||||||
@ -349,17 +364,6 @@ public abstract class Transaction {
|
|||||||
return new PublicKeyAccount(this.repository, this.transactionData.getCreatorPublicKey());
|
return new PublicKeyAccount(this.repository, this.transactionData.getCreatorPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load encapsulating block's data from repository, if any
|
|
||||||
*
|
|
||||||
* @return BlockData, or null if transaction is not in a Block
|
|
||||||
* @throws DataException
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public BlockData getBlock() throws DataException {
|
|
||||||
return this.repository.getTransactionRepository().getBlockDataFromSignature(this.transactionData.getSignature());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load parent's transaction data from repository via this transaction's reference.
|
* Load parent's transaction data from repository via this transaction's reference.
|
||||||
*
|
*
|
||||||
|
@ -2,7 +2,6 @@ package repository;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import data.account.AccountBalanceData;
|
|
||||||
import data.assets.AssetData;
|
import data.assets.AssetData;
|
||||||
import data.assets.OrderData;
|
import data.assets.OrderData;
|
||||||
import data.assets.TradeData;
|
import data.assets.TradeData;
|
||||||
@ -39,6 +38,8 @@ public interface AssetRepository {
|
|||||||
|
|
||||||
// Trades
|
// Trades
|
||||||
|
|
||||||
|
public List<TradeData> getTrades(long haveAssetId, long wantAssetId) throws DataException;
|
||||||
|
|
||||||
public List<TradeData> getOrdersTrades(byte[] orderId) throws DataException;
|
public List<TradeData> getOrdersTrades(byte[] orderId) throws DataException;
|
||||||
|
|
||||||
public void save(TradeData tradeData) throws DataException;
|
public void save(TradeData tradeData) throws DataException;
|
||||||
|
@ -5,10 +5,10 @@ import qora.transaction.Transaction.TransactionType;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import data.block.BlockData;
|
|
||||||
|
|
||||||
public interface TransactionRepository {
|
public interface TransactionRepository {
|
||||||
|
|
||||||
|
// Fetching transactions / transaction height
|
||||||
|
|
||||||
public TransactionData fromSignature(byte[] signature) throws DataException;
|
public TransactionData fromSignature(byte[] signature) throws DataException;
|
||||||
|
|
||||||
public TransactionData fromReference(byte[] reference) throws DataException;
|
public TransactionData fromReference(byte[] reference) throws DataException;
|
||||||
@ -18,11 +18,16 @@ public interface TransactionRepository {
|
|||||||
/** Returns block height containing transaction or 0 if not in a block or transaction doesn't exist */
|
/** Returns block height containing transaction or 0 if not in a block or transaction doesn't exist */
|
||||||
public int getHeightFromSignature(byte[] signature) throws DataException;
|
public int getHeightFromSignature(byte[] signature) throws DataException;
|
||||||
|
|
||||||
@Deprecated
|
// Transaction participants
|
||||||
public BlockData getBlockDataFromSignature(byte[] signature) throws DataException;
|
|
||||||
|
|
||||||
public List<byte[]> getAllSignaturesInvolvingAddress(String address) throws DataException;
|
public List<byte[]> getAllSignaturesInvolvingAddress(String address) throws DataException;
|
||||||
|
|
||||||
|
public void saveParticipants(TransactionData transactionData, List<String> participants) throws DataException;
|
||||||
|
|
||||||
|
public void deleteParticipants(TransactionData transactionData) throws DataException;
|
||||||
|
|
||||||
|
// Searching transactions
|
||||||
|
|
||||||
public List<byte[]> getAllSignaturesMatchingCriteria(Integer startBlock, Integer blockLimit, TransactionType txType, String address) throws DataException;
|
public List<byte[]> getAllSignaturesMatchingCriteria(Integer startBlock, Integer blockLimit, TransactionType txType, String address) throws DataException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -228,6 +228,34 @@ public class HSQLDBAssetRepository implements AssetRepository {
|
|||||||
|
|
||||||
// Trades
|
// Trades
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<TradeData> getTrades(long haveAssetId, long wantAssetId) throws DataException {
|
||||||
|
List<TradeData> trades = new ArrayList<TradeData>();
|
||||||
|
|
||||||
|
try (ResultSet resultSet = this.repository.checkedExecute(
|
||||||
|
"SELECT initiating_order_id, target_order_id, AssetTrades.amount, AssetTrades.price, traded FROM AssetOrders JOIN AssetTrades ON initiating_order_id = asset_order_id "
|
||||||
|
+ "WHERE have_asset_id = ? AND want_asset_id = ? ORDER BY traded ASC",
|
||||||
|
haveAssetId, wantAssetId)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return trades;
|
||||||
|
|
||||||
|
do {
|
||||||
|
byte[] initiatingOrderId = resultSet.getBytes(1);
|
||||||
|
byte[] targetOrderId = resultSet.getBytes(2);
|
||||||
|
BigDecimal amount = resultSet.getBigDecimal(3);
|
||||||
|
BigDecimal price = resultSet.getBigDecimal(4);
|
||||||
|
long timestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
|
||||||
|
|
||||||
|
TradeData trade = new TradeData(initiatingOrderId, targetOrderId, amount, price, timestamp);
|
||||||
|
trades.add(trade);
|
||||||
|
} while (resultSet.next());
|
||||||
|
|
||||||
|
return trades;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch asset trades from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TradeData> getOrdersTrades(byte[] initiatingOrderId) throws DataException {
|
public List<TradeData> getOrdersTrades(byte[] initiatingOrderId) throws DataException {
|
||||||
List<TradeData> trades = new ArrayList<TradeData>();
|
List<TradeData> trades = new ArrayList<TradeData>();
|
||||||
|
@ -5,8 +5,6 @@ import java.sql.ResultSet;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
|
|
||||||
import qora.crypto.Crypto;
|
|
||||||
|
|
||||||
public class HSQLDBDatabaseUpdates {
|
public class HSQLDBDatabaseUpdates {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,8 +73,11 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
switch (databaseVersion) {
|
switch (databaseVersion) {
|
||||||
case 0:
|
case 0:
|
||||||
// create from new
|
// create from new
|
||||||
|
stmt.execute("SET DATABASE SQL NAMES TRUE"); // SQL keywords cannot be used as DB object names, e.g. table names
|
||||||
|
stmt.execute("SET DATABASE SQL SYNTAX MYS TRUE"); // Required for our use of INSERT ... ON DUPLICATE KEY UPDATE ... syntax
|
||||||
|
stmt.execute("SET DATABASE SQL RESTRICT EXEC TRUE"); // No multiple-statement execute() or DDL/DML executeQuery()
|
||||||
stmt.execute("SET DATABASE DEFAULT TABLE TYPE CACHED");
|
stmt.execute("SET DATABASE DEFAULT TABLE TYPE CACHED");
|
||||||
stmt.execute("SET DATABASE COLLATION SQL_TEXT NO PAD");
|
stmt.execute("SET DATABASE COLLATION SQL_TEXT NO PAD"); // Do not pad strings to same length before comparison
|
||||||
stmt.execute("CREATE COLLATION SQL_TEXT_UCC_NO_PAD FOR SQL_TEXT FROM SQL_TEXT_UCC NO PAD");
|
stmt.execute("CREATE COLLATION SQL_TEXT_UCC_NO_PAD FOR SQL_TEXT FROM SQL_TEXT_UCC NO PAD");
|
||||||
stmt.execute("CREATE COLLATION SQL_TEXT_NO_PAD FOR SQL_TEXT FROM SQL_TEXT NO PAD");
|
stmt.execute("CREATE COLLATION SQL_TEXT_NO_PAD FOR SQL_TEXT FROM SQL_TEXT NO PAD");
|
||||||
stmt.execute("SET FILES SPACE TRUE"); // Enable per-table block space within .data file, useful for CACHED table types
|
stmt.execute("SET FILES SPACE TRUE"); // Enable per-table block space within .data file, useful for CACHED table types
|
||||||
@ -151,13 +152,12 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
// Index to allow quick sorting by creation-else-signature
|
// Index to allow quick sorting by creation-else-signature
|
||||||
stmt.execute("CREATE INDEX UnconfirmedTransactionsIndex ON UnconfirmedTransactions (creation, signature)");
|
stmt.execute("CREATE INDEX UnconfirmedTransactionsIndex ON UnconfirmedTransactions (creation, signature)");
|
||||||
|
|
||||||
// Transaction recipients
|
// Transaction participants
|
||||||
// XXX This should be transaction "participants" to allow lookup of all activity by an address!
|
// To allow lookup of all activity by an address
|
||||||
// Could add "is_recipient" boolean flag
|
stmt.execute("CREATE TABLE TransactionParticipants (signature Signature, participant QoraAddress NOT NULL, "
|
||||||
stmt.execute("CREATE TABLE TransactionRecipients (signature Signature, recipient QoraAddress NOT NULL, "
|
|
||||||
+ "FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
+ "FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||||
// Use a separate table space as this table will be very large.
|
// Use a separate table space as this table will be very large.
|
||||||
stmt.execute("SET TABLE TransactionRecipients NEW SPACE");
|
stmt.execute("SET TABLE TransactionParticipants NEW SPACE");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
@ -310,9 +310,11 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
|
|
||||||
case 22:
|
case 22:
|
||||||
// Accounts
|
// Accounts
|
||||||
stmt.execute("CREATE TABLE Accounts (account QoraAddress, reference Signature, PRIMARY KEY (account))");
|
stmt.execute("CREATE TABLE Accounts (account QoraAddress, reference Signature, public_key QoraPublicKey, PRIMARY KEY (account))");
|
||||||
stmt.execute("CREATE TABLE AccountBalances (account QoraAddress, asset_id AssetID, balance QoraAmount NOT NULL, "
|
stmt.execute("CREATE TABLE AccountBalances (account QoraAddress, asset_id AssetID, balance QoraAmount NOT NULL, "
|
||||||
+ "PRIMARY KEY (account, asset_id), FOREIGN KEY (account) REFERENCES Accounts (account) ON DELETE CASCADE)");
|
+ "PRIMARY KEY (account, asset_id), FOREIGN KEY (account) REFERENCES Accounts (account) ON DELETE CASCADE)");
|
||||||
|
// For looking up an account by public key
|
||||||
|
stmt.execute("CREATE INDEX AccountPublicKeyIndex on Accounts (public_key)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 23:
|
case 23:
|
||||||
@ -387,35 +389,6 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
stmt.execute("CREATE INDEX ATTransactionsIndex on ATTransactions (AT_address)");
|
stmt.execute("CREATE INDEX ATTransactionsIndex on ATTransactions (AT_address)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 28:
|
|
||||||
// Associate public keys with accounts
|
|
||||||
stmt.execute("ALTER TABLE Accounts add public_key QoraPublicKey");
|
|
||||||
// For looking up an account by public key
|
|
||||||
stmt.execute("CREATE INDEX AccountPublicKeyIndex on Accounts (public_key)");
|
|
||||||
|
|
||||||
// Do not call close() on this as connection did not come from pool!
|
|
||||||
HSQLDBRepository repository = new HSQLDBRepository(connection);
|
|
||||||
|
|
||||||
try (ResultSet resultSet = repository.checkedExecute("SELECT DISTINCT creator from Transactions")) {
|
|
||||||
if (resultSet == null) {
|
|
||||||
repository = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
byte[] publicKey = resultSet.getBytes(1);
|
|
||||||
|
|
||||||
String address = Crypto.toAddress(publicKey);
|
|
||||||
|
|
||||||
HSQLDBSaver saveHelper = new HSQLDBSaver("Accounts");
|
|
||||||
saveHelper.bind("account", address).bind("public_key", publicKey);
|
|
||||||
saveHelper.execute(repository);
|
|
||||||
} while (resultSet.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
repository = null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return false;
|
return false;
|
||||||
|
@ -31,10 +31,6 @@ public class HSQLDBRepositoryFactory implements RepositoryFactory {
|
|||||||
|
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.setProperty("close_result", "true"); // Auto-close old ResultSet if Statement creates new ResultSet
|
properties.setProperty("close_result", "true"); // Auto-close old ResultSet if Statement creates new ResultSet
|
||||||
properties.setProperty("sql.strict_exec", "true"); // No multi-SQL execute() or DDL/DML executeQuery()
|
|
||||||
properties.setProperty("sql.enforce_names", "true"); // SQL keywords cannot be used as DB object names, e.g. table names
|
|
||||||
properties.setProperty("sql.syntax_mys", "true"); // Required for our use of INSERT ... ON DUPLICATE KEY UPDATE ... syntax
|
|
||||||
properties.setProperty("sql.pad_space", "false"); // Do not pad strings to same length before comparison
|
|
||||||
this.connectionPool.setProperties(properties);
|
this.connectionPool.setProperties(properties);
|
||||||
|
|
||||||
// Perform DB updates?
|
// Perform DB updates?
|
||||||
|
@ -7,12 +7,8 @@ import java.sql.Timestamp;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
|
|
||||||
import data.PaymentData;
|
import data.PaymentData;
|
||||||
import data.block.BlockData;
|
|
||||||
import data.transaction.TransactionData;
|
import data.transaction.TransactionData;
|
||||||
import qora.transaction.Transaction.TransactionType;
|
import qora.transaction.Transaction.TransactionType;
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
@ -249,31 +245,11 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockData getBlockDataFromSignature(byte[] signature) throws DataException {
|
|
||||||
if (signature == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Fetch block signature (if any)
|
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT block_signature FROM BlockTransactions WHERE transaction_signature = ? LIMIT 1",
|
|
||||||
signature)) {
|
|
||||||
if (resultSet == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
byte[] blockSignature = resultSet.getBytes(1);
|
|
||||||
|
|
||||||
return this.repository.getBlockRepository().fromSignature(blockSignature);
|
|
||||||
} catch (SQLException | DataException e) {
|
|
||||||
throw new DataException("Unable to fetch transaction's block from repository", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<byte[]> getAllSignaturesInvolvingAddress(String address) throws DataException {
|
public List<byte[]> getAllSignaturesInvolvingAddress(String address) throws DataException {
|
||||||
List<byte[]> signatures = new ArrayList<byte[]>();
|
List<byte[]> signatures = new ArrayList<byte[]>();
|
||||||
|
|
||||||
// XXX We need a table for all parties involved in a transaction, not just recipients
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT signature FROM TransactionRecipients WHERE participant = ?", address)) {
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT signature FROM TransactionRecipients WHERE recipient = ?", address)) {
|
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return signatures;
|
return signatures;
|
||||||
|
|
||||||
@ -289,6 +265,32 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveParticipants(TransactionData transactionData, List<String> participants) throws DataException {
|
||||||
|
byte[] signature = transactionData.getSignature();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (String participant : participants) {
|
||||||
|
HSQLDBSaver saver = new HSQLDBSaver("TransactionParticipants");
|
||||||
|
|
||||||
|
saver.bind("signature", signature).bind("participant", participant);
|
||||||
|
|
||||||
|
saver.execute(this.repository);
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to save transaction participant into repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteParticipants(TransactionData transactionData) throws DataException {
|
||||||
|
try {
|
||||||
|
this.repository.delete("TransactionParticipants", "signature = ?", transactionData.getSignature());
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to delete transaction participants from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<byte[]> getAllSignaturesMatchingCriteria(Integer startBlock, Integer blockLimit, TransactionType txType, String address) throws DataException {
|
public List<byte[]> getAllSignaturesMatchingCriteria(Integer startBlock, Integer blockLimit, TransactionType txType, String address) throws DataException {
|
||||||
List<byte[]> signatures = new ArrayList<byte[]>();
|
List<byte[]> signatures = new ArrayList<byte[]>();
|
||||||
@ -323,13 +325,13 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
|
|
||||||
if (hasAddress) {
|
if (hasAddress) {
|
||||||
if (hasTxType)
|
if (hasTxType)
|
||||||
tableJoins.add("TransactionRecipients ON TransactionRecipients.signature = Transactions.signature");
|
tableJoins.add("TransactionParticipants ON TransactionParticipants.signature = Transactions.signature");
|
||||||
else if (hasHeightRange)
|
else if (hasHeightRange)
|
||||||
tableJoins.add("TransactionRecipients ON TransactionRecipients.signature = BlockTransactions.transaction_signature");
|
tableJoins.add("TransactionParticipants ON TransactionParticipants.signature = BlockTransactions.transaction_signature");
|
||||||
else
|
else
|
||||||
tableJoins.add("TransactionRecipients");
|
tableJoins.add("TransactionParticipants");
|
||||||
|
|
||||||
signatureColumn = "TransactionRecipients.signature";
|
signatureColumn = "TransactionParticipants.signature";
|
||||||
}
|
}
|
||||||
|
|
||||||
// WHERE clauses next
|
// WHERE clauses next
|
||||||
@ -346,14 +348,13 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
whereClauses.add("Transactions.type = " + txType.value);
|
whereClauses.add("Transactions.type = " + txType.value);
|
||||||
|
|
||||||
if (hasAddress) {
|
if (hasAddress) {
|
||||||
whereClauses.add("TransactionRecipients.recipient = ?");
|
whereClauses.add("TransactionParticipants.participant = ?");
|
||||||
bindParams.add(address);
|
bindParams.add(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
String sql = "SELECT " + signatureColumn + " FROM " + String.join(" JOIN ", tableJoins) + " WHERE " + String.join(" AND ", whereClauses);
|
String sql = "SELECT " + signatureColumn + " FROM " + String.join(" JOIN ", tableJoins) + " WHERE " + String.join(" AND ", whereClauses);
|
||||||
System.out.println("Transaction search SQL:\n" + sql);
|
System.out.println("Transaction search SQL:\n" + sql);
|
||||||
|
|
||||||
// XXX We need a table for all parties involved in a transaction, not just recipients
|
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, bindParams.toArray())) {
|
try (ResultSet resultSet = this.repository.checkedExecute(sql, bindParams.toArray())) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return signatures;
|
return signatures;
|
||||||
|
@ -120,8 +120,7 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In Qora v1, the bytes used for verification have transaction type set to REGISTER_NAME_TRANSACTION so we need to test for v1-ness and adjust the bytes
|
* In Qora v1, the bytes used for verification have asset's reference zeroed so we need to test for v1-ness and adjust the bytes accordingly.
|
||||||
* accordingly.
|
|
||||||
*
|
*
|
||||||
* @param transactionData
|
* @param transactionData
|
||||||
* @return byte[]
|
* @return byte[]
|
||||||
@ -136,8 +135,8 @@ public class IssueAssetTransactionTransformer extends TransactionTransformer {
|
|||||||
// Special v1 version
|
// Special v1 version
|
||||||
|
|
||||||
// Zero duplicate signature/reference
|
// Zero duplicate signature/reference
|
||||||
int start = bytes.length - SIGNATURE_LENGTH - BIG_DECIMAL_LENGTH;
|
int start = bytes.length - ASSET_REFERENCE_LENGTH - FEE_LENGTH; // before asset reference (and fee)
|
||||||
int end = start + SIGNATURE_LENGTH;
|
int end = start + ASSET_REFERENCE_LENGTH;
|
||||||
Arrays.fill(bytes, start, end, (byte) 0);
|
Arrays.fill(bytes, start, end, (byte) 0);
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import com.google.common.hash.HashCode;
|
import com.google.common.hash.HashCode;
|
||||||
|
|
||||||
|
import controller.Controller;
|
||||||
import data.transaction.TransactionData;
|
import data.transaction.TransactionData;
|
||||||
import qora.block.BlockChain;
|
import qora.block.BlockChain;
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
@ -13,8 +14,6 @@ import utils.Base58;
|
|||||||
|
|
||||||
public class txhex {
|
public class txhex {
|
||||||
|
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
System.err.println("usage: txhex <base58-tx-signature>");
|
System.err.println("usage: txhex <base58-tx-signature>");
|
||||||
@ -24,7 +23,7 @@ public class txhex {
|
|||||||
byte[] signature = Base58.decode(args[0]);
|
byte[] signature = Base58.decode(args[0]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl);
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
System.err.println("Couldn't connect to repository: " + e.getMessage());
|
System.err.println("Couldn't connect to repository: " + e.getMessage());
|
||||||
|
@ -31,6 +31,7 @@ import com.google.common.hash.HashCode;
|
|||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
|
import controller.Controller;
|
||||||
import data.at.ATData;
|
import data.at.ATData;
|
||||||
import data.at.ATStateData;
|
import data.at.ATStateData;
|
||||||
import data.block.BlockData;
|
import data.block.BlockData;
|
||||||
@ -56,7 +57,6 @@ import utils.Triple;
|
|||||||
public class v1feeder extends Thread {
|
public class v1feeder extends Thread {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger(v1feeder.class);
|
private static final Logger LOGGER = LogManager.getLogger(v1feeder.class);
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
|
||||||
|
|
||||||
private static final int INACTIVITY_TIMEOUT = 60 * 1000; // milliseconds
|
private static final int INACTIVITY_TIMEOUT = 60 * 1000; // milliseconds
|
||||||
private static final int CONNECTION_TIMEOUT = 2 * 1000; // milliseconds
|
private static final int CONNECTION_TIMEOUT = 2 * 1000; // milliseconds
|
||||||
@ -529,7 +529,7 @@ public class v1feeder extends Thread {
|
|||||||
readLegacyATs(legacyATPathname);
|
readLegacyATs(legacyATPathname);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl);
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
LOGGER.error("Couldn't connect to repository", e);
|
LOGGER.error("Couldn't connect to repository", e);
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package test;
|
package test;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
|
||||||
|
import controller.Controller;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
|
||||||
import repository.DataException;
|
import repository.DataException;
|
||||||
@ -10,12 +13,9 @@ import repository.hsqldb.HSQLDBRepositoryFactory;
|
|||||||
|
|
||||||
public class Common {
|
public class Common {
|
||||||
|
|
||||||
// public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true;close_result=true;sql.strict_exec=true;sql.enforce_names=true;sql.syntax_mys=true;sql.pad_space=false";
|
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:file:db/test;create=true";
|
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setRepository() throws DataException {
|
public static void setRepository() throws DataException {
|
||||||
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(connectionUrl);
|
RepositoryFactory repositoryFactory = new HSQLDBRepositoryFactory(Controller.connectionUrl);
|
||||||
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
RepositoryManager.setRepositoryFactory(repositoryFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import repository.hsqldb.HSQLDBRepositoryFactory;
|
|||||||
// Don't extend Common as we want an in-memory database
|
// Don't extend Common as we want an in-memory database
|
||||||
public class GenesisTests {
|
public class GenesisTests {
|
||||||
|
|
||||||
public static final String connectionUrl = "jdbc:hsqldb:mem:db/test;create=true;close_result=true;sql.strict_exec=true;sql.enforce_names=true;sql.syntax_mys=true";
|
public static final String connectionUrl = "jdbc:hsqldb:mem:db/blockchain;create=true";
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setRepository() throws DataException {
|
public static void setRepository() throws DataException {
|
||||||
|
@ -74,7 +74,7 @@ import settings.Settings;
|
|||||||
// Don't extend Common as we want to use an in-memory database
|
// Don't extend Common as we want to use an in-memory database
|
||||||
public class TransactionTests {
|
public class TransactionTests {
|
||||||
|
|
||||||
private static final String connectionUrl = "jdbc:hsqldb:mem:db/test;create=true;close_result=true;sql.strict_exec=true;sql.enforce_names=true;sql.syntax_mys=true";
|
private static final String connectionUrl = "jdbc:hsqldb:mem:db/blockchain;create=true";
|
||||||
|
|
||||||
private static final byte[] generatorSeed = HashCode.fromString("0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210").asBytes();
|
private static final byte[] generatorSeed = HashCode.fromString("0123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210").asBytes();
|
||||||
private static final byte[] senderSeed = HashCode.fromString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef").asBytes();
|
private static final byte[] senderSeed = HashCode.fromString("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef").asBytes();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user