Skip to content

Commit

Permalink
Merge pull request #12 from just-defi/update_SendRequest
Browse files Browse the repository at this point in the history
update SendRequest to CheckDeviation
  • Loading branch information
running-tomato authored Dec 15, 2020
2 parents 8884371 + f4b3c27 commit 786549d
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
build/
logs/
key.store
deviation.yml

node/HELP.md
node/.gradle
Expand Down
1 change: 1 addition & 0 deletions node/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,6 @@ def binaryRelease(taskName, jarName, mainClass) {

artifacts {
archives(binaryRelease('buildUserNodeJar', 'UserNode', 'com.tron.user.SendRequest'),
binaryRelease('buildCheckDeviationJar', 'CheckDeviation', 'com.tron.user.CheckDeviation'),
binaryRelease('buildOracleJar', 'OracleNode', 'com.tron.OracleApplication'))
}
226 changes: 226 additions & 0 deletions node/src/main/java/com/tron/user/CheckDeviation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package com.tron.user;

import static com.tron.common.Constant.FULLNODE_HOST;
import static com.tron.common.Constant.READONLY_ACCOUNT;
import static com.tron.common.Constant.TRIGGET_CONSTANT_CONTRACT;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.internal.Lists;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.AtomicLongMap;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tron.client.message.BroadCastResponse;
import com.tron.common.util.AbiUtil;
import com.tron.common.util.HttpUtil;
import com.tron.common.util.Tool;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.util.EntityUtils;
import org.tron.common.crypto.ECKey;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.StringUtil;

@Slf4j
public class CheckDeviation {

private static DeviationConfig config = null;
private static ECKey key;
private static long DEVIATION = 10;
private static Map<String, Long> deviationMap = new HashMap<>();
private static Map<String, Long> forceRequestTime = new HashMap<>();

public static void main(String[] args) {
Args argv = new Args();
JCommander jct = JCommander.newBuilder()
.addObject(argv)
.build();
jct.setProgramName("Deviation check");
jct.setAcceptUnknownOptions(true);
jct.parse(args);
if (Strings.isNullOrEmpty(argv.config)) {
throw new RuntimeException("config file cannot be null");
}
try {
config = DeviationConfig.loadConfig(argv.config);
key = ECKey.fromPrivate(ByteArray.fromHexString(config.getPrivateKey()));
run();
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
}
}

private static void run() {
setDeviation();
setForceRequestTime();
AtomicLongMap forceMap = AtomicLongMap.create();
while (true) {
for (PairInfo pairInfo: config.getPairs()) {
String contract = pairInfo.getContract();
long price = getAggPrice(pairInfo.getName());
if (price == 0) {
forceMap.addAndGet(contract, config.getSleep());
continue;
}
if (!compare(contract, price) && !mustForce(forceMap, contract)) {
forceMap.addAndGet(contract, config.getSleep());
} else {
sendRequest(contract);
log.info("send request");
forceMap.remove(contract);
}
sleep(100); // for slow down the http qps
}
sleep(config.getSleep());
}
}

private static long getAggPrice(String pair) {
List<String> jobs = config.getJobs().get(pair);
if (jobs == null) {
log.error("can not get jobUrls, pair: {}", pair);
throw new RuntimeException("can get jobUrls");
}
List<Long> priceList = Lists.newArrayList();
for (int i = 0; i < jobs.size(); i++) {
Map<String, Object> server = config.getNodeServer().get(i);
priceList.add(getPrice(
String.format("http://%s:%d/job/result/%s",
server.get("host"), server.get("port"), jobs.get(i))
));
}
Long[] priceArr = priceList.toArray(new Long[priceList.size()]);
Arrays.sort(priceArr);
log.info("pair: {}, price: {}", pair, priceArr);
return priceArr[priceArr.length/2];
}

private static long getPrice(String jobUrl) {
long price = 0;
try {
HttpResponse response = HttpUtil.getByUri(jobUrl);
if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
String result = EntityUtils.toString(response.getEntity());
JsonObject data = (JsonObject) JsonParser.parseString(result);
return data.getAsJsonPrimitive("data").getAsLong();
} else {
log.error("[alarm]getPrice fail. job="+jobUrl);
}
} catch (Exception e) {
e.printStackTrace();
}
return price;
}

private static void sendRequest(String contract) {
try {
Map<String, Object> params = Maps.newHashMap();
params.put("owner_address", StringUtil.encode58Check(key.getAddress()));
params.put("contract_address", contract);
params.put("function_selector", "requestRateUpdate()");
params.put("parameter", "");
params.put("fee_limit", config.getFeelimit().toString());
params.put("call_value", 0);
params.put("visible", true);
BroadCastResponse rps = Tool.triggerContract(key, params, config.getFullnode());
if (rps != null) {
log.info("trigger " + contract + " Contract result is: " + rps.isResult()
+ ", msg is: " + rps.getMessage());
}
} catch (Throwable e) {
e.printStackTrace();
}
}

private static long getPriceFromContract(String contract) throws IOException {
String param = AbiUtil.parseParameters("latestAnswer()", "");
Map<String, Object> params = Maps.newHashMap();
params.put("owner_address", READONLY_ACCOUNT);
params.put("contract_address", contract);
params.put("function_selector", "latestAnswer()");
params.put("parameter", param);
params.put("visible", true);
HttpResponse response = HttpUtil.post(
"https", FULLNODE_HOST, TRIGGET_CONSTANT_CONTRACT, params);
ObjectMapper mapper = new ObjectMapper();
assert response != null;
Map<String, Object> result = mapper.readValue(EntityUtils.toString(response.getEntity()), Map.class);
return Optional.ofNullable((List<String>)result.get("constant_result"))
.map(constantResult -> constantResult.get(0))
.map(str-> str.replaceAll("^0[x|X]", ""))
.map(str -> Long.parseLong(str, 16))
.orElseThrow(() -> new IllegalArgumentException("can not get the price, contract:" + contract));
}

private static boolean compare(String contract, long nowPrice) {
try {
long prePrice = getPriceFromContract(contract);
log.info(contract +": " + prePrice + " " + nowPrice);
long sub = Math.abs(Math.subtractExact(prePrice, nowPrice));
Long deviation = deviationMap.get(contract);
deviation = deviation == null ? DEVIATION : deviation;
return Math.multiplyExact(sub, 1000) / prePrice >= deviation;
} catch (Exception e) {
e.printStackTrace();
}
return true;
}

private static void setDeviation() {
for (PairInfo pairInfo: config.getPairs()) {
deviationMap.put(pairInfo.getContract(), pairInfo.getDeviation());
}
}

private static void setForceRequestTime() {
for (PairInfo pairInfo: config.getPairs()) {
forceRequestTime.put(pairInfo.getContract(), pairInfo.getUpdateInterval());
}
}

private static boolean mustForce(AtomicLongMap forceMap, String contract) {
Long forceTime = forceRequestTime.get(contract);
if (forceTime == null) {
return true;
}
return forceMap.get(contract) >= forceTime;
}

private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

static class Args {
@Parameter(
names = {"--config", "-c"},
help = true,
description = "specify the config file",
order = 1)
private String config;
@Parameter(
names = "--help",
help = true,
order = 2)
private boolean help;
}
}



39 changes: 39 additions & 0 deletions node/src/main/java/com/tron/user/DeviationConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.tron.user;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.yaml.snakeyaml.Yaml;

@Data
public class DeviationConfig {

private long sleep;
private String fullnode;
private String privateKey;
private BigInteger feelimit;
private List<PairInfo> pairs;
private List<Map<String, Object>> nodeServer;
private Map<String, List<String>> jobs;

private static DeviationConfig config = null;

public static DeviationConfig loadConfig(String confPath) throws FileNotFoundException {
Yaml yaml = new Yaml();
InputStream inputStream = new FileInputStream(confPath);
config = yaml.loadAs(inputStream, DeviationConfig.class);
System.out.println(config);
return config;
}

public static DeviationConfig getConfig() {
if (config == null) {
throw new RuntimeException("config can not be null");
}
return config;
}
}
10 changes: 10 additions & 0 deletions node/src/main/java/com/tron/user/Job.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tron.user;

import lombok.Data;

@Data
public class Job {
private String host;
private int port;
private String job;
}
13 changes: 13 additions & 0 deletions node/src/main/java/com/tron/user/PairInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tron.user;

import lombok.Data;

@Data
public class PairInfo {
public PairInfo() {}

private String name;
private String contract;
private long deviation; // 1:1000
private long updateInterval; // ms
}
4 changes: 4 additions & 0 deletions node/src/main/java/com/tron/user/SendRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.StringUtil;

/**
* will be replaced by class {CheckDeviation}
*/
@Deprecated
public class SendRequest {

private static String SPLIT = ",";
Expand Down

0 comments on commit 786549d

Please sign in to comment.