Commit 6de5665d authored by jianhua.zhang's avatar jianhua.zhang

合约校验接口功能开发

parent 367fbe7b
package com.wuban.tron.explore.controller;
import com.wuban.tron.explore.entity.Contract;
import com.wuban.tron.explore.entity.example.ContractExample;
import com.wuban.tron.explore.param.request.ContractRequest;
import com.wuban.tron.explore.service.ContractComplierService;
import com.wuban.tron.explore.service.ContractService;
import com.wuban.tron.explore.service.TronService;
import com.wuban.tron.explore.util.ApiResponse;
import com.wuban.tron.explore.util.BizExceptionEnum;
import com.wuban.tron.explore.util.ResponseKit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
* <core>合约校验API接口</core>
*
* @author sky
* @date 2020/11/30
*/
@Slf4j
@RestController
@RequestMapping("/api/explorer/v1/")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ContractController {
private final ContractService contractService;
private final TronService tronService;
private final ContractComplierService contractComplierService;
@RequestMapping(value="compileSolidity", method = RequestMethod.POST)
public ApiResponse checkContract(@RequestBody @Valid ContractRequest reqParam) {
String address = reqParam.getAddress();
if (StringUtils.isEmpty(address)) {
return ResponseKit.fail(BizExceptionEnum.REQUEST_NULL.getCode(),BizExceptionEnum.REQUEST_NULL.getMessage());
}
/*
按照合约地址查询DB中是否存在此合约,如果不存在,调用链上接口API
*/
ContractExample example = new ContractExample();
example.createCriteria().andContractAddressEqualTo(address);
Contract con = this.contractService.selectOneByExample(example);
if (con != null) {
return ResponseKit.success(con);
}
// 调用链上接口API
Contract contract = this.tronService.getContract(address);
if (contract == null) {
return ResponseKit.fail(BizExceptionEnum.SERVER_ERROR.getCode(),BizExceptionEnum.SERVER_ERROR.getMessage());
}
// 编译合约
String code = this.contractComplierService.complier(reqParam.getName(), reqParam.getValue(), reqParam.getCompiler());
// 校验btyecode是否一致,不一致返回,一致持久化
if (!contract.getBytecode().equals(code)) {
return ResponseKit.fail(BizExceptionEnum.SERVER_ERROR.getCode(),BizExceptionEnum.SERVER_ERROR.getMessage());
}
this.contractService.insert(contract);
return ResponseKit.success();
}
}
......@@ -45,6 +45,7 @@ import java.util.List;
@RestController
@RequestMapping("/api/tron")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Deprecated
public class TransactionController {
private final TransactionService transactionService;
......
package com.wuban.tron.explore.dao;
import com.wuban.tron.explore.entity.Contract;
import com.wuban.tron.explore.entity.example.ContractExample;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
/**
* <core>合约DAO</core>
*
* @author sky
* @date 2020/11/30
*/
@Repository
public interface ContractRepository {
/**
* 添加合约信息
*
* @param record
* @return
*/
int insert(@Param("record") Contract record);
/**
* 查询合约信息
*
* @param example 检索条件
* @return
*/
Contract selectOneByExample(@Param("example") ContractExample example);
}
......@@ -2,6 +2,12 @@ package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>权限MODEL</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class Keys {
private String address;
......
......@@ -13,7 +13,7 @@ import java.util.List;
@Data
public class TransactionsRawData {
private List<Contract> contract;
private List<TronContract> contract;
private String ref_block_bytes;
private String ref_block_hash;
private Long expiration;
......
......@@ -9,7 +9,7 @@ import lombok.Data;
* @date 2020/11/02
*/
@Data
public class Contract {
public class TronContract {
private ContractParameter parameter;
private String type;
......
package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>合约事件</core>
*
* @author sky
* @date 2020/11/30
*/
@Data
public class TronTransEvent {
private String caller_contract_address;
private TronTransEventResult result;
private String transaction_id;
private TronTransEventResultType result_type;
private long block_timestamp;
private int block_number;
private String event_name;
private String contract_address;
private int event_index;
}
package com.wuban.tron.explore.domain;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* <core>合约事件结果</core>
*
* @author sky
* @date 2020/11/30
*/
@Data
public class TronTransEventResult {
@JsonProperty(value="0")
private String _$0;
@JsonProperty(value="1")
private String _$1;
@JsonProperty(value="2")
private String _$2;
@JsonProperty(value="3")
private String _$3;
@JsonProperty(value="4")
private String _$4;
@JsonProperty(value="5")
private String _$5;
@JsonProperty(value="6")
private String _$6;
@JsonProperty(value="7")
private String _$7;
@JsonProperty(value="8")
private String _$8;
@JsonProperty(value="9")
private String _$9;
@JsonProperty(value="10")
private String _$10;
private String callContractAddr;
private String amount;
private String marketIdx;
private String userAddr;
}
package com.wuban.tron.explore.domain;
import lombok.Data;
/**
* <core>合约事件结果类型</core>
*
* @author sky
* @date 2020/11/30
*/
@Data
public class TronTransEventResultType {
private String callContractAddr;
private String amount;
private String marketIdx;
private String userAddr;
}
package com.wuban.tron.explore.entity;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* 合约表
* @author sky
* @date 2020-11-30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Contract {
/**
*
*/
private Long id;
/**
*
*/
private String bytecode;
/**
* 名称
*/
private String name;
/**
*
*/
private String originAddress;
/**
*
*/
private String abi;
/**
*
*/
private Long originEnergyLimit;
/**
* 合约地址
*/
private String contractAddress;
/**
*
*/
private String codeHash;
public static Contract getInstance() {
return Contract.builder()
.id(0L)
.bytecode("")
.name("")
.originAddress("")
.abi("")
.originEnergyLimit(0L)
.contractAddress("")
.codeHash("")
.build();
}
}
\ No newline at end of file
package com.wuban.tron.explore.param.request;
import lombok.Data;
/**
* <core>合约校验请求参数</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
public class ContractRequest {
private String address;
private String name;
private String value;
private String version;
private String compiler;
private String optimization;
private String code;
private String parameters;
private String library;
private String runs;
private String evm_version;
private String license_type;
}
......@@ -3,6 +3,12 @@ package com.wuban.tron.explore.param.response;
import lombok.Builder;
import lombok.Data;
/**
* <core>账户信息MODEL</core>
*
* @author sky
* @date 2020/11/02
*/
@Data
@Builder
public class AccountInfoModel {
......
......@@ -27,21 +27,34 @@ public abstract class BaseCommonService {
protected static final String GET_BLOCK_BYNUM = PREFIX + "/getblockbynum";
/**
* 查询最新的几个块
* 查询最新的几个块API
*/
protected static final String GET_BLOCK_BYLATESTNUM = PREFIX + "/getblockbylatestnum";
/**
* 查询账户信息
* 查询账户信息API
*/
protected static final String GET_ACCOUNT = PREFIX + "/getaccount";
protected static final String FREEZE_BALANCE = "/wallet/freezebalance";
/**
* 事件日志API
*/
protected static final String CONTRACT_EVENT = "/event/contract/";
/**
* 获取合约API
*/
protected static final String GET_CONTRACT = "/wallet/getcontract";
@Value("${tron.site}")
private String tronSite;
@Value("${contract.complier.site}")
String contractComplierSite;
/**
* http请求
*
......@@ -76,17 +89,41 @@ public abstract class BaseCommonService {
}
/**
* 构建签名
* 构建请求体
*
* @param paramMap 请求参数
* @return Request
*/
protected Request builderPost(Map<String, Object> paramMap) {
String param = JSON.toJSONString(paramMap);
RequestBody postBody = RequestBody.create(param, Constant.JSON_TYPE);
return new Request.Builder().url(this.contractComplierSite).post(postBody)
.addHeader(Constant.CONTENT_TYPE_KEY, Constant.CONTENT_TYPE_VAL).build();
}
/**
* 构建请求体
*
* @param uri 合约方法名称
* @param paramMap 请求参数
* @return Request
*/
protected Request builder(String uri, Map<String, Object> paramMap) {
protected Request builderPost(String uri, Map<String, Object> paramMap) {
String param = JSON.toJSONString(paramMap);
RequestBody postBody = RequestBody.create(param, Constant.JSON_TYPE);
return new Request.Builder().url(this.tronSite + uri).post(postBody)
.addHeader(Constant.CONTENT_TYPE_KEY, Constant.CONTENT_TYPE_VAL).build();
}
/**
* 构建请求体
*
* @param uri 合约方法名称
* @return Request
*/
protected Request builderGet(String uri) {
return new Request.Builder().url(this.tronSite + uri).get()
.addHeader(Constant.CONTENT_TYPE_KEY, Constant.CONTENT_TYPE_VAL).build();
}
}
package com.wuban.tron.explore.service;
/**
* <core>编译合约服务接口</core>
*
* @author sky
* @date 2020/11/30
*/
public interface ContractComplierService {
/**
* 编译合约
*
* @param name 名称
* @param value 合约内容
* @param complier solidity版本号
* @return
*/
String complier(String name, String value, String complier);
}
package com.wuban.tron.explore.service;
import com.wuban.tron.explore.entity.Contract;
import com.wuban.tron.explore.entity.example.ContractExample;
import org.apache.ibatis.annotations.Param;
/**
* <core>合约服务接口</core>
*
* @author sky
* @date 2020/11/30
*/
public interface ContractService {
/**
* 添加合约信息
*
* @param record
* @return
*/
int insert(@Param("record") Contract record);
/**
* 查询合约信息
*
* @param example 检索条件
* @return
*/
Contract selectOneByExample(@Param("example") ContractExample example);
}
package com.wuban.tron.explore.service;
import com.wuban.tron.explore.domain.TronAccount;
import com.wuban.tron.explore.domain.TronResponseArrayData;
import com.wuban.tron.explore.domain.TronResponseData;
import com.wuban.tron.explore.domain.*;
import com.wuban.tron.explore.entity.Contract;
import java.util.List;
/**
* <core>波场区块服务接口</core>
......@@ -36,4 +37,20 @@ public interface TronService {
*/
TronAccount getAccount(String address);
/**
* 根据合约地址获取事件信息
*
* @param address 合约地址
* @return
*/
List<TronTransEvent> getContractEvent(String address);
/**
* 根据合约地址获取合约信息
*
* @param address 合约地址
* @return
*/
Contract getContract(String address);
}
package com.wuban.tron.explore.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.wuban.tron.explore.service.BaseCommonService;
import com.wuban.tron.explore.service.ContractComplierService;
import com.wuban.tron.explore.util.ApiResponse;
import okhttp3.Request;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* <core>编译合约服务接口实现类</core>
*
* @author sky
* @date 2020/11/30
*/
@Service
public class ContractComplierServiceImpl extends BaseCommonService implements ContractComplierService {
@Override
public String complier(String name, String value, String complier) {
Map<String, Object> map = new HashMap<>(3);
map.put("name", name);
map.put("value", value);
map.put("complier", complier);
Request request = this.builderPost(map);
String str = this.execute(request);
if (StringUtils.isEmpty(str)) {
return null;
}
return (String) JSONObject.parseObject(str, ApiResponse.class).getData();
}
}
package com.wuban.tron.explore.service.impl;
import com.wuban.tron.explore.dao.ContractRepository;
import com.wuban.tron.explore.entity.Contract;
import com.wuban.tron.explore.entity.example.ContractExample;
import com.wuban.tron.explore.service.ContractService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* <core>合约服务接口实现类</core>
*
* @author sky
* @date 2020/11/30
*/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ContractServiceImpl implements ContractService {
private final ContractRepository contractRepository;
/**
* 添加合约信息
*
* @param record
* @return
*/
@Override
public int insert(Contract record) {
return this.contractRepository.insert(record);
}
/**
* 查询合约信息
*
* @param example 检索条件
* @return
*/
@Override
public Contract selectOneByExample(ContractExample example) {
return this.contractRepository.selectOneByExample(example);
}
}
......@@ -223,7 +223,7 @@ public class TransactionServiceImpl implements TransactionService {
List<Transaction> retList = new ArrayList<>(transactionsList.size());
transactionsList.forEach(o -> {
TransactionsRawData rawData = o.getRaw_data();
Contract contract = rawData.getContract().get(0);
TronContract contract = rawData.getContract().get(0);
ContractParameter contractParameter = contract.getParameter();
ContractParameterValue val = contractParameter.getValue();
......
package com.wuban.tron.explore.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wuban.tron.explore.constant.Constant;
import com.wuban.tron.explore.domain.TronAccount;
import com.wuban.tron.explore.domain.TronResponseArrayData;
import com.wuban.tron.explore.domain.TronResponseData;
import com.wuban.tron.explore.domain.*;
import com.wuban.tron.explore.entity.Contract;
import com.wuban.tron.explore.service.BaseCommonService;
import com.wuban.tron.explore.service.TronService;
import lombok.extern.slf4j.Slf4j;
......@@ -15,6 +15,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
......@@ -56,7 +57,7 @@ public class TronServiceImpl extends BaseCommonService implements TronService {
Map<String, Object> map = new HashMap<>(1);
map.put("num", param);
Request request = this.builder(interfaceName, map);
Request request = this.builderPost(interfaceName, map);
String str = this.execute(request);
return str;
}
......@@ -71,7 +72,7 @@ public class TronServiceImpl extends BaseCommonService implements TronService {
Map<String, Object> map = new HashMap<>(1);
map.put("address", address);
Request request = this.builder(GET_ACCOUNT, map);
Request request = this.builderPost(GET_ACCOUNT, map);
String str = this.execute(request);
if (StringUtils.isEmpty(str)) {
this.stringRedisTemplate.opsForSet().add(Constant.ADDRESS_KEY, address);
......@@ -82,5 +83,65 @@ public class TronServiceImpl extends BaseCommonService implements TronService {
return JSONObject.parseObject(str, TronAccount.class);
}
@Override
public List<TronTransEvent> getContractEvent(String address) {
Request request = this.builderGet(CONTRACT_EVENT + address);
String str = this.execute(request);
if (StringUtils.isEmpty(str)) {
return null;
}
System.out.println("处理前:》》》》》"+str);
String ret = clearData(str);
System.out.println("处理后:》》》》》"+ret);
return JSONArray.parseArray(ret, TronTransEvent.class);
}
@Override
public Contract getContract(String address) {
Map<String, Object> map = new HashMap<>(1);
map.put("value", address);
Request request = this.builderPost(GET_CONTRACT, map);
String str = this.execute(request);
if (StringUtils.isEmpty(str)) {
return null;
}
return JSONObject.parseObject(str, Contract.class);
}
/**
* 数据清洗
*
* 清洗前:
* "1":"2",
* "2":"0x67c62732f1f6086a98310aa5c83163977394f92e",
* "3":"0x4f948b55157ed879a2b6863c22a4e31d28ceebb7",
* "4":"300000000",
* "5":"285000000",
* "6":"15000000",
* 清洗后:
* "_$1":"2",
* "_$2":"0x67c62732f1f6086a98310aa5c83163977394f92e",
* "_$3":"0x4f948b55157ed879a2b6863c22a4e31d28ceebb7",
* "_$4":"300000000",
* "_$5":"285000000",
* "_$6":"15000000",
* @param data
* @return
*/
private String clearData(String data) {
int range = 10;
String ret = data;
String regex = "\":";
for (int i = 0; i < range; i++) {
String tmp = i+regex;
ret = ret.replaceAll(tmp, "_\\$"+i+"\":");
}
return ret;
}
}
package com.wuban.tron.explore.util;
/**
* @author sky
*
**/
public enum BizExceptionEnum {
/**
* 通用异常.
*/
SERVER_ERROR(1000, "服务器异常"),
REQUEST_NULL(1001, "请求参数有错误"),
SESSION_TIMEOUT(1002, "会话超时"),
PARAM_INVALID(1003,"参数无效"),
PARAM_MISS(1004,"参数丢失"),
METHOD_NOT_ALLOWED(1005, "不支持当前请求类型"),
SQL_EX(1006, "运行SQL出现异常");
BizExceptionEnum(int code, String message) {
this.code = code;
this.message = message;
}
private Integer code;
private String message;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
......@@ -3,6 +3,10 @@
tron:
site: https://api.shasta.trongrid.io
contract:
complier:
site: http://47.115.200.174:8080/api/explorer/v1/compileSolidity
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
......
......@@ -3,6 +3,10 @@
tron:
site: https://api.shasta.trongrid.io
contract:
complier:
site: http://47.115.200.174:8080/api/explorer/v1/compileSolidity
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
......
This diff is collapsed.
package com.wuban.tron.explore.service.impl;
import com.wuban.tron.explore.BaseTest;
import com.wuban.tron.explore.service.ContractComplierService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
class ContractComplierServiceImplTest extends BaseTest {
@Autowired
private ContractComplierService contractComplierService;
@BeforeEach
void setUp() {
}
@Test
void complier() {
String name = "Storage2";
String complier = "solidity0.4.25+commit";
String value = "pragma solidity ^0.4.25;\n" +
"\n" +
"contract Storage2 {\n" +
" uint pos0;\n" +
" mapping(address => uint) pos1;\n" +
"\n" +
" function Storage2() {\n" +
" pos0 = 12334;\n" +
" pos1[msg.sender] = 56278;\n" +
" }\n" +
" \n" +
" function Hello() public returns (string hel) {\n" +
" return \"Hello\";\n" +
" }\n" +
" \n" +
" function GetInt() public returns (uint data) {\n" +
" return pos0;\n" +
" }\n" +
" \n" +
" function SetInt(uint val) public {\n" +
" pos0 = val;\n" +
" }\n" +
"}";
String str = this.contractComplierService.complier(name, value, complier);
System.out.println("*************"+str);
}
}
\ No newline at end of file
package com.wuban.tron.explore.service.impl;
import com.wuban.tron.explore.domain.TronAccount;
import com.wuban.tron.explore.domain.TronResponseArrayData;
import com.wuban.tron.explore.domain.TronResponseData;
import com.wuban.tron.explore.domain.*;
import com.wuban.tron.explore.service.TronService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
......@@ -13,6 +11,8 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.tron.common.utils.ByteArray;
import org.tron.walletserver.WalletApi;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
......@@ -46,5 +46,19 @@ class TronServiceImplTest {
log.info(hexString);
}
@Test
void getContractEvent() {
List<TronTransEvent> data = this.tronService.getContractEvent("TMypW2w7P2y8QzV8i9BAE31yzQukp63tbo");
System.out.println(data);
}
@Test
void getContract() {
String base58check = "TTfwGdf3v66CaYQijg4Qb2CFtdgQnkkFko";
String hexString = ByteArray.toHexString(WalletApi.decodeFromBase58Check(base58check));
System.out.println(hexString);
this.tronService.getContract(hexString);
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment