diff --git a/pom.xml b/pom.xml index a2a88ad..4e19041 100644 --- a/pom.xml +++ b/pom.xml @@ -40,18 +40,18 @@ 1.3 - 3.12.4 - 5.7.2 - 1.8.0-RC1 - 5.8.0-RC1 - 1.48 + 4.5.1 + 5.8.2 + 1.8.2 + 5.8.2 + 1.49 UTF-8 - 2.17.1 - 1.12.73 + 2.17.2 + 1.12.237 1.2.1 - 1.2.0 - 1.12.73 - 2.14.0-beta.1 + 1.5.1 + 1.12.237 + 2.17.3 @@ -71,7 +71,7 @@ com.fasterxml.jackson.core jackson-databind - 2.12.6.1 + 2.13.3 org.jmockit @@ -93,7 +93,7 @@ org.apache.commons commons-math3 - 3.5 + 3.6.1 @@ -152,13 +152,16 @@ ${mockito.version} test - - - com.hedera.hashgraph - sdk-jdk7 - ${hedera-java-sdk.version} + sdk-full + 2.16.1 + + + + io.grpc + grpc-netty-shaded + 1.46.0 com.amazonaws @@ -183,34 +186,48 @@ javax.xml.bind jaxb-api - 2.3.0 - - - - com.google.cloud - google-cloud-spanner - 1.33.0 - - - com.google.cloud - google-cloud-storage - 1.88.0 + 2.3.1 org.flywaydb flyway-core - 7.4.0 + 8.5.11 org.bouncycastle bcprov-jdk15on - 1.67 + 1.70 org.postgresql postgresql - 42.3.3 + 42.3.4 + + + com.google.cloud + google-cloud-storage + 2.8.1 + + + com.google.cloud + google-cloud-pubsub + 1.119.1 + + + com.google.cloud.functions + functions-framework-api + 1.0.4 + + + com.google.cloud.sql + postgres-socket-factory + 1.6.1 + + + com.zaxxer + HikariCP + 5.0.1 @@ -238,7 +255,23 @@ ${project.artifactId} + + + com.google.cloud.functions + function-maven-plugin + 0.10.0 + + com.hedera.exchange.ERTGcp + + @@ -297,7 +330,30 @@ - + + org.apache.maven.plugins + maven-shade-plugin + + + package + shade + + ${project.build.directory}/deployment/${project.build.finalName}.jar + + + + .SF + .DSA + .RSA + + + + + + + + org.apache.maven.plugins maven-shade-plugin diff --git a/src/main/java/com/hedera/exchange/ERTAws.java b/src/main/java/com/hedera/exchange/ERTAws.java new file mode 100644 index 0000000..dbee211 --- /dev/null +++ b/src/main/java/com/hedera/exchange/ERTAws.java @@ -0,0 +1,62 @@ +package com.hedera.exchange; + +/*- + * ‌ + * Hedera Exchange Rate Tool + * ​ + * Copyright (C) 2019 - 2020 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + * + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static com.hedera.exchange.ExchangeRateTool.AWS_TAG; + +public class ERTAws { + public static void main(final String ... args) { + ExchangeRateTool ert = new ExchangeRateTool(); + ert.run(AWS_TAG); + } +} diff --git a/src/main/java/com/hedera/exchange/database/AWSDBParams.java b/src/main/java/com/hedera/exchange/ERTGcp.java similarity index 80% rename from src/main/java/com/hedera/exchange/database/AWSDBParams.java rename to src/main/java/com/hedera/exchange/ERTGcp.java index affa2a4..fe571f0 100644 --- a/src/main/java/com/hedera/exchange/database/AWSDBParams.java +++ b/src/main/java/com/hedera/exchange/ERTGcp.java @@ -1,4 +1,4 @@ -package com.hedera.exchange.database; +package com.hedera.exchange; /*- * ‌ @@ -52,22 +52,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import com.hedera.exchange.ERTUtils; +import com.google.cloud.functions.HttpFunction; +import com.google.cloud.functions.HttpRequest; +import com.google.cloud.functions.HttpResponse; -public class AWSDBParams { - public String getEndpoint() { - return ERTUtils.getDecryptedEnvironmentVariableFromAWS("ENDPOINT") + getDatabaseName(); - } - - public String getUsername() { - return ERTUtils.getDecryptedEnvironmentVariableFromAWS("USERNAME"); - } - - public String getPassword() { - return ERTUtils.getDecryptedEnvironmentVariableFromAWS("PASSWORD"); - } +import static com.hedera.exchange.ExchangeRateTool.GCP_TAG; - public String getDatabaseName() { - return ERTUtils.getDecryptedEnvironmentVariableFromAWS("DATABASE"); +public class ERTGcp implements HttpFunction { + @Override + public void service(final HttpRequest httpRequest, final HttpResponse httpResponse) throws Exception { + ExchangeRateTool ert = new ExchangeRateTool(); + ert.run(GCP_TAG); } } diff --git a/src/main/java/com/hedera/exchange/ERTNotificationHelper.java b/src/main/java/com/hedera/exchange/ERTNotificationHelper.java index 335a12e..3533859 100644 --- a/src/main/java/com/hedera/exchange/ERTNotificationHelper.java +++ b/src/main/java/com/hedera/exchange/ERTNotificationHelper.java @@ -57,10 +57,23 @@ import com.amazonaws.services.sns.AmazonSNSClient; import com.amazonaws.services.sns.AmazonSNSClientBuilder; import com.amazonaws.services.sns.model.AmazonSNSException; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutureCallback; +import com.google.api.core.ApiFutures; +import com.google.api.gax.rpc.ApiException; +import com.google.cloud.pubsub.v1.Publisher; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.ByteString; +import com.google.pubsub.v1.PubsubMessage; +import com.google.pubsub.v1.TopicName; import com.hedera.exchange.exchanges.Exchange; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + import static com.hedera.exchange.ERTUtils.getDecryptedEnvironmentVariableFromAWS; public final class ERTNotificationHelper { @@ -78,6 +91,70 @@ private ERTNotificationHelper() { * Content of the Email */ public static void publishMessage(final String subject, final String message, final String region) { + if (ExchangeRateTool.env == Environment.AWS) { + publishMessageUsingSNS(subject, message, region); + } else { + try { + publishMessageUsingPubSub(List.of(subject, message)); + } catch (InterruptedException ex) { + LOGGER.error(Exchange.EXCHANGE_FILTER, "failed to terminate PubSub publisher"); + } + } + } + + private static void publishMessageUsingPubSub(List messages) throws InterruptedException { + final var projectId = System.getenv("PROJECT_ID"); + final var topicId = System.getenv("TOPIC_ID"); + LOGGER.info(Exchange.EXCHANGE_FILTER, "projectId is : {}, topicId is {}", projectId, topicId); + TopicName topicName = TopicName.of(projectId, topicId); + Publisher publisher = null; + + try { + publisher = Publisher.newBuilder(topicName).build(); + + for (var message : messages) { + ByteString data = ByteString.copyFromUtf8(message); + PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build(); + + // Once published, returns a server-assigned message id (unique within the topic) + ApiFuture future = publisher.publish(pubsubMessage); + + // Add an asynchronous callback to handle success / failure + ApiFutures.addCallback( + future, + new ApiFutureCallback<>() { + + @Override + public void onFailure(Throwable throwable) { + if (throwable instanceof ApiException) { + ApiException apiException = ((ApiException) throwable); + // details on the API exception + System.out.println(apiException.getStatusCode().getCode()); + System.out.println(apiException.isRetryable()); + } + System.out.println("Error publishing message : " + message); + } + + @Override + public void onSuccess(String messageId) { + // Once published, returns server-assigned message ids (unique within the topic) + System.out.println("Published message ID: " + messageId); + } + }, + MoreExecutors.directExecutor()); + } + } catch (IOException ex) { + LOGGER.error(Exchange.EXCHANGE_FILTER, "Failed to publish message"); + } finally { + if (publisher != null) { + // When finished with the publisher, shutdown to free up resources. + publisher.shutdown(); + publisher.awaitTermination(1, TimeUnit.MINUTES); + } + } + } + + private static void publishMessageUsingSNS(final String subject, final String message, final String region) { try { final AmazonSNSClient SNS_CLIENT = (AmazonSNSClient) AmazonSNSClientBuilder.standard() .withRegion(getValidRegion(region)) diff --git a/src/main/java/com/hedera/exchange/ERTParams.java b/src/main/java/com/hedera/exchange/ERTParams.java index 7e2ad40..3ae7c1e 100644 --- a/src/main/java/com/hedera/exchange/ERTParams.java +++ b/src/main/java/com/hedera/exchange/ERTParams.java @@ -67,9 +67,8 @@ import com.google.cloud.storage.Storage; import com.google.cloud.storage.StorageOptions; import com.hedera.hashgraph.sdk.AccountId; -import com.hedera.exchange.database.AWSDBParams; import com.hedera.exchange.database.ExchangeDB; -import com.hedera.exchange.database.ExchangeRateAWSRD; +import com.hedera.exchange.database.QueryHelper; import com.hedera.exchange.exchanges.Exchange; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -82,6 +81,8 @@ import java.util.Map; import java.util.Set; +import static com.hedera.exchange.ExchangeRateTool.env; + /** * This class reads the parameters from the config file and provides get methods to fetch the configuration parameters. * @@ -151,12 +152,12 @@ public class ERTParams { */ public static ERTParams readConfig(final String[] args) throws IOException { if (args == null || args.length == 0) { - return readDefaultConfig(); + return readDefaultConfigFromAWS(); } final String configurationPath = args[0]; if (configurationPath == null || configurationPath.trim().length() < 1) { - return readDefaultConfig(); + return readDefaultConfigFromAWS(); } LOGGER.debug("Using configuration file: {}", configurationPath); @@ -170,19 +171,28 @@ public static ERTParams readConfig(final String[] args) throws IOException { } if (configurationPath.contains("TO_DECIDE:AWS_NodeAddressFormat")){ - return readDefaultConfig(configurationPath); + return readDefaultConfigFromAWS(configurationPath); } return readConfig(configurationPath); } + + public static ERTParams readConfig() throws IOException { + if (env == Environment.AWS) { + return readDefaultConfigFromAWS(); + } else { + return readDefaultConfigFromGCP(); + } + } + /** * Reads the AWS instance address from the arguments and replaces the node address in the * default configuration * @param awsInstanceAddress * @return ERTParams object */ - private static ERTParams readDefaultConfig(String awsInstanceAddress) throws IOException { + private static ERTParams readDefaultConfigFromAWS(String awsInstanceAddress) throws IOException { final String defaultConfigUri = ERTUtils.getDecryptedEnvironmentVariableFromAWS("DEFAULT_CONFIG_URI"); ERTParams ertParams = readConfigFromAWSS3(defaultConfigUri); @@ -198,11 +208,24 @@ private static ERTParams readDefaultConfig(String awsInstanceAddress) throws IOE * @return ERTParams object * @throws IOException */ - private static ERTParams readDefaultConfig() throws IOException { + private static ERTParams readDefaultConfigFromAWS() throws IOException { final String defaultConfigUri = ERTUtils.getDecryptedEnvironmentVariableFromAWS("DEFAULT_CONFIG_URI"); return readConfigFromAWSS3(defaultConfigUri); } + private static ERTParams readDefaultConfigFromGCP() throws IOException { + final var projectId = System.getenv("PROJECT_ID"); + final var bucket = System.getenv("BUCKET_NAME"); + final var config = System.getenv("CONFIG_PATH"); + LOGGER.info("Reading configuration file from GCP: {}, {}, {}", projectId, bucket, config); + var options = StorageOptions.newBuilder().setProjectId(projectId).build(); + var storage = options.getService(); + var blob = storage.get(bucket, config); + + return OBJECT_MAPPER.readValue(blob.getContent(), ERTParams.class); +// return readConfig("src/main/resources/configIntegration.json"); + } + /** * Read Config file from the Amazon S3 bucket * @param endpoint @@ -404,7 +427,11 @@ public String getOperatorId() { @JsonIgnore public String getOperatorKey(String networkName) { - return ERTUtils.getDecryptedEnvironmentVariableFromAWS("OPERATOR_KEY_" + networkName); + if (env == Environment.AWS) { + return ERTUtils.getDecryptedEnvironmentVariableFromAWS("OPERATOR_KEY_" + networkName); + } else { + return System.getenv("OPERATOR_KEY_" + networkName); + } } /** @@ -428,7 +455,7 @@ public long getValidationDelayInMilliseconds() { * @return ExchangeRateDb object as we are configured with AWS POSTGRESQL for now. */ public ExchangeDB getExchangeDB() { - return new ExchangeRateAWSRD(new AWSDBParams()); + return new QueryHelper(); } /** diff --git a/src/main/java/com/hedera/exchange/ERTUtils.java b/src/main/java/com/hedera/exchange/ERTUtils.java index 3b56623..1bbc40c 100644 --- a/src/main/java/com/hedera/exchange/ERTUtils.java +++ b/src/main/java/com/hedera/exchange/ERTUtils.java @@ -88,7 +88,7 @@ import java.util.List; import java.util.Map; -import static com.hedera.exchange.ExchangeRateTool.LAMBDA_FUNCTION_NAME; +import static com.hedera.exchange.ExchangeRateTool.FUNCTION_NAME; /** * This class implements helper functions of ERT @@ -132,7 +132,7 @@ private ERTUtils() { */ public static String getDecryptedEnvironmentVariableFromAWS(final String environmentVariable) { final String environmentValue = System.getenv(environmentVariable); - return getDecryptedValueFromAWS(environmentValue, LAMBDA_FUNCTION_NAME); + return getDecryptedValueFromAWS(environmentValue, FUNCTION_NAME); } static String getDecryptedValueFromAWS(final String value, final String lambdaFunctionName) { diff --git a/src/main/java/com/hedera/exchange/Environment.java b/src/main/java/com/hedera/exchange/Environment.java new file mode 100644 index 0000000..0c540a2 --- /dev/null +++ b/src/main/java/com/hedera/exchange/Environment.java @@ -0,0 +1,5 @@ +package com.hedera.exchange; + +public enum Environment { + AWS, GCP +} diff --git a/src/main/java/com/hedera/exchange/ExchangeRateTool.java b/src/main/java/com/hedera/exchange/ExchangeRateTool.java index 0596ce5..64e307c 100644 --- a/src/main/java/com/hedera/exchange/ExchangeRateTool.java +++ b/src/main/java/com/hedera/exchange/ExchangeRateTool.java @@ -60,7 +60,6 @@ import com.hedera.hashgraph.sdk.PrecheckStatusException; import com.hedera.hashgraph.sdk.PrivateKey; import com.hedera.hashgraph.sdk.ReceiptStatusException; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -81,22 +80,21 @@ * * @author Anirudh, Cesar */ -public class ExchangeRateTool { +public class ExchangeRateTool{ private static final Logger LOGGER = LogManager.getLogger(ExchangeRateTool.class); private static final Map EMPTY_MAP = Collections.emptyMap(); + protected static final String AWS_TAG = "aws"; + protected static final String GCP_TAG = "gcp"; + static final int DEFAULT_RETRIES = 4; - static final String LAMBDA_FUNCTION_NAME = System.getenv("AWS_LAMBDA_FUNCTION_NAME"); + public static Environment env; + static String FUNCTION_NAME; private ERTParams ertParams; private ExchangeDB exchangeDB; - public static void main(final String ... args) { - ExchangeRateTool ert = new ExchangeRateTool(); - ert.run(args); - } - /** * This method executes the ERT logic and if an execution fails, it retries for the a fixed number of times * mentioned in DEFAULT_RETRIES. @@ -105,14 +103,33 @@ public static void main(final String ... args) { protected void run(final String ... args) { LOGGER.debug(Exchange.EXCHANGE_FILTER, "Starting ExchangeRateTool"); try { - ertParams = ERTParams.readConfig(args); + env = validateTag(args); + FUNCTION_NAME = env == Environment.AWS ? + System.getenv("AWS_LAMBDA_FUNCTION_NAME") : + System.getenv("K_SERVICE"); + ertParams = ERTParams.readConfig(); exchangeDB = ertParams.getExchangeDB(); execute(); } catch (Exception ex) { - final var subject = "FAILED : ERT Run Failed on " + LAMBDA_FUNCTION_NAME; + final var subject = "FAILED : ERT Run Failed on " + FUNCTION_NAME; final var message = ex.getMessage() + "\n"; LOGGER.error(Exchange.EXCHANGE_FILTER, subject, ex); - ERTNotificationHelper.publishMessage(subject, message + ExceptionUtils.getStackTrace(ex), ertParams.getRegion()); + ERTNotificationHelper.publishMessage(subject, message + ex.getMessage(), ertParams.getRegion()); + } + } + + private Environment validateTag(final String[] args) { + if (args == null) { + LOGGER.error(Exchange.EXCHANGE_FILTER, "invalid tag provided. Has to be one of {}, {}", GCP_TAG, AWS_TAG); + throw new IllegalArgumentException("Invalid tag provided. Has to be one of " + GCP_TAG + ", " + AWS_TAG); + } + + if (args[0].matches(GCP_TAG)) { + LOGGER.info(Exchange.EXCHANGE_FILTER, "Running on GCP Cloud Functions"); + return Environment.GCP; + } else { + LOGGER.info(Exchange.EXCHANGE_FILTER, "Running on AWS Lambda"); + return Environment.AWS; } } @@ -195,7 +212,7 @@ protected Status fileUpdateTransactionForNetwork( final var nodesFromPrevRun = ertAddressBookFromPreviousRun != null ? getNodesForClient(ertAddressBookFromPreviousRun.getNodes()) : EMPTY_MAP; - final Map nodesForClient = nodesFromPrevRun.isEmpty() ? nodesFromPrevRun : nodesFromConfig; + final Map nodesForClient = !nodesFromPrevRun.isEmpty() ? nodesFromPrevRun : nodesFromConfig; LOGGER.info(Exchange.EXCHANGE_FILTER, "Building a Hedera Client with nodes {} \n Account {}", nodesForClient, @@ -284,4 +301,9 @@ private Rate getCurrentRate(final ExchangeDB exchangeDb, final ERTParams params) LOGGER.info(Exchange.EXCHANGE_FILTER, "Using default exchange rate as current exchange rate"); return params.getDefaultRate(); } + + public static void main(final String ... args) { + ExchangeRateTool ert = new ExchangeRateTool(); + ert.run("gcp"); + } } \ No newline at end of file diff --git a/src/main/java/com/hedera/exchange/HederaNetworkCommunicator.java b/src/main/java/com/hedera/exchange/HederaNetworkCommunicator.java index f7be2f1..54859c4 100644 --- a/src/main/java/com/hedera/exchange/HederaNetworkCommunicator.java +++ b/src/main/java/com/hedera/exchange/HederaNetworkCommunicator.java @@ -69,7 +69,6 @@ import com.hedera.hashgraph.sdk.TransactionReceipt; import com.hedera.hashgraph.sdk.TransactionResponse; import com.hedera.hashgraph.sdk.proto.NodeAddressBook; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -149,6 +148,7 @@ public ERTAddressBook updateExchangeRateFile( LOGGER.info(Exchange.EXCHANGE_FILTER, "Balance before updating the Exchange Rate file: {}", currentBalance.hbars.toString()); +// ERTAddressBook newAddressBook = new ERTAddressBook(); ERTAddressBook newAddressBook = fetchAddressBook(client); updateExchangeRateFileTxn(exchangeRate, exchangeRateFileId, exchangeRateAsBytes, client, memo, ertParams.getRegion()); @@ -257,8 +257,8 @@ private void updateExchangeRateFileTxn( } } catch (PrecheckStatusException ex) { var subject = String.format("ERROR : %s : PreCheckStatusException : %s", networkName, ex.status); - LOGGER.error(Exchange.EXCHANGE_FILTER, subject); - ERTNotificationHelper.publishMessage(subject, ExceptionUtils.getStackTrace(ex), region); + LOGGER.error(Exchange.EXCHANGE_FILTER, subject, ex); + ERTNotificationHelper.publishMessage(subject, ex.getMessage(), region); if( retryCount++ == DEFAULT_RETRIES ) { throw ex; } @@ -353,8 +353,8 @@ private byte[] getFileContentsQuery(final Client client, final FileId fileId) th final Hbar getContentsQueryFee = new FileContentsQuery() .setFileId(fileId) .getCost(client); - LOGGER.debug(Exchange.EXCHANGE_FILTER, "Cost to get file {} contents is : {}", fileId, getContentsQueryFee); - client.setDefaultMaxQueryPayment(getContentsQueryFee); + LOGGER.info(Exchange.EXCHANGE_FILTER, "Cost to get file {} contents is : {}", fileId, getContentsQueryFee); + client.setDefaultMaxQueryPayment(Hbar.from(1L)); final ByteString contentsResponse = new FileContentsQuery() .setFileId(fileId) diff --git a/src/main/java/com/hedera/exchange/api/ExchangeRateAPI.java b/src/main/java/com/hedera/exchange/api/ExchangeRateAPI.java index 78a24fd..a2d6415 100644 --- a/src/main/java/com/hedera/exchange/api/ExchangeRateAPI.java +++ b/src/main/java/com/hedera/exchange/api/ExchangeRateAPI.java @@ -52,14 +52,18 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import com.hedera.exchange.Environment; import com.hedera.exchange.ExchangeRate; -import com.hedera.exchange.database.AWSDBParams; +import com.hedera.exchange.ExchangeRateTool; +import com.hedera.exchange.database.DBParams; import com.hedera.exchange.database.ExchangeDB; -import com.hedera.exchange.database.ExchangeRateAWSRD; +import com.hedera.exchange.database.QueryHelper; import java.util.HashMap; import java.util.Map; +import static com.hedera.exchange.Environment.AWS; + /** * This class implements an API that one can trigger using an AWS lambda for example and get the latest Exchange rate file * from the database. @@ -75,7 +79,9 @@ public class ExchangeRateAPI { } public static LambdaResponse getLatest() throws Exception { - final ExchangeDB exchangeDb = new ExchangeRateAWSRD(new AWSDBParams()); + // currently only supported on AWS + ExchangeRateTool.env = AWS; + final ExchangeDB exchangeDb = new QueryHelper(); final ExchangeRate latestExchangeRate = exchangeDb.getLatestExchangeRate(); if (latestExchangeRate == null) { return new LambdaResponse(200, "No exchange rate available yet"); diff --git a/src/main/java/com/hedera/exchange/api/ExchangeRateHistoryAPI.java b/src/main/java/com/hedera/exchange/api/ExchangeRateHistoryAPI.java index 51142e3..e8d09c4 100644 --- a/src/main/java/com/hedera/exchange/api/ExchangeRateHistoryAPI.java +++ b/src/main/java/com/hedera/exchange/api/ExchangeRateHistoryAPI.java @@ -59,11 +59,13 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.hedera.exchange.Environment; import com.hedera.exchange.ExchangeRate; +import com.hedera.exchange.ExchangeRateTool; import com.hedera.exchange.Rate; -import com.hedera.exchange.database.AWSDBParams; +import com.hedera.exchange.database.DBParams; import com.hedera.exchange.database.ExchangeDB; -import com.hedera.exchange.database.ExchangeRateAWSRD; +import com.hedera.exchange.database.QueryHelper; import com.hedera.exchange.exchanges.Exchange; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -88,6 +90,8 @@ import java.util.Map; import java.util.TimeZone; +import static com.hedera.exchange.Environment.AWS; + /** * This class implements an API which returns the data from the last 'n'[defaulted to 5] successful runs of ERT * @@ -128,8 +132,9 @@ public void handleRequest(InputStream inputStream, OutputStream outputStream, Co no_of_records = Integer.parseInt((String) queryStringParameters.get("no_of_records")); } } - - final ExchangeDB exchangeDb = new ExchangeRateAWSRD(new AWSDBParams()); + // currently only supported on AWS + ExchangeRateTool.env = AWS; + final ExchangeDB exchangeDb = new QueryHelper(); LOGGER.info(Exchange.EXCHANGE_FILTER, "params received : {}", no_of_records); NO_OF_RECORDS = no_of_records; ExchangeRate midnightRate = exchangeDb.getLatestMidnightExchangeRate(); diff --git a/src/main/java/com/hedera/exchange/database/DBParams.java b/src/main/java/com/hedera/exchange/database/DBParams.java new file mode 100644 index 0000000..3e59df2 --- /dev/null +++ b/src/main/java/com/hedera/exchange/database/DBParams.java @@ -0,0 +1,133 @@ +package com.hedera.exchange.database; + +/*- + * ‌ + * Hedera Exchange Rate Tool + * ​ + * Copyright (C) 2019 - 2020 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + * + * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.hedera.exchange.ERTUtils; +import com.hedera.exchange.Environment; +import com.hedera.exchange.exchanges.Exchange; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +import static com.hedera.exchange.ExchangeRateTool.env; + +public final class DBParams { + private static final Logger LOGGER = LogManager.getLogger(DBParams.class); + + public DBParams() { + throw new UnsupportedOperationException("Utility Class"); + } + + public static String getEndpoint() { + if (env == Environment.AWS) { + return ERTUtils.getDecryptedEnvironmentVariableFromAWS("ENDPOINT") + getDatabaseName(); + } + else { + LOGGER.error(Exchange.EXCHANGE_FILTER, "should not be possible"); + return System.getenv("ENDPOINT") + getDatabaseName(); + } + } + + public static String getUsername() { + if (env == Environment.AWS) { + return ERTUtils.getDecryptedEnvironmentVariableFromAWS("USERNAME"); + } + else { + return System.getenv("USERNAME"); + } + } + + public static String getPassword() { + if (env == Environment.AWS) { + return ERTUtils.getDecryptedEnvironmentVariableFromAWS("PASSWORD"); + } + else { + return System.getenv("PASSWORD"); + } + } + + public static String getDatabaseName() { + if (env == Environment.AWS) { + return ERTUtils.getDecryptedEnvironmentVariableFromAWS("DATABASE"); + } + else { + return System.getenv("DATABASE"); + } + } + + public static Connection getConnection() throws SQLException { + if (env == Environment.AWS) { + return DriverManager.getConnection(getEndpoint(), getUsername(), getPassword()); + } else { + DataSource pool = getGcpDataSource(); + return pool.getConnection(); + } + } + + public static DataSource getGcpDataSource() { + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(String.format("jdbc:postgresql:///%s", getDatabaseName())); + config.setUsername(getUsername()); + config.setPassword(getPassword()); + config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.postgres.SocketFactory"); + config.addDataSourceProperty("cloudSqlInstance", System.getenv("INSTANCE_CONNECTION_NAME")); + config.addDataSourceProperty("ipTypes", "PUBLIC,PRIVATE"); + return new HikariDataSource(config); + } +} diff --git a/src/main/java/com/hedera/exchange/database/GCPExchangeRateDB.java b/src/main/java/com/hedera/exchange/database/GCPExchangeRateDB.java deleted file mode 100644 index 1f1a5fe..0000000 --- a/src/main/java/com/hedera/exchange/database/GCPExchangeRateDB.java +++ /dev/null @@ -1,220 +0,0 @@ -package com.hedera.exchange.database; - -/*- - * ‌ - * Hedera Exchange Rate Tool - * ​ - * Copyright (C) 2019 - 2020 Hedera Hashgraph, LLC - * ​ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ‍ - * - * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos. - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -import com.google.cloud.spanner.*; -import com.hedera.exchange.ExchangeRate; - -public class GCPExchangeRateDB { - - // copy instance and db id from spanner website - private static final String projectId = "ert-public-test-1"; - private static final String instanceId = "ert-spanner-instance"; - private static final String databaseId = "ert_data"; - - public static void pushExchangeRate(ExchangeRate exchangeRate){ - // Instantiates a client - SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build(); - Spanner spanner = options.getService(); - try{ - // Creates a database client - DatabaseClient dbClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - - String sql = String.format("INSERT INTO ExchangeRate (ExpirationTime, ExchagneRateData) values ('{}', {})", - exchangeRate.getNextExpirationTimeInSeconds(), exchangeRate.toString()); - - dbClient.readWriteTransaction().run( - new TransactionRunner.TransactionCallable() { - @Override - public Void run(TransactionContext transaction) throws Exception { - long rowCount = transaction.executeUpdate(Statement.of(sql)); - System.out.printf("%d record inserted.\n", rowCount); - return null; - } - } - ); - - } - catch( Exception e ){ - System.out.println("Writing to DB failed : " + e.getMessage()); - } - finally { - spanner.close(); - } - } - - public static void pushMidnightExchangeRate(ExchangeRate exchangeRate){ - // Instantiates a client - SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build(); - Spanner spanner = options.getService(); - try{ - // Creates a database client - DatabaseClient dbClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - - String sql = String.format("INSERT INTO MidnightExchangeRate (ExpirationTime, ExchangeRateData) values ('{}', {})", - exchangeRate.getNextExpirationTimeInSeconds(), exchangeRate.toJson()); - - dbClient.readWriteTransaction().run( - new TransactionRunner.TransactionCallable() { - @Override - public Void run(TransactionContext transaction) throws Exception { - long rowCount = transaction.executeUpdate(Statement.of(sql)); - System.out.printf("%d record inserted.\n", rowCount); - return null; - } - } - ); - - } - catch( Exception e ){ - System.out.println("Writing to DB failed : " + e.getMessage()); - } - finally { - spanner.close(); - } - } - - // TODO build a DS to hold all the queries to exchanges and data they sent back - public static void pushQueriedExchangesData(){ - // Instantiates a client - SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build(); - Spanner spanner = options.getService(); - try{ - // Creates a database client - DatabaseClient dbClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - - String sql = String.format("INSERT INTO ExcahngesData (ExpirationTime, ExchangesData) values ('{}', {})", - "" , ""); - - dbClient.readWriteTransaction().run( - new TransactionRunner.TransactionCallable() { - @Override - public Void run(TransactionContext transaction) throws Exception { - long rowCount = transaction.executeUpdate(Statement.of(sql)); - System.out.printf("%d record inserted.\n", rowCount); - return null; - } - } - ); - - } - catch( Exception e ){ - System.out.println("Writing to DB failed : " + e.getMessage()); - } - finally { - spanner.close(); - } - } - - public static void getMidnightExchange(long expirationTime){ - // Instantiates a client - SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build(); - Spanner spanner = options.getService(); - try{ - // Creates a database client - DatabaseClient dbClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - - String sql = String.format("SELECT ExchangeRateData FROM MidnightExchangeRate where ExpirationTime = {}", - expirationTime); - - ResultSet resultSet = dbClient.singleUse().executeQuery(Statement.of(sql)); - - // TODO map the result set to exchange rate. - - } - catch( Exception e ){ - System.out.println("Writing to DB failed : " + e.getMessage()); - } - finally { - spanner.close(); - } - } - - - public static void main(){ - // copy instance and db id from spanner website - String projectId = "ert-public-test-1"; - String instanceId = "ert-spanner-instance"; - String databaseId = "ert_data"; - // Instantiates a client - SpannerOptions options = SpannerOptions.newBuilder().setProjectId(projectId).build(); - Spanner spanner = options.getService(); - - - try{ - // Creates a database client - DatabaseClient dbClient = spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId)); - - dbClient.readWriteTransaction().run( - new TransactionRunner.TransactionCallable() { - @Override - public Void run(TransactionContext transaction) throws Exception { - String sql = "INSERT INTO ExchangeRate (ExpirationTime, ExchagneRateData) " + - "values ('1567022400', '1,15,1567018800;1,14,1567022400')"; - long rowCount = transaction.executeUpdate(Statement.of(sql)); - System.out.printf("%d record inserted.\n", rowCount); - return null; - } - } - ); - - } - catch( Exception e ){ - System.out.println("Writing to DB failed : " + e.getMessage()); - } - finally { - spanner.close(); - } - } -} diff --git a/src/main/java/com/hedera/exchange/database/ExchangeRateAWSRD.java b/src/main/java/com/hedera/exchange/database/QueryHelper.java similarity index 76% rename from src/main/java/com/hedera/exchange/database/ExchangeRateAWSRD.java rename to src/main/java/com/hedera/exchange/database/QueryHelper.java index 9d4cd65..a1287d8 100644 --- a/src/main/java/com/hedera/exchange/database/ExchangeRateAWSRD.java +++ b/src/main/java/com/hedera/exchange/database/QueryHelper.java @@ -53,6 +53,7 @@ */ import com.hedera.exchange.ERTAddressBook; +import com.hedera.exchange.Environment; import com.hedera.exchange.ExchangeRate; import com.hedera.exchange.exchanges.Exchange; import org.apache.logging.log4j.LogManager; @@ -61,45 +62,53 @@ import java.io.IOException; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import static com.hedera.exchange.ExchangeRateTool.env; +import static com.hedera.exchange.database.DBParams.getEndpoint; +import static com.hedera.exchange.database.DBParams.getGcpDataSource; +import static com.hedera.exchange.database.DBParams.getPassword; +import static com.hedera.exchange.database.DBParams.getUsername; + /** - * This class implements the ExchangeDB interface using AWS RDS + * This class implements the ExchangeDB interface * which species what APIs that we need to fetch/push data into the Database. * * If you foresee doing more of this mapping, I would recommend moving to JPA/Hibernate. * */ -public class ExchangeRateAWSRD implements ExchangeDB { - - private static final Logger LOGGER = LogManager.getLogger(ExchangeRateAWSRD.class); +public class QueryHelper implements ExchangeDB { - private static final String LATEST_EXCHANGE_QUERY = "SELECT e1.expirationTime, e1.exchangeRateFile FROM exchange_rate AS e1 INNER JOIN (SELECT MAX(expirationTime) expirationTime FROM exchange_rate) AS e2 ON e1.expirationTime = e2.expirationTime LIMIT 1"; + private static final Logger LOGGER = LogManager.getLogger(QueryHelper.class); - private static final String LATEST_ADDRESSBOOK_QUERY = "SELECT e1.expirationTime, e1.addressBook FROM address_book AS e1 INNER JOIN (SELECT MAX(expirationTime) expirationTime FROM address_book) AS e2 ON e1.expirationTime = e2.expirationTime and networkName = ? LIMIT 1"; + private static final String LATEST_EXCHANGE_QUERY = "SELECT e1.expiration_time, e1.exchange_rate_file FROM exchange_rate AS e1 INNER JOIN (SELECT MAX(expiration_time) expiration_time FROM exchange_rate) AS e2 ON e1.expiration_time = e2.expiration_time LIMIT 1"; - private static final String MIDNIGHT_EXCHANGE_QUERY = "SELECT e1.expirationTime, e1.exchangeRateFile FROM midnight_rate AS e1 INNER JOIN (SELECT MAX(expirationTime) expirationTime FROM midnight_rate) AS e2 ON e1.expirationTime = e2.expirationTime LIMIT 1"; + private static final String LATEST_ADDRESS_BOOK_QUERY = "SELECT e1.expiration_time, e1.address_book FROM address_book AS e1 INNER JOIN (SELECT MAX(expiration_time) expiration_time FROM address_book) AS e2 ON e1.expiration_time = e2.expiration_time and network_name = ? LIMIT 1"; - private static final String LATEST_QUERIED_QUERY = "SELECT e1.expirationTime, e1.queriedrates FROM queried_rate AS e1 INNER JOIN (SELECT MAX(expirationTime) expirationTime FROM queried_rate) AS e2 ON e1.expirationTime = e2.expirationTime LIMIT 1"; + private static final String MIDNIGHT_EXCHANGE_QUERY = "SELECT e1.expiration_time, e1.exchange_rate_file FROM midnight_rate AS e1 INNER JOIN (SELECT MAX(expiration_time) expiration_time FROM midnight_rate) AS e2 ON e1.expiration_time = e2.expiration_time LIMIT 1"; - private final AWSDBParams params; + private static final String LATEST_QUERIED_QUERY = "SELECT e1.expiration_time, e1.queried_rates FROM queried_rates AS e1 INNER JOIN (SELECT MAX(expiration_time) expiration_time FROM queried_rates) AS e2 ON e1.expiration_time = e2.expiration_time LIMIT 1"; - public ExchangeRateAWSRD(final AWSDBParams params) { - this.params = params; + public QueryHelper() { this.migrate(); } private void migrate() { - final Flyway flyway = Flyway.configure() - .dataSource(this.params.getEndpoint(), - this.params.getUsername(), - this.params.getPassword()) - .baselineOnMigrate(true) - .load(); + final Flyway flyway; + if (env == Environment.AWS) { + flyway = Flyway.configure() + .dataSource(getEndpoint(), getUsername(), getPassword()) + .baselineOnMigrate(true) + .load(); + } else { + flyway = Flyway.configure() + .dataSource(getGcpDataSource()) + .baselineOnMigrate(true) + .load(); + } flyway.migrate(); } @@ -107,9 +116,9 @@ private void migrate() { public ExchangeRate getMidnightExchangeRate(long expirationTime) throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get the midnight exchange rate from midnight rate table " + "with nextExpiration time :{}", expirationTime); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement prepStatement = conn.prepareStatement( - "SELECT expirationTime, exchangeRateFile FROM midnight_rate where expirationTime = ?")){ + "SELECT expiration_time, exchange_rate_file FROM midnight_rate where expiration_time = ?")){ prepStatement.setLong(1, expirationTime); final ResultSet result = prepStatement.executeQuery(); if (result.next()) { @@ -125,8 +134,8 @@ public ExchangeRate getMidnightExchangeRate(long expirationTime) throws SQLExcep @Override public ERTAddressBook getLatestERTAddressBook(String networkName) throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get latest ERTAddressBook from address_book table"); - try (final Connection conn = getConnection(); - final PreparedStatement statement = conn.prepareStatement(LATEST_ADDRESSBOOK_QUERY)) { + try (final Connection conn = DBParams.getConnection(); + final PreparedStatement statement = conn.prepareStatement(LATEST_ADDRESS_BOOK_QUERY)) { statement.setString(1, networkName); LOGGER.info(Exchange.EXCHANGE_FILTER,"final query for addressbook : {}", statement.toString()); @@ -147,9 +156,9 @@ public void pushERTAddressBook(long expirationTime, ERTAddressBook ertAddressBoo String addressBook = ertAddressBook.toJson(); LOGGER.info(Exchange.EXCHANGE_FILTER, "push latest addressBook to address_book table : {}", addressBook); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement statement = conn.prepareStatement( - "INSERT INTO address_book (expirationTime,addressBook,networkName) VALUES(?,?::JSON,?)")) { + "INSERT INTO address_book (expiration_time, address_book, network_name) VALUES(?,?::JSON,?)")) { statement.setLong(1, expirationTime); statement.setObject(2, addressBook); statement.setString(3,networkName); @@ -160,7 +169,7 @@ public void pushERTAddressBook(long expirationTime, ERTAddressBook ertAddressBoo @Override public ExchangeRate getLatestExchangeRate() throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get latest exchange rate from exchange rate table"); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final Statement statement = conn.createStatement(); final ResultSet result = statement.executeQuery(LATEST_EXCHANGE_QUERY)) { if (result.next()) { @@ -176,9 +185,9 @@ public ExchangeRate getLatestExchangeRate() throws SQLException, IOException { public ExchangeRate getExchangeRate(long expirationTime) throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get the exchange rate from exchange rate table " + "with nextExpiration time :{}", expirationTime); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement prepStatement = conn.prepareStatement( - "SELECT expirationTime, exchangeRateFile FROM exchange_rate where expirationTime = ?")){ + "SELECT expiration_time, exchange_rate_file FROM exchange_rate where expiration_time = ?")){ prepStatement.setLong(1, expirationTime); final ResultSet result = prepStatement.executeQuery(); if (result.next()) { @@ -195,9 +204,9 @@ public ExchangeRate getExchangeRate(long expirationTime) throws SQLException, IO public String getQueriedRate(long expirationTime) throws SQLException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get the queried rate from queried rate table " + "with nextExpiration time :{}", expirationTime); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement prepStatement = conn.prepareStatement( - "SELECT expirationTime, queriedrates FROM queried_rate where expirationTime = ?")){ + "SELECT expiration_time, queried_rates FROM queried_rates where expiration_time = ?")){ prepStatement.setLong(1, expirationTime); final ResultSet result = prepStatement.executeQuery(); if (result.next()) { @@ -213,7 +222,7 @@ public String getQueriedRate(long expirationTime) throws SQLException { @Override public ExchangeRate getLatestMidnightExchangeRate() throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get midnight exchange rate from midnight rate table"); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final Statement statement = conn.createStatement(); final ResultSet result = statement.executeQuery(MIDNIGHT_EXCHANGE_QUERY)) { if (result.next()) { @@ -228,7 +237,7 @@ public ExchangeRate getLatestMidnightExchangeRate() throws SQLException, IOExcep @Override public String getLatestQueriedRate() throws SQLException { LOGGER.info(Exchange.EXCHANGE_FILTER, "query to get the latest queried rate"); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final Statement statement = conn.createStatement(); final ResultSet result = statement.executeQuery(LATEST_QUERIED_QUERY)) { if (result.next()) { @@ -244,9 +253,9 @@ public String getLatestQueriedRate() throws SQLException { public void pushExchangeRate(ExchangeRate exchangeRate) throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "push latest exchange rate to exchange rate table : {}", exchangeRate.toJson()); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement statement = conn.prepareStatement( - "INSERT INTO exchange_rate (expirationTime,exchangeRateFile) VALUES(?,?::JSON)")) { + "INSERT INTO exchange_rate (expiration_time, exchange_rate_file) VALUES(?,?::JSON)")) { statement.setLong(1, exchangeRate.getNextExpirationTimeInSeconds()); statement.setObject(2, exchangeRate.toJson()); statement.executeUpdate(); @@ -257,9 +266,9 @@ public void pushExchangeRate(ExchangeRate exchangeRate) throws SQLException, IOE public void pushMidnightRate(ExchangeRate exchangeRate) throws SQLException, IOException { LOGGER.info(Exchange.EXCHANGE_FILTER, "push the midnight exchange rate to midnight rate table : {}", exchangeRate.toJson()); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement statement = conn.prepareStatement( - "INSERT INTO midnight_rate (expirationTime,exchangeRateFile) VALUES(?,?::JSON)")) { + "INSERT INTO midnight_rate (expiration_time, exchange_rate_file) VALUES(?,?::JSON)")) { statement.setLong(1, exchangeRate.getNextExpirationTimeInSeconds()); statement.setObject(2, exchangeRate.toJson()); statement.executeUpdate(); @@ -270,21 +279,13 @@ public void pushMidnightRate(ExchangeRate exchangeRate) throws SQLException, IOE public void pushQueriedRate(long expirationTime, String queriedRate) throws SQLException { LOGGER.info(Exchange.EXCHANGE_FILTER, "push the queried exchanges to queried rate table : {}:{}", expirationTime, queriedRate); - try (final Connection conn = getConnection(); + try (final Connection conn = DBParams.getConnection(); final PreparedStatement statement = conn.prepareStatement( - "INSERT INTO queried_rate (expirationTime,queriedrates) VALUES(?,?::JSON)")) { + "INSERT INTO queried_rates (expiration_time, queried_rates) VALUES(?,?::JSON)")) { statement.setLong(1, expirationTime); statement.setObject(2, queriedRate); statement.executeUpdate(); } } - private Connection getConnection() throws SQLException { - final String endpoint = this.params.getEndpoint(); - LOGGER.info(Exchange.EXCHANGE_FILTER, "Connecting to endpoint: {}", endpoint); - return DriverManager.getConnection(endpoint, - this.params.getUsername(), - this.params.getPassword()); - } - } diff --git a/src/main/resources/config.json.All b/src/main/resources/config.json.All new file mode 100644 index 0000000..9157e9d --- /dev/null +++ b/src/main/resources/config.json.All @@ -0,0 +1,76 @@ +{ + "exchanges": { + "bitrex": "https://api.bittrex.com/api/v1.1/public/getmarketsummary?market=USD-HBAR", + "liquid": "https://api.liquid.com/products/741", + "coinbase": "https://api.coinbase.com/v2/exchange-rates?currency=HBAR", + "okcoin": "https://www.okcoin.com/api/spot/v3/instruments/HBAR-USD/ticker", + "binance": "https://api.binance.us/api/v3/ticker/24hr?symbol=HBARUSD", + "gate": "https://api.gateio.ws/api/v4/spot/tickers?currency_pair=HBAR_USDT", + "bitmart": "https://api-cloud.bitmart.com/contract/v1/tickers?contract_symbol=HBARUSDT", + "bittrue": "https://openapi.bitrue.com/api/v1/ticker/24hr?symbol=HBARUSDT", + "hitbit": "https://api.hitbtc.com/api/3/public/ticker/HBARUSDT", + "huobi" : "https://api.huobi.pro/market/detail?symbol=hbarusdt", + "upbit": "https://api.upbit.com/v1/ticker?markets=USD-HBAR", + "paybito": "https://stream.paybito.com:8443/SocketStream/api/get24hTicker?counter=HBAR&base=USD" + }, + "defaultCentEquiv" : 360000, + "defaultHbarEquiv": 30000, + "frequencyInSeconds" : 3600, + "floorCentsPerHbar": 0, + "fileId": "0.0.112", + "maxTransactionFee": 10000000, + "exchangeRateAllowedPercentage": "25", + "operatorId": "0.0.57", + "Networks": { + "mainnet": { + "0.0.3": "35.237.200.180:50211", + "0.0.4": "35.186.191.247:50211", + "0.0.5": "35.192.2.25:50211", + "0.0.6": "35.199.161.108:50211" + }, + "testnetstable": { + "0.0.3": "0.testnet.hedera.com:50211", + "0.0.4": "1.testnet.hedera.com:50211" + }, + "previewNet": { + "0.0.3": "35.231.208.148:50211", + "0.0.4": "35.199.15.177:50211", + "0.0.5": "35.225.201.195:50211" + }, + "integrationNet": { + "0.0.3": "34.74.191.8:50211", + "0.0.4": "35.245.150.69:50211", + "0.0.5": "34.70.193.123:50211" + }, + "performanceNet": { + "0.0.3": "34.67.136.38:50211", + "0.0.6": "34.83.73.160:50211", + "0.0.7": "34.94.104.178:50211", + "0.0.8": "35.203.2.132:50211" + }, + "performance2testNet": { + "0.0.3": "34.71.110.128:50211", + "0.0.4": "34.75.170.122:50211", + "0.0.5": "34.101.241.32:50211", + "0.0.6": "35.203.2.132:50211" + }, + "stagingNetSmall": { + "0.0.3": "104.196.48.231:50211", + "0.0.8": "35.203.26.115:50211", + "0.0.9": "34.77.3.213:50211" + }, + "stagingNetLarge": { + "0.0.3":"35.237.208.135:50211", + "0.0.4":"35.236.222.232:50211", + "0.0.5":"34.68.193.194:50211" + }, + "devnetdevopstest": { + "0.0.3":"35.196.138.70:50211", + "0.0.4":"35.236.198.2:50211", + "0.0.5":"34.68.119.250:50211" + } + }, + "payerAccount": "0.0.57", + "region": "us-central1", + "validationDelayInMilliseconds": 10000 +} \ No newline at end of file diff --git a/src/main/resources/config.json.devnetdevopstest b/src/main/resources/config.json.devnetdevopstest new file mode 100644 index 0000000..2a9be26 --- /dev/null +++ b/src/main/resources/config.json.devnetdevopstest @@ -0,0 +1,34 @@ +{ + "exchanges": { + "bitrex": "https://api.bittrex.com/api/v1.1/public/getmarketsummary?market=USD-HBAR", + "liquid": "https://api.liquid.com/products/741", + "coinbase": "https://api.coinbase.com/v2/exchange-rates?currency=HBAR", + "okcoin": "https://www.okcoin.com/api/spot/v3/instruments/HBAR-USD/ticker", + "binance": "https://api.binance.us/api/v3/ticker/24hr?symbol=HBARUSD", + "gate": "https://api.gateio.ws/api/v4/spot/tickers?currency_pair=HBAR_USDT", + "bitmart": "https://api-cloud.bitmart.com/contract/v1/tickers?contract_symbol=HBARUSDT", + "bittrue": "https://openapi.bitrue.com/api/v1/ticker/24hr?symbol=HBARUSDT", + "hitbit": "https://api.hitbtc.com/api/3/public/ticker/HBARUSDT", + "huobi" : "https://api.huobi.pro/market/detail?symbol=hbarusdt", + "upbit": "https://api.upbit.com/v1/ticker?markets=USD-HBAR", + "paybito": "https://stream.paybito.com:8443/SocketStream/api/get24hTicker?counter=HBAR&base=USD" + }, + "defaultCentEquiv" : 360000, + "defaultHbarEquiv": 30000, + "frequencyInSeconds" : 3600, + "floorCentsPerHbar": 0, + "fileId": "0.0.112", + "maxTransactionFee": 10000000, + "exchangeRateAllowedPercentage": "25", + "operatorId": "0.0.57", + "Networks": { + "devnetdevopstest": { + "0.0.3":"35.196.138.70:50211", + "0.0.4":"35.236.198.2:50211", + "0.0.5":"34.68.119.250:50211" + } + }, + "payerAccount": "0.0.57", + "region": "us-central1", + "validationDelayInMilliseconds": 10000 +} \ No newline at end of file diff --git a/src/main/resources/config.json.mainnet b/src/main/resources/config.json.mainnet new file mode 100644 index 0000000..35e871a --- /dev/null +++ b/src/main/resources/config.json.mainnet @@ -0,0 +1,35 @@ +{ + "exchanges": { + "bitrex": "https://api.bittrex.com/api/v1.1/public/getmarketsummary?market=USD-HBAR", + "liquid": "https://api.liquid.com/products/741", + "coinbase": "https://api.coinbase.com/v2/exchange-rates?currency=HBAR", + "okcoin": "https://www.okcoin.com/api/spot/v3/instruments/HBAR-USD/ticker", + "binance": "https://api.binance.us/api/v3/ticker/24hr?symbol=HBARUSD", + "gate": "https://api.gateio.ws/api/v4/spot/tickers?currency_pair=HBAR_USDT", + "bitmart": "https://api-cloud.bitmart.com/contract/v1/tickers?contract_symbol=HBARUSDT", + "bittrue": "https://openapi.bitrue.com/api/v1/ticker/24hr?symbol=HBARUSDT", + "hitbit": "https://api.hitbtc.com/api/3/public/ticker/HBARUSDT", + "huobi" : "https://api.huobi.pro/market/detail?symbol=hbarusdt", + "upbit": "https://api.upbit.com/v1/ticker?markets=USD-HBAR", + "paybito": "https://stream.paybito.com:8443/SocketStream/api/get24hTicker?counter=HBAR&base=USD" + }, + "defaultCentEquiv" : 360000, + "defaultHbarEquiv": 30000, + "frequencyInSeconds" : 3600, + "floorCentsPerHbar": 0, + "fileId": "0.0.112", + "maxTransactionFee": 10000000, + "exchangeRateAllowedPercentage": "25", + "operatorId": "0.0.57", + "Networks": { + "mainnet": { + "0.0.3": "35.237.200.180:50211", + "0.0.4": "35.186.191.247:50211", + "0.0.5": "35.192.2.25:50211", + "0.0.6": "35.199.161.108:50211" + } + }, + "payerAccount": "0.0.57", + "region": "us-central1", + "validationDelayInMilliseconds": 10000 +} \ No newline at end of file diff --git a/src/main/resources/config.json.testnet b/src/main/resources/config.json.testnet new file mode 100644 index 0000000..85901ce --- /dev/null +++ b/src/main/resources/config.json.testnet @@ -0,0 +1,31 @@ +{ + "exchanges": { + "bitrex": "https://api.bittrex.com/api/v1.1/public/getmarketsummary?market=USD-HBAR", + "liquid": "https://api.liquid.com/products/741", + "coinbase": "https://api.coinbase.com/v2/exchange-rates?currency=HBAR", + "okcoin": "https://www.okcoin.com/api/spot/v3/instruments/HBAR-USD/ticker", + "binance": "https://api.binance.us/api/v3/ticker/24hr?symbol=HBARUSD", + "gate": "https://api.gateio.ws/api/v4/spot/tickers?currency_pair=HBAR_USDT", + "bitmart": "https://api-cloud.bitmart.com/contract/v1/tickers?contract_symbol=HBARUSDT", + "bittrue": "https://openapi.bitrue.com/api/v1/ticker/24hr?symbol=HBARUSDT", + "hitbit": "https://api.hitbtc.com/api/3/public/ticker/HBARUSDT", + "huobi" : "https://api.huobi.pro/market/detail?symbol=hbarusdt" + }, + "defaultCentEquiv" : 360000, + "defaultHbarEquiv": 30000, + "frequencyInSeconds" : 3600, + "floorCentsPerHbar": 0, + "fileId": "0.0.112", + "maxTransactionFee": 10000000, + "exchangeRateAllowedPercentage": "25", + "operatorId": "0.0.57", + "Networks": { + "publicTestNet": { + "0.0.3": "0.testnet.hedera.com:50211", + "0.0.4": "1.testnet.hedera.com:50211" + } + }, + "payerAccount": "0.0.57", + "region": "us-central1", + "validationDelayInMilliseconds": 10000 +} diff --git a/src/main/resources/configIntegration.json b/src/main/resources/configIntegration.json index 101b4ab..5662a46 100644 --- a/src/main/resources/configIntegration.json +++ b/src/main/resources/configIntegration.json @@ -18,6 +18,12 @@ "Nodes": { "0.0.3": "35.196.146.2:50211" }, + "Networks": { + "integrationNet": { + "0.0.4": "35.245.150.69:50211", + "0.0.5": "34.70.193.123:50211" + } + }, "payerAccount": "0.0.57" }