diff --git a/.ci/check_rare_string.sh b/.ci/check_rare_string.sh new file mode 100644 index 000000000..fa2555b20 --- /dev/null +++ b/.ci/check_rare_string.sh @@ -0,0 +1,54 @@ +#!/bin/bash + + + +function LOG_ERROR() +{ + local content=${1} + echo -e "\033[31m"${content}"\033[0m" +} + +function LOG_INFO() +{ + local content=${1} + echo -e "\033[32m"${content}"\033[0m" +} + +get_md5sum_cmd() { + local md5sum_cmd="md5sum" + if [ "$(uname)" == "Darwin" ]; then + md5sum_cmd="md5" + fi + echo "$md5sum_cmd" +} + +function checkConcatenatedRareString() { + + concatenatedString=${1} + log_file=${2} + md5sum_cmd=$(get_md5sum_cmd) + + md5_concatenatedString=$(echo -n "$concatenatedString" | $md5sum_cmd | awk '{print $1}') + + # compare rare string and stringFromGet + get_output=$(cat ${log_file}| grep "result=" | awk -F '[][]' '{print $4}' | awk NF | tail -n 1) + md5_stringFromGet=$(echo -n "$get_output" | $md5sum_cmd | awk '{print $1}') + if [ "$md5_concatenatedString" != "$md5_stringFromGet" ]; then + LOG_ERROR "error: check failed, the md5 values of rareString and stringFromGet are not equal, fail concatenatedString: ${concatenatedString}, get_output: ${get_output}" + exit 1 + else + LOG_INFO "check success, concatenatedString: ${concatenatedString}" + fi +} + +main() { + concatenatedString=${1} + log_file=${2} + LOG_INFO "check rare string start, concatenatedString: ${concatenatedString}" + + checkConcatenatedRareString ${concatenatedString} ${log_file} + LOG_INFO "check rare string finished!" +} + +main "$@" + diff --git a/.ci/ci_cross_all_check.sh b/.ci/ci_cross_all_check.sh index 937bdc7c9..1a8390345 100644 --- a/.ci/ci_cross_all_check.sh +++ b/.ci/ci_cross_all_check.sh @@ -2,7 +2,9 @@ set -e ROOT=$(pwd)/demo/ +CI_PWD=$(pwd) PLUGIN_BRANCH=master +final_rare_input="" LOG_INFO() { local content=${1} @@ -14,6 +16,14 @@ LOG_ERROR() { echo -e "\033[31m[ERROR] ${content}\033[0m" } +prepare_rare_string() { + final_rare_input=$(bash ${CI_PWD}/.ci/gen_rare_string.sh) +} + +check_rare_string() { + bash ${CI_PWD}/.ci/check_rare_string.sh ${final_rare_input} ${ROOT}/WeCross-Console/logs/debug.log +} + check_log() { cd ${ROOT} error_log=routers-payment/127.0.0.1-8250-25500/logs/error.log @@ -62,6 +72,8 @@ demo_test() { ensure_bcos_nodes_running + prepare_rare_string + cd WeCross-Console/ bash start.sh < : certain tag or branch to download e.g - bash $0 v1.3.1 + bash $0 v1.4.0 EOF exit 0 } diff --git a/scripts/download_plugin.sh b/scripts/download_plugin.sh index 75c0f2b39..e8d0319f0 100644 --- a/scripts/download_plugin.sh +++ b/scripts/download_plugin.sh @@ -50,10 +50,10 @@ Usage: : certain tag or branch to download e.g - bash $0 BCOS2 v1.3.1 - bash $0 BCOS3 v1.3.1 - bash $0 Fabric1 v1.3.1 - bash $0 Fabric2 v1.3.1 + bash $0 BCOS2 v1.4.0 + bash $0 BCOS3 v1.4.0 + bash $0 Fabric1 v1.4.0 + bash $0 Fabric2 v1.4.0 EOF exit 0 } diff --git a/scripts/download_wecross.sh b/scripts/download_wecross.sh index e91169c31..ffe1ac226 100755 --- a/scripts/download_wecross.sh +++ b/scripts/download_wecross.sh @@ -6,7 +6,7 @@ LANG=en_US.UTF-8 enable_build_from_resource=0 compatibility_version= -default_compatibility_version=v1.3.1 # update this every release +default_compatibility_version=v1.4.0 # update this every release deps_dir=$(pwd)'/WeCross/plugin/' pages_dir=$(pwd)'/WeCross/pages/' src_dir=$(pwd)'/src/' diff --git a/scripts/light_monitor.sh b/scripts/light_monitor.sh new file mode 100755 index 000000000..15d398196 --- /dev/null +++ b/scripts/light_monitor.sh @@ -0,0 +1,129 @@ +#!/bin/bash +dirPath="$(cd "$(dirname "$0")" && pwd)" +cd "${dirPath}" || exit 1 + +# rpc ip +rpc_ip="" +# rpc 端口 +rpc_port="" +# +disk_dir="." + +# 磁盘容量告警阈值,默认剩余5%开始告警 +disk_space_threshold=95 +memory_free_threshold=5 + +alarm() { + echo "$1" + alert_msg="$1" + alert_ip=$(/sbin/ifconfig eth0 | grep inet | grep -v inet6 | awk '{print $2}') + alert_time=$(date "+%Y-%m-%d %H:%M:%S") + + # TODO: alarm the message, mail or phone + + echo "[${alert_time}]:[${alert_ip}]:${alert_msg}" +# | mail -s "fisco-bcos alarm message" 123456@me.com +} + +# echo message with time +info() { + time=$(date "+%Y-%m-%d %H:%M:%S") + echo "[$time] $1" +} + +error() { + echo -e "\033[31m $1 \033[0m" +} + +dir_must_exists() { + if [ ! -d "$1" ]; then + error "$1 DIR does not exist, please check!" + exit 1 + fi +} + +function check_disk() { + local dir="$1" + local disk_space_usage_percent + disk_space_usage_percent=$(df -h "${dir}" | grep /dev | awk -F" " '{print $5}' | cut -d"%" -f1) + # info "disk_space_left_percent: ${disk_space_left_percent}, disk_space_threshold:${disk_space_threshold}" + if [[ ${disk_space_threshold} -lt ${disk_space_usage_percent} ]]; then + alarm " ERROR! insufficient disk capacity, monitor disk directory: ${dir}, used disk space percent: ${disk_space_usage_percent}%" + return 1 + fi +} + +# check memory +function check_memory() { + local memory_free + memory_free=$(free -g | grep Mem | awk '{print $4}') + if [[ ${memory_free_threshold} -gt ${memory_free} ]]; then + alarm " ERROR! insufficient memory, free memory: ${memory_free}G" + return 1 + fi +} + +# check if nodeX is work well +function check_router_work_properly() { + local config_ip="${1}" + local config_port="${2}" + + local testResult + testResult=$(curl -s "http://$config_ip:$config_port/sys/test" -X GET) + [[ -z "$testResult" ]] && { + alarm " ERROR! Cannot connect to $config_ip:$config_port, method: sys/test" + return 1 + } +} + +function help() { + echo "Usage:" + echo "Optional:" + echo " -d [Optional] disk directory to be monitor" + echo " -i [Require] rpc server ip" + echo " -p [Require] rpc server port" + echo " -T [Optional] disk capacity alarm threshold, default: 5%" + echo " -f [Optional] memory free alarm threshold, default: 5G" + echo " -h Help." + echo "Example:" + echo " bash light_monitor.sh -i 127.0.0.1 -p 8250" + echo " bash light_monitor.sh -i 127.0.0.1 -p 8250 -d /data -T 10" + exit 0 +} + +function params_must_set() { + local name="$1" + local params="$2" + local flag="$3" + [[ -z "${params}" ]] && { + error "${name} must be set, you can use \'${flag}\' option to set it" + exit 1 + } +} + +while getopts "d:i:p:T:f:h" option; do + case $option in + d) + disk_dir=$OPTARG + dir_must_exists ${disk_dir} + ;; + i) rpc_ip=$OPTARG ;; + p) rpc_port=$OPTARG ;; + T) disk_space_threshold=$OPTARG ;; + f) memory_free_threshold=$OPTARG ;; + h) help ;; + *) help ;; + esac +done + +params_must_set "rpc ip" "${rpc_ip}" "-i" +params_must_set "rpc port" "${rpc_port}" "-p" + +# 磁盘容量检查 +if [ -n "${disk_dir}" ]; then + check_disk "${disk_dir}" +fi + +check_memory + +check_router_work_properly "${rpc_ip}" "${rpc_port}" diff --git a/src/main/java/com/webank/wecross/Generator.java b/src/main/java/com/webank/wecross/Generator.java index 8cd36fc4d..da2c4916b 100644 --- a/src/main/java/com/webank/wecross/Generator.java +++ b/src/main/java/com/webank/wecross/Generator.java @@ -3,6 +3,8 @@ import com.webank.wecross.config.StubManagerConfig; import com.webank.wecross.stub.StubFactory; import com.webank.wecross.stubmanager.StubManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -12,6 +14,7 @@ public class Generator { public static void main(String[] args) { context = new AnnotationConfigApplicationContext(StubManagerConfig.class); + Logger logger = LoggerFactory.getLogger(Generator.class); if (args.length < ARGS_LENGTH) { System.out.println("Usage: connection/account "); @@ -28,8 +31,10 @@ public static void main(String[] args) { StubFactory stubFactory = stubManager.getStubFactory(type); if (op.equals("connection")) { + logger.info("generateConnection: {}", path); stubFactory.generateConnection(path, new String[] {}); } else if (op.equals("account")) { + logger.info("generateAccount: {}", path); stubFactory.generateAccount(path, new String[] {}); } else { System.err.println("Unknown operation: " + op); diff --git a/src/main/java/com/webank/wecross/common/WeCrossDefault.java b/src/main/java/com/webank/wecross/common/WeCrossDefault.java index d826fd5fb..ef69b6e0a 100644 --- a/src/main/java/com/webank/wecross/common/WeCrossDefault.java +++ b/src/main/java/com/webank/wecross/common/WeCrossDefault.java @@ -4,7 +4,7 @@ import java.util.List; public class WeCrossDefault { - public static final String VERSION = "v1.3.1"; + public static final String VERSION = "v1.4.0"; public static final String TEMPLATE_URL = "http://127.0.0.1:8080/"; diff --git a/src/main/java/com/webank/wecross/interchain/InterchainDefault.java b/src/main/java/com/webank/wecross/interchain/InterchainDefault.java index 9324cd9e2..106d3b621 100644 --- a/src/main/java/com/webank/wecross/interchain/InterchainDefault.java +++ b/src/main/java/com/webank/wecross/interchain/InterchainDefault.java @@ -3,6 +3,7 @@ public class InterchainDefault { public static final int CALL_TYPE_QUERY = 0; public static final int CALL_TYPE_INVOKE = 1; + public static final int CALL_TYPE_GET_BLOCK = 2; public static final long TIMEOUT_DELAY = 10; public static final String SPLIT_REGEX = " "; diff --git a/src/main/java/com/webank/wecross/interchain/InterchainErrorCode.java b/src/main/java/com/webank/wecross/interchain/InterchainErrorCode.java index cf31c95a4..e569efe5f 100644 --- a/src/main/java/com/webank/wecross/interchain/InterchainErrorCode.java +++ b/src/main/java/com/webank/wecross/interchain/InterchainErrorCode.java @@ -6,4 +6,5 @@ public class InterchainErrorCode { public static final int CALL_TARGET_CHAIN_ERROR = 1003; public static final int CALL_CALLBACK_ERROR = 1004; public static final int REGISTER_CALLBACK_RESULT_ERROR = 1005; + public static final int GET_TARGET_CHAIN_BLOCK_ERROR = 1006; } diff --git a/src/main/java/com/webank/wecross/interchain/InterchainScheduler.java b/src/main/java/com/webank/wecross/interchain/InterchainScheduler.java index 097c06329..b1e05b8bb 100644 --- a/src/main/java/com/webank/wecross/interchain/InterchainScheduler.java +++ b/src/main/java/com/webank/wecross/interchain/InterchainScheduler.java @@ -2,6 +2,7 @@ import static com.webank.wecross.interchain.InterchainDefault.TIMEOUT_DELAY; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.webank.wecross.account.UniversalAccount; import com.webank.wecross.exception.WeCrossException; @@ -33,131 +34,199 @@ public interface InterchainCallback { } public void start(InterchainCallback callback) { - getXATransactionState( - (getTransactionStateException, xaTransactionID, xaTransactionSeq) -> { - if (Objects.nonNull(getTransactionStateException)) { - callback.onReturn(getTransactionStateException); - return; - } + if (interchainRequest.getCallType() == InterchainDefault.CALL_TYPE_GET_BLOCK) { + String realUid = + Sha256Utils.sha256String( + (systemResource.getHubResource() + interchainRequest.getUid()) + .getBytes(StandardCharsets.UTF_8)); + getTargetChainBlock( + ((callTargetChainException, block) -> { + boolean state = true; + String result; + try { + result = objectMapper.writeValueAsString(block); + } catch (JsonProcessingException ignored) { + result = "[]"; + } - if (logger.isDebugEnabled()) { - logger.debug( - "Transaction state, xaTransactionID: {}, xaTransactionSeq: {}, inter chain request: {}", - xaTransactionID, - xaTransactionSeq, - interchainRequest); - } + if (Objects.nonNull(callTargetChainException)) { + logger.error( + "Get target chain block failed, error code: {}, message: {}", + callTargetChainException.getInternalErrorCode(), + callTargetChainException.getInternalMessage()); - String realUid = - Sha256Utils.sha256String( - (systemResource.getHubResource() + interchainRequest.getUid()) - .getBytes(StandardCharsets.UTF_8)); - - long timestamp = System.currentTimeMillis(); - long callTargetChainSeq = - timestamp > xaTransactionSeq ? timestamp : (xaTransactionSeq + 1L); - callTargetChain( - realUid, - xaTransactionID, - callTargetChainSeq, - (callTargetChainException, callTargetChainResult) -> { - boolean state = true; - String result = callTargetChainResult; - - if (Objects.nonNull(callTargetChainException)) { - logger.error( - "Call target chain failed, error code: {}, message: {}", - callTargetChainException.getInternalErrorCode(), - callTargetChainException.getInternalMessage()); - - state = false; - result = "[]"; - } + state = false; + result = "[]"; + } + String finalResult = result; + callCallback( + realUid, + null, + 0, + state, + result, + (callCallbackException, errorCode, message, callCallbackResult) -> { + if (Objects.nonNull(callCallbackException)) { + /* exception occurred, no need to register result */ + callback.onReturn(callCallbackException); + return; + } + + if (logger.isDebugEnabled()) { + logger.debug( + "GetBlock call callback, result: {}, inter chain request: {}", + callCallbackResult, + interchainRequest); + } + + registerCallbackResult( + null, + 0, + errorCode, + message, + finalResult, + registerCallbackResultException -> { + if (logger.isDebugEnabled()) { + logger.debug( + "Register getBlock callback result, errorCode: {}, message: {}, result: {}, inter chain request: {}", + errorCode, + message, + callCallbackResult, + interchainRequest); + } + callback.onReturn(registerCallbackResultException); + }); + }); + })); + } else { + getXATransactionState( + (getTransactionStateException, xaTransactionID, xaTransactionSeq) -> { + if (Objects.nonNull(getTransactionStateException)) { + callback.onReturn(getTransactionStateException); + return; + } - if (logger.isDebugEnabled()) { - logger.debug( - "Call target chain, xaTransactionID: {}, xaTransactionSeq: {}, state: {}, result: {}, inter chain request: {}", - xaTransactionID, - callTargetChainSeq, - state, - result, - interchainRequest); - } + if (logger.isDebugEnabled()) { + logger.debug( + "Transaction state, xaTransactionID: {}, xaTransactionSeq: {}, inter chain request: {}", + xaTransactionID, + xaTransactionSeq, + interchainRequest); + } - boolean finalState = state; - String finalResult = result; - getXATransactionState( - (getCallbackTransactionStateException, - callbackXATransactionID, - callbackXATransactionSeq) -> { - if (Objects.nonNull( - getCallbackTransactionStateException)) { - callback.onReturn( - getCallbackTransactionStateException); - return; - } - - long newTimestamp = System.currentTimeMillis(); - long callCallbackSeq = - newTimestamp > callbackXATransactionSeq - ? newTimestamp - : (callbackXATransactionSeq + 1L); - - callCallback( - Sha256Utils.sha256String( - realUid.getBytes( - StandardCharsets.UTF_8)), + String realUid = + Sha256Utils.sha256String( + (systemResource.getHubResource() + + interchainRequest.getUid()) + .getBytes(StandardCharsets.UTF_8)); + + long timestamp = System.currentTimeMillis(); + long callTargetChainSeq = + timestamp > xaTransactionSeq ? timestamp : (xaTransactionSeq + 1L); + callTargetChain( + realUid, + xaTransactionID, + callTargetChainSeq, + (callTargetChainException, callTargetChainResult) -> { + boolean state = true; + String result = callTargetChainResult; + + if (Objects.nonNull(callTargetChainException)) { + logger.error( + "Call target chain failed, error code: {}, message: {}", + callTargetChainException.getInternalErrorCode(), + callTargetChainException.getInternalMessage()); + + state = false; + result = "[]"; + } + + if (logger.isDebugEnabled()) { + logger.debug( + "Call target chain, xaTransactionID: {}, xaTransactionSeq: {}, state: {}, result: {}, inter chain request: {}", + xaTransactionID, + callTargetChainSeq, + state, + result, + interchainRequest); + } + + boolean finalState = state; + String finalResult = result; + getXATransactionState( + (getCallbackTransactionStateException, callbackXATransactionID, - callCallbackSeq, - finalState, - finalResult, - (callCallbackException, - errorCode, - message, - callCallbackResult) -> { - if (Objects.nonNull( - callCallbackException)) { - /* exception occurred, no need to register result */ - callback.onReturn( - callCallbackException); - return; - } - - if (logger.isDebugEnabled()) { - logger.debug( - "Call callback, xaTransactionID: {}, xaTransactionSeq: {}, result: {}, inter chain request: {}", + callbackXATransactionSeq) -> { + if (Objects.nonNull( + getCallbackTransactionStateException)) { + callback.onReturn( + getCallbackTransactionStateException); + return; + } + + long newTimestamp = System.currentTimeMillis(); + long callCallbackSeq = + newTimestamp > callbackXATransactionSeq + ? newTimestamp + : (callbackXATransactionSeq + 1L); + + callCallback( + Sha256Utils.sha256String( + realUid.getBytes( + StandardCharsets.UTF_8)), + callbackXATransactionID, + callCallbackSeq, + finalState, + finalResult, + (callCallbackException, + errorCode, + message, + callCallbackResult) -> { + if (Objects.nonNull( + callCallbackException)) { + /* exception occurred, no need to register result */ + callback.onReturn( + callCallbackException); + return; + } + + if (logger.isDebugEnabled()) { + logger.debug( + "Call callback, xaTransactionID: {}, xaTransactionSeq: {}, result: {}, inter chain request: {}", + callbackXATransactionID, + callCallbackSeq, + callCallbackResult, + interchainRequest); + } + + registerCallbackResult( callbackXATransactionID, callCallbackSeq, + errorCode, + message, callCallbackResult, - interchainRequest); - } - - registerCallbackResult( - callbackXATransactionID, - callCallbackSeq, - errorCode, - message, - callCallbackResult, - registerCallbackResultException -> { - if (logger.isDebugEnabled()) { - logger.debug( - "Register callback result, xaTransactionID: {}, xaTransactionSeq: {}, errorCode: {}, message: {}, result: {}, inter chain request: {}", - callbackXATransactionID, - callCallbackSeq, - errorCode, - message, - callCallbackResult, - interchainRequest); - } - callback.onReturn( - registerCallbackResultException); - }); - }); - }, - interchainRequest.getCallbackPath()); - }); - }, - interchainRequest.getPath()); + registerCallbackResultException -> { + if (logger + .isDebugEnabled()) { + logger.debug( + "Register callback result, xaTransactionID: {}, xaTransactionSeq: {}, errorCode: {}, message: {}, result: {}, inter chain request: {}", + callbackXATransactionID, + callCallbackSeq, + errorCode, + message, + callCallbackResult, + interchainRequest); + } + callback.onReturn( + registerCallbackResultException); + }); + }); + }, + interchainRequest.getCallbackPath()); + }); + }, + interchainRequest.getPath()); + } } public interface GetTransactionStateCallback { @@ -333,6 +402,54 @@ public void callTargetChain( } } + public interface GetBlockCallback { + void onReturn(WeCrossException exception, Block block); + } + + public void getTargetChainBlock(GetBlockCallback callback) { + try { + Path path = Path.decode(interchainRequest.getPath()); + Resource resource = systemResource.getZoneManager().fetchResource(path); + if (Objects.isNull(resource)) { + callback.onReturn( + new WeCrossException( + WeCrossException.ErrorCode.INTER_CHAIN_ERROR, + "GET_TARGET_CHAIN_BLOCK_ERROR", + InterchainErrorCode.GET_TARGET_CHAIN_BLOCK_ERROR, + "Target path '" + path + "' not found"), + null); + return; + } + long blockNumber = Long.parseLong(interchainRequest.getArgs()[0]); + resource.getBlockManager() + .asyncGetBlock( + blockNumber, + (blockHeaderException, block) -> { + if (Objects.nonNull(blockHeaderException)) { + callback.onReturn( + new WeCrossException( + WeCrossException.ErrorCode.INTER_CHAIN_ERROR, + "GET_TARGET_CHAIN_BLOCK_ERROR", + InterchainErrorCode + .GET_TARGET_CHAIN_BLOCK_ERROR, + blockHeaderException.getMessage()), + null); + } else { + callback.onReturn(null, block); + } + }); + } catch (Exception e) { + logger.error("Get target chain block exception, ", e); + callback.onReturn( + new WeCrossException( + WeCrossException.ErrorCode.INTER_CHAIN_ERROR, + "GET_TARGET_CHAIN_BLOCK_ERROR", + InterchainErrorCode.GET_TARGET_CHAIN_BLOCK_ERROR, + "Exception occurred"), + null); + } + } + public interface CallCallbackCallback { // result is json form of string array void onReturn(WeCrossException exception, int errorCode, String message, String result); diff --git a/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandler.java b/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandler.java index 3b5393898..63d24a3a8 100644 --- a/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandler.java +++ b/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandler.java @@ -8,7 +8,6 @@ import io.netty.handler.ssl.SslHandshakeCompletionEvent; import io.netty.handler.timeout.IdleStateEvent; import io.netty.util.AttributeKey; -import javax.net.ssl.SSLPeerUnverifiedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +58,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { logger.info(" handshake success, host: {}, ctx: {}", node, hashCode); try { getChannelHandlerCallBack().onConnect(ctx, getConnectToServer()); - } catch (SSLPeerUnverifiedException e1) { + } catch (Exception e1) { logger.warn( " handshake on connect exception, disconnect, host: {}, ctx: {}, cause: {}", node, @@ -67,6 +66,8 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { e1.getCause()); ctx.disconnect(); ctx.close(); + throw new RuntimeException( + "SSLPeerUnverifiedException, handshake on connect exception", e1); } } else { logger.warn( diff --git a/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandlerCallBack.java b/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandlerCallBack.java index 8a01439fd..7839a0c23 100644 --- a/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandlerCallBack.java +++ b/src/main/java/com/webank/wecross/network/p2p/netty/channel/handler/ChannelHandlerCallBack.java @@ -61,16 +61,20 @@ private String bytesToHex(byte[] hashInBytes) { return sb.toString(); } - private PublicKey fetchCertificate(ChannelHandlerContext ctx) - throws SSLPeerUnverifiedException { + private PublicKey fetchCertificate(ChannelHandlerContext ctx) throws Exception { SslHandler sslhandler = ctx.channel().pipeline().get(SslHandler.class); - - Certificate[] certs = sslhandler.engine().getSession().getPeerCertificates(); + Certificate[] certs; + try { + certs = sslhandler.engine().getSession().getPeerCertificates(); + } catch (SSLPeerUnverifiedException e) { + logger.error("fetchCertificate error", e); + throw new Exception("fetchCertificate error", e); + } logger.info( " ctx: {}, Certificate length: {}, pipeline sslHandlers: {}", Objects.hashCode(ctx), certs.length, - String.valueOf(ctx.channel().pipeline().names())); + ctx.channel().pipeline().names()); Certificate cert = certs[0]; PublicKey publicKey = cert.getPublicKey(); @@ -91,8 +95,7 @@ private PublicKey fetchCertificate(ChannelHandlerContext ctx) * @return * @throws SSLPeerUnverifiedException */ - public Node channelContext2Node(ChannelHandlerContext context) - throws SSLPeerUnverifiedException { + public Node channelContext2Node(ChannelHandlerContext context) throws Exception { if (null == context) { return null; } @@ -105,8 +108,7 @@ public Node channelContext2Node(ChannelHandlerContext context) return new Node(nodeID, host, port); } - public void onConnect(ChannelHandlerContext ctx, boolean connectToServer) - throws SSLPeerUnverifiedException { + public void onConnect(ChannelHandlerContext ctx, boolean connectToServer) throws Exception { Node node = channelContext2Node(ctx); int hashCode = System.identityHashCode(ctx); @@ -127,15 +129,9 @@ public void onConnect(ChannelHandlerContext ctx, boolean connectToServer) callBack.onConnect(ctx, node); } else { try { - threadPool.execute( - new Runnable() { - @Override - public void run() { - callBack.onConnect(ctx, node); - } - }); + threadPool.execute(() -> callBack.onConnect(ctx, node)); } catch (TaskRejectedException e) { - logger.warn(" TaskRejectedException: {} ", e); + logger.warn(" TaskRejectedException: ", e); callBack.onConnect(ctx, node); } } diff --git a/src/main/java/com/webank/wecross/network/rpc/URIHandlerDispatcher.java b/src/main/java/com/webank/wecross/network/rpc/URIHandlerDispatcher.java index f95b8dac2..20babf400 100644 --- a/src/main/java/com/webank/wecross/network/rpc/URIHandlerDispatcher.java +++ b/src/main/java/com/webank/wecross/network/rpc/URIHandlerDispatcher.java @@ -73,6 +73,7 @@ public void initializeRequestMapper(WeCrossHost host) { new TransactionURIHandler(transactionFetcher, host.getAccountManager()); registerURIHandler(new URIMethod("GET", "/trans/getTransaction"), transactionURIHandler); registerURIHandler(new URIMethod("GET", "/trans/listTransactions"), transactionURIHandler); + registerURIHandler(new URIMethod("GET", "/trans/getBlock"), transactionURIHandler); ConnectionURIHandler connectionURIHandler = new ConnectionURIHandler(); connectionURIHandler.setP2PService(host.getP2PService()); diff --git a/src/main/java/com/webank/wecross/network/rpc/handler/ResourceURIHandler.java b/src/main/java/com/webank/wecross/network/rpc/handler/ResourceURIHandler.java index 42e9cbd12..88f63fed6 100644 --- a/src/main/java/com/webank/wecross/network/rpc/handler/ResourceURIHandler.java +++ b/src/main/java/com/webank/wecross/network/rpc/handler/ResourceURIHandler.java @@ -152,6 +152,12 @@ public void handle( return; } + logger.info( + "resource sendTransaction, path: {}, request: {}, ua: {}", + path, + restRequest.getData(), + ua.getName()); + resourceObj.asyncSendTransaction( transactionRequest, ua, @@ -186,6 +192,11 @@ public void handle( new TypeReference>() {}); restRequest.checkRestRequest(); + logger.info( + "resourceCall, path: {}, request: {}, ua: {}", + path, + restRequest.getData(), + ua.getName()); TransactionRequest transactionRequest = restRequest.getData(); Resource resourceObj = getResource(path); @@ -224,10 +235,6 @@ public void handle( } case "customcommand": { - if (logger.isDebugEnabled()) { - logger.debug("zone: {}, chain: {}", path.getZone(), path.getChain()); - } - ZoneManager zoneManager = host.getZoneManager(); Zone zone = zoneManager.getZone(path.getZone()); if (Objects.isNull(zone)) { @@ -244,6 +251,14 @@ public void handle( content, new TypeReference>() {}); + logger.info( + "resource customCommand, zone: {}, chain: {}, command:{}, args:{}, ua:{}", + path.getZone(), + path.getChain(), + restRequest.getData().getCommand(), + restRequest.getData().getArgs(), + ua.getName()); + chain.asyncCustomCommand( restRequest.getData().getCommand(), path, diff --git a/src/main/java/com/webank/wecross/network/rpc/handler/SystemInfoHandler.java b/src/main/java/com/webank/wecross/network/rpc/handler/SystemInfoHandler.java index 611da1d9f..36337719d 100644 --- a/src/main/java/com/webank/wecross/network/rpc/handler/SystemInfoHandler.java +++ b/src/main/java/com/webank/wecross/network/rpc/handler/SystemInfoHandler.java @@ -9,6 +9,8 @@ import com.webank.wecross.restserver.response.StubResponse; import com.webank.wecross.stubmanager.StubManager; import com.webank.wecross.zone.ZoneManager; +import java.io.File; +import java.lang.management.ManagementFactory; import java.security.Provider; import java.security.Security; import java.util.stream.Collectors; @@ -77,6 +79,13 @@ private class SystemStatus { private String namedGroups; private String disabledNamedGroups; + private String totalDiskSpace; + private String totalDiskFreeSpace; + private String totalDiskUsable; + + private String totalMemorySize; + private String freeMemorySize; + public String getOsName() { return osName; } @@ -164,6 +173,46 @@ public String getDisabledNamedGroups() { public void setDisabledNamedGroups(String disabledNamedGroups) { this.disabledNamedGroups = disabledNamedGroups; } + + public String getTotalDiskSpace() { + return totalDiskSpace; + } + + public void setTotalDiskSpace(String totalDiskSpace) { + this.totalDiskSpace = totalDiskSpace; + } + + public String getTotalDiskFreeSpace() { + return totalDiskFreeSpace; + } + + public void setTotalDiskFreeSpace(String totalDiskFreeSpace) { + this.totalDiskFreeSpace = totalDiskFreeSpace; + } + + public String getTotalDiskUsable() { + return totalDiskUsable; + } + + public void setTotalDiskUsable(String totalDiskUsable) { + this.totalDiskUsable = totalDiskUsable; + } + + public String getTotalMemorySize() { + return totalMemorySize; + } + + public void setTotalMemorySize(String totalMemorySize) { + this.totalMemorySize = totalMemorySize; + } + + public String getFreeMemorySize() { + return freeMemorySize; + } + + public void setFreeMemorySize(String freeMemorySize) { + this.freeMemorySize = freeMemorySize; + } } private void systemStatus( @@ -185,6 +234,32 @@ private void systemStatus( status.setProviderName(provider.getName()); status.setProviderVersion(String.valueOf(provider.getVersion())); + // disk space usage + File[] disks = File.listRoots(); + long total = 0; + long free = 0; + long usable = 0; + for (File disk : disks) { + // B to GB + total += disk.getTotalSpace() / 1024 / 1024 / 1024; + free += disk.getFreeSpace() / 1024 / 1024 / 1024; + usable += disk.getUsableSpace() / 1024 / 1024 / 1024; + } + status.setTotalDiskSpace(total + "GB"); + status.setTotalDiskFreeSpace(free + "GB"); + status.setTotalDiskUsable(usable + "GB"); + + // memory usage + com.sun.management.OperatingSystemMXBean operatingSystemMXBean = + (com.sun.management.OperatingSystemMXBean) + ManagementFactory.getOperatingSystemMXBean(); + long totalPhysicalMemorySize = + operatingSystemMXBean.getTotalPhysicalMemorySize() / 1024 / 1024 / 1024; + long freePhysicalMemorySize = + operatingSystemMXBean.getFreePhysicalMemorySize() / 1024 / 1024 / 1024; + status.setTotalMemorySize(totalPhysicalMemorySize + "GB"); + status.setFreeMemorySize(freePhysicalMemorySize + "GB"); + RestResponse restResponse = new RestResponse(); restResponse.setData(status); diff --git a/src/main/java/com/webank/wecross/network/rpc/handler/TransactionURIHandler.java b/src/main/java/com/webank/wecross/network/rpc/handler/TransactionURIHandler.java index be8748bea..45928f748 100644 --- a/src/main/java/com/webank/wecross/network/rpc/handler/TransactionURIHandler.java +++ b/src/main/java/com/webank/wecross/network/rpc/handler/TransactionURIHandler.java @@ -1,14 +1,19 @@ package com.webank.wecross.network.rpc.handler; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.webank.wecross.account.AccountAccessControlFilter; import com.webank.wecross.account.AccountManager; import com.webank.wecross.account.UniversalAccount; import com.webank.wecross.account.UserContext; import com.webank.wecross.common.NetworkQueryStatus; import com.webank.wecross.common.WeCrossDefault; +import com.webank.wecross.exception.WeCrossException; import com.webank.wecross.network.UriDecoder; +import com.webank.wecross.restserver.RestRequest; import com.webank.wecross.restserver.RestResponse; import com.webank.wecross.restserver.fetcher.TransactionFetcher; +import com.webank.wecross.restserver.request.BlockRequest; import com.webank.wecross.stub.*; import java.util.Objects; import org.slf4j.Logger; @@ -18,6 +23,7 @@ public class TransactionURIHandler implements URIHandler { private static final Logger logger = LoggerFactory.getLogger(TransactionURIHandler.class); + private final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); private TransactionFetcher transactionFetcher; @@ -211,6 +217,12 @@ public void handle( }); return; } + case "getBlock": + { + getBlockRequest( + userContext, callback, restResponse, uri, content, uriDecoder); + return; + } default: { logger.warn("Unsupported method: {}", method); @@ -226,4 +238,99 @@ public void handle( } callback.onResponse(restResponse); } + + private void getBlockRequest( + UserContext userContext, + Callback callback, + RestResponse restResponse, + String uri, + String content, + UriDecoder uriDecoder) { + String path; + long blockNumber; + + try { + if (uri.contains("path=") && uri.contains("blockNumber=")) { + try { + path = uriDecoder.getQueryBykey("path"); + blockNumber = Long.parseLong(uriDecoder.getQueryBykey("blockNumber")); + } catch (Exception e) { + restResponse.setErrorCode(NetworkQueryStatus.URI_QUERY_ERROR); + restResponse.setMessage(e.getMessage()); + callback.onResponse(restResponse); + return; + } + } else { + RestRequest blockRequest = + objectMapper.readValue( + content, new TypeReference>() {}); + blockRequest.checkRestRequest(); + blockNumber = blockRequest.getData().getBlockNumber(); + path = blockRequest.getData().getPath(); + } + Path chain; + try { + chain = Path.decode(path); + } catch (Exception e) { + logger.warn("Decode chain path error: {}", path); + restResponse.setErrorCode(NetworkQueryStatus.URI_QUERY_ERROR); + restResponse.setMessage("Decode chain path error"); + callback.onResponse(restResponse); + return; + } + // check permission + try { + UniversalAccount ua = accountManager.getUniversalAccount(userContext); + AccountAccessControlFilter filter = ua.getAccessControlFilter(); + if (!filter.hasPermission(path)) { + throw new Exception("Permission denied"); + } + } catch (Exception e) { + logger.warn("Verify permission failed. path:{} error: {}", path, e); + restResponse.setErrorCode(NetworkQueryStatus.URI_QUERY_ERROR); + restResponse.setMessage("Verify permission failed"); + callback.onResponse(restResponse); + return; + } + + transactionFetcher.asyncGetBlock( + chain, + blockNumber, + (fetchException, response) -> { + if (logger.isDebugEnabled()) { + logger.debug( + "getBlock, response: {}, fetchException: ", + response, + fetchException); + } + + if (Objects.nonNull(fetchException)) { + logger.warn("Failed to get block: ", fetchException); + restResponse.setErrorCode( + NetworkQueryStatus.TRANSACTION_ERROR + + fetchException.getErrorCode()); + restResponse.setMessage(fetchException.getMessage()); + } else { + try { + restResponse.setData(objectMapper.writeValueAsString(response)); + } catch (Exception e) { + restResponse.setErrorCode(NetworkQueryStatus.INTERNAL_ERROR); + restResponse.setMessage("Encode block error"); + } + } + + callback.onResponse(restResponse); + }); + } catch (WeCrossException e) { + logger.warn("Process request error: ", e); + restResponse.setErrorCode(NetworkQueryStatus.NETWORK_PACKAGE_ERROR + e.getErrorCode()); + restResponse.setMessage(e.getMessage()); + callback.onResponse(restResponse); + } catch (Exception e) { + logger.warn("Process request error: ", e); + restResponse.setErrorCode(NetworkQueryStatus.INTERNAL_ERROR); + restResponse.setMessage(e.getMessage()); + callback.onResponse(restResponse); + } + } } diff --git a/src/main/java/com/webank/wecross/network/rpc/handler/XATransactionHandler.java b/src/main/java/com/webank/wecross/network/rpc/handler/XATransactionHandler.java index 4e5ddb560..f5c0f2078 100644 --- a/src/main/java/com/webank/wecross/network/rpc/handler/XATransactionHandler.java +++ b/src/main/java/com/webank/wecross/network/rpc/handler/XATransactionHandler.java @@ -58,6 +58,7 @@ public void setPaths(Set paths) { public static class ListXATransactionsRequest { private int size; + private String path; private Map offsets = Collections.synchronizedMap(new HashMap<>()); public int getSize() { @@ -75,6 +76,14 @@ public Map getOffsets() { public void setOffsets(Map offsets) { this.offsets = offsets; } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } } @Override @@ -229,6 +238,7 @@ public void handle( host.getAccountManager().getAdminUA(), xaRequest.getData().getOffsets(), xaRequest.getData().getSize(), + xaRequest.getData().getPath(), (exception, xaTransactionListResponse) -> { if (logger.isDebugEnabled()) { logger.debug( diff --git a/src/main/java/com/webank/wecross/restserver/fetcher/TransactionFetcher.java b/src/main/java/com/webank/wecross/restserver/fetcher/TransactionFetcher.java index 0b2a820fc..2a2d47e15 100644 --- a/src/main/java/com/webank/wecross/restserver/fetcher/TransactionFetcher.java +++ b/src/main/java/com/webank/wecross/restserver/fetcher/TransactionFetcher.java @@ -5,12 +5,15 @@ import com.webank.wecross.exception.WeCrossException; import com.webank.wecross.restserver.response.CompleteTransactionResponse; import com.webank.wecross.restserver.response.TransactionListResponse; +import com.webank.wecross.stub.Block; import com.webank.wecross.stub.Driver; import com.webank.wecross.stub.Path; import com.webank.wecross.stub.StubConstant; +import com.webank.wecross.stub.Transaction; import com.webank.wecross.zone.Chain; import com.webank.wecross.zone.ZoneManager; import java.util.Objects; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,6 +73,8 @@ public void asyncFetchTransaction( completeTransactionResponse.setReceiptBytes(transaction.getReceiptBytes()); completeTransactionResponse.setBlockNumber(blockNumber); completeTransactionResponse.setTxHash(txHash); + completeTransactionResponse.setTimestamp( + transaction.getTransactionResponse().getTimestamp()); if (transaction.isTransactionByProxy()) { completeTransactionResponse.setByProxy(true); @@ -113,6 +118,39 @@ public void asyncFetchTransaction( }); } + public interface FetchBlockCallback { + void onResponse(WeCrossException e, Block response); + } + + public void asyncGetBlock(Path chainPath, Long blockNumber, FetchBlockCallback callback) { + Chain chain = zoneManager.getChain(chainPath); + Driver driver = chain.getDriver(); + driver.asyncGetBlock( + blockNumber, + false, + chain.chooseConnection(), + (e, block) -> { + if (Objects.nonNull(e)) { + logger.warn( + "Failed to get block, chain: {}, blockNumber: {}, e:", + chainPath, + blockNumber, + e); + callback.onResponse( + new WeCrossException( + WeCrossException.ErrorCode.GET_BLOCK_ERROR, e.getMessage()), + null); + return; + } + + if (logger.isDebugEnabled()) { + logger.debug("getBlock, blockNumber: {}, block: {}", blockNumber, block); + } + + callback.onResponse(null, block); + }); + } + public interface FetchTransactionListCallback { void onResponse(WeCrossException e, TransactionListResponse response); } @@ -208,53 +246,107 @@ private void recursiveFetchTransactionList( response); } - if (block.transactionsHashes.isEmpty()) { + if (block.transactionsHashes.isEmpty() + && block.transactionsWithDetail.isEmpty()) { // blank block response.setNextBlockNumber(blockNumber - 1); response.setNextOffset(0); recursiveFetchTransactionList(chain, driver, size, response, mainCallback); return; } - - int offset = response.getNextOffset(); - if (offset >= block.transactionsHashes.size()) { - logger.warn( - "Wrong offset, total txHash: {}, offset: {}, response: {}", - block.transactionsHashes.size(), - offset, - response); - mainCallback.onResponse( - new WeCrossException( - WeCrossException.ErrorCode.GET_BLOCK_ERROR, "Wrong offset"), - null); - return; - } - int index; int count = size; - for (index = offset; - index < block.transactionsHashes.size() && count > 0; - index++) { - // hash is blank - if (!"".equals(block.transactionsHashes.get(index).trim())) { - TransactionListResponse.Transaction transaction = - new TransactionListResponse.Transaction(); - transaction.setBlockNumber(blockNumber); - transaction.setTxHash(block.transactionsHashes.get(index)); - response.addTransaction(transaction); - count--; + if (!block.transactionsWithDetail.isEmpty()) { + int offset = response.getNextOffset(); + if (offset >= block.transactionsWithDetail.size()) { + logger.warn( + "Wrong offset, total txHash: {}, offset: {}, response: {}", + block.transactionsWithDetail.size(), + offset, + response); + mainCallback.onResponse( + new WeCrossException( + WeCrossException.ErrorCode.GET_BLOCK_ERROR, + "Wrong offset"), + null); + return; + } + for (index = offset; + index < block.transactionsWithDetail.size() && count > 0; + index++) { + Transaction transaction = block.transactionsWithDetail.get(index); + if (Objects.nonNull(transaction) + && StringUtils.isNotBlank( + transaction.getTransactionResponse().getHash())) { + TransactionListResponse.TransactionWithDetail transactionDetail = + new TransactionListResponse.TransactionWithDetail(); + transactionDetail.setBlockNumber(blockNumber); + transactionDetail.setTxHash( + transaction.getTransactionResponse().getHash()); + if (transaction.isTransactionByProxy()) { + transactionDetail.setPath(transaction.getResource()); + transactionDetail.setAccountIdentity( + transaction.getAccountIdentity()); + transactionDetail.setMethod( + transaction.getTransactionRequest().getMethod()); + transactionDetail.setXaTransactionID( + (String) + transaction + .getTransactionRequest() + .getOptions() + .get(StubConstant.XA_TRANSACTION_ID)); + } + response.addTransactionWithDetail(transactionDetail); + count--; + } } - } - long nextBlockNumber = - index == block.transactionsHashes.size() - ? blockNumber - 1 - : blockNumber; - int nextOffset = index == block.transactionsHashes.size() ? 0 : index; - response.setNextBlockNumber(nextBlockNumber); - response.setNextOffset(nextOffset); + long nextBlockNumber = + index == block.transactionsWithDetail.size() + ? blockNumber - 1 + : blockNumber; + int nextOffset = index == block.transactionsWithDetail.size() ? 0 : index; + response.setNextBlockNumber(nextBlockNumber); + response.setNextOffset(nextOffset); + recursiveFetchTransactionList(chain, driver, count, response, mainCallback); + } else { + int offset = response.getNextOffset(); + if (offset >= block.transactionsHashes.size()) { + logger.warn( + "Wrong offset, total txHash: {}, offset: {}, response: {}", + block.transactionsHashes.size(), + offset, + response); + mainCallback.onResponse( + new WeCrossException( + WeCrossException.ErrorCode.GET_BLOCK_ERROR, + "Wrong offset"), + null); + return; + } + for (index = offset; + index < block.transactionsHashes.size() && count > 0; + index++) { + // hash is blank + if (!"".equals(block.transactionsHashes.get(index).trim())) { + TransactionListResponse.Transaction transaction = + new TransactionListResponse.Transaction(); + transaction.setBlockNumber(blockNumber); + transaction.setTxHash(block.transactionsHashes.get(index)); + response.addTransaction(transaction); + count--; + } + } - recursiveFetchTransactionList(chain, driver, count, response, mainCallback); + long nextBlockNumber = + index == block.transactionsHashes.size() + ? blockNumber - 1 + : blockNumber; + int nextOffset = index == block.transactionsHashes.size() ? 0 : index; + response.setNextBlockNumber(nextBlockNumber); + response.setNextOffset(nextOffset); + recursiveFetchTransactionList(chain, driver, count, response, mainCallback); + } }); } diff --git a/src/main/java/com/webank/wecross/restserver/request/BlockRequest.java b/src/main/java/com/webank/wecross/restserver/request/BlockRequest.java new file mode 100644 index 000000000..737c4f08e --- /dev/null +++ b/src/main/java/com/webank/wecross/restserver/request/BlockRequest.java @@ -0,0 +1,29 @@ +package com.webank.wecross.restserver.request; + +public class BlockRequest { + private long blockNumber; + private String path; + + public BlockRequest() {} + + public BlockRequest(long blockNumber, String path) { + this.blockNumber = blockNumber; + this.path = path; + } + + public long getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(long blockNumber) { + this.blockNumber = blockNumber; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/src/main/java/com/webank/wecross/restserver/response/CompleteTransactionResponse.java b/src/main/java/com/webank/wecross/restserver/response/CompleteTransactionResponse.java index 52d8363c6..030049d76 100644 --- a/src/main/java/com/webank/wecross/restserver/response/CompleteTransactionResponse.java +++ b/src/main/java/com/webank/wecross/restserver/response/CompleteTransactionResponse.java @@ -22,6 +22,7 @@ public class CompleteTransactionResponse { private int errorCode; // transaction rolled back private String message; + private long timestamp; public String getPath() { return path; @@ -135,6 +136,14 @@ public void setMessage(String message) { this.message = message; } + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + @Override public String toString() { return "CompleteTransactionResponse{" @@ -163,15 +172,14 @@ public String toString() { + Arrays.toString(result) + ", byProxy=" + byProxy - + ", txBytes=" - + Arrays.toString(txBytes) - + ", receiptBytes=" - + Arrays.toString(receiptBytes) + ", errorCode=" + errorCode + ", message='" + message + '\'' + + ", timestamp='" + + timestamp + + '\'' + '}'; } } diff --git a/src/main/java/com/webank/wecross/restserver/response/TransactionListResponse.java b/src/main/java/com/webank/wecross/restserver/response/TransactionListResponse.java index c22de05b4..ede0150a0 100644 --- a/src/main/java/com/webank/wecross/restserver/response/TransactionListResponse.java +++ b/src/main/java/com/webank/wecross/restserver/response/TransactionListResponse.java @@ -10,8 +10,19 @@ public class TransactionListResponse { private int nextOffset; private List transactions = Collections.synchronizedList(new LinkedList<>()); + private List transactionWithDetails = + Collections.synchronizedList(new LinkedList<>()); + public TransactionListResponse() {} + public void addTransactionWithDetail(TransactionWithDetail transactionWithDetail) { + this.transactionWithDetails.add(transactionWithDetail); + } + + public void addTransactionWithDetails(List transactionWithDetails) { + this.transactionWithDetails.addAll(transactionWithDetails); + } + public void addTransaction(Transaction transaction) { this.transactions.add(transaction); } @@ -44,6 +55,14 @@ public void setTransactions(List transactions) { this.transactions = transactions; } + public List getTransactionWithDetails() { + return transactionWithDetails; + } + + public void setTransactionWithDetails(List transactionWithDetails) { + this.transactionWithDetails = transactionWithDetails; + } + @Override public String toString() { return "TransactionListResponse{" @@ -87,4 +106,84 @@ public String toString() { + '}'; } } + + public static class TransactionWithDetail { + private String txHash; + private long blockNumber; + private String accountIdentity; + private String path; + private String method; + private String xaTransactionID; + + public String getTxHash() { + return txHash; + } + + public void setTxHash(String txHash) { + this.txHash = txHash; + } + + public long getBlockNumber() { + return blockNumber; + } + + public void setBlockNumber(long blockNumber) { + this.blockNumber = blockNumber; + } + + public String getAccountIdentity() { + return accountIdentity; + } + + public void setAccountIdentity(String accountIdentity) { + this.accountIdentity = accountIdentity; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getXaTransactionID() { + return xaTransactionID; + } + + public void setXaTransactionID(String xaTransactionID) { + this.xaTransactionID = xaTransactionID; + } + + @Override + public String toString() { + return "TransactionWithDetail{" + + "txHash='" + + txHash + + '\'' + + ", blockNumber=" + + blockNumber + + ", accountIdentity='" + + accountIdentity + + '\'' + + ", path='" + + path + + '\'' + + ", method='" + + method + + '\'' + + ", xaTransactionID='" + + xaTransactionID + + '\'' + + '}'; + } + } } diff --git a/src/main/java/com/webank/wecross/routine/xa/XATransactionManager.java b/src/main/java/com/webank/wecross/routine/xa/XATransactionManager.java index 875fffd11..30db13765 100644 --- a/src/main/java/com/webank/wecross/routine/xa/XATransactionManager.java +++ b/src/main/java/com/webank/wecross/routine/xa/XATransactionManager.java @@ -576,6 +576,44 @@ public void asyncGetXATransaction( } } + private ListXAReduceCallback getListXACallback( + int count, Map offsets, int size, ListXATransactionsCallback callback) { + List errors = + Collections.synchronizedList(new LinkedList<>()); + Map nextOffsets = new ConcurrentHashMap<>(offsets); + + return (chain, listXAResponse) -> { + + // first time to list, reset offsets + if (nextOffsets.get(chain) == -1) { + nextOffsets.put(chain, listXAResponse.getTotal() - 1); + } + + XATransactionListResponse response = new XATransactionListResponse(); + if (Objects.nonNull(listXAResponse.getChainErrorMessage())) { + errors.add(listXAResponse.getChainErrorMessage()); + if (!errors.isEmpty()) { + XAResponse xaResponse = new XAResponse(); + xaResponse.setStatus(-1); + xaResponse.setChainErrorMessages(errors); + response.setXaResponse(xaResponse); + } + } else { + response.setXaList(listXAResponse.getXaTransactions()); + // update offsets + Long nextOffset = + nextOffsets.get(chain) - listXAResponse.getXaTransactions().size(); + nextOffsets.put(chain, nextOffset); + response.setNextOffsets(nextOffsets); + if (nextOffsets.get(chain) == -1) { + response.setFinished(true); + } + response.recoverUsername(accountManager); + } + callback.onResponse(null, response); + }; + } + public interface ListXATransactionsCallback { void onResponse(WeCrossException e, XATransactionListResponse xaTransactionListResponse); } @@ -728,6 +766,7 @@ public void asyncListXATransactions( UniversalAccount ua, Map offsets, int size, + String chainPath, ListXATransactionsCallback callback) { try { @@ -742,7 +781,12 @@ public void asyncListXATransactions( XATransactionListResponse response = new XATransactionListResponse(); - List chainPaths = setToList(zoneManager.getAllChainsInfo(false).keySet()); + List chainPaths = new ArrayList<>(); + if (Objects.isNull(chainPath) || chainPath.isEmpty()) { + chainPaths = setToList(zoneManager.getAllChainsInfo(false).keySet()); + } else { + chainPaths.add(Path.decode(chainPath)); + } int chainNum = chainPaths.size(); if (chainNum == 0) { @@ -761,8 +805,15 @@ public void asyncListXATransactions( } } - ListXAReduceCallback reduceCallback = - getListXAReduceCallback(offsets.size(), offsets, size, callback); + ListXAReduceCallback reduceCallback = null; + if (Objects.isNull(chainPath) || chainPath.isEmpty()) { + // has sort operation callback + reduceCallback = getListXAReduceCallback(offsets.size(), offsets, size, callback); + } else { + // Remove sort operation callback + reduceCallback = getListXACallback(offsets.size(), offsets, size, callback); + } + for (String chain : offsets.keySet()) { if (!requireIgnore || offsets.get(chain) != -1L) { asyncListXATransactions( diff --git a/src/main/java/com/webank/wecross/stub/Block.java b/src/main/java/com/webank/wecross/stub/Block.java index 20f88681b..d1a9f35d6 100644 --- a/src/main/java/com/webank/wecross/stub/Block.java +++ b/src/main/java/com/webank/wecross/stub/Block.java @@ -1,13 +1,15 @@ package com.webank.wecross.stub; +import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.Arrays; import java.util.LinkedList; import java.util.List; public class Block { - public byte[] rawBytes; + @JsonIgnore public byte[] rawBytes; public BlockHeader blockHeader; public List transactionsHashes = new LinkedList<>(); + public List transactionsWithDetail = new LinkedList<>(); public BlockHeader getBlockHeader() { return blockHeader; @@ -33,6 +35,14 @@ public void setRawBytes(byte[] rawBytes) { this.rawBytes = rawBytes; } + public List getTransactionsWithDetail() { + return transactionsWithDetail; + } + + public void setTransactionsWithDetail(List transactionsWithDetail) { + this.transactionsWithDetail = transactionsWithDetail; + } + @Override public String toString() { return "Block{" @@ -42,6 +52,8 @@ public String toString() { + blockHeader + ", transactionsHashes=" + Arrays.toString(transactionsHashes.toArray()) + + ", transactionsWithDetail=" + + Arrays.toString(transactionsWithDetail.toArray()) + '}'; } } diff --git a/src/main/java/com/webank/wecross/stub/BlockHeader.java b/src/main/java/com/webank/wecross/stub/BlockHeader.java index bd5cc0018..ae65dd773 100644 --- a/src/main/java/com/webank/wecross/stub/BlockHeader.java +++ b/src/main/java/com/webank/wecross/stub/BlockHeader.java @@ -7,6 +7,7 @@ public class BlockHeader { private String stateRoot; private String transactionRoot; private String receiptRoot; + private long timestamp; public long getNumber() { return number; @@ -56,6 +57,14 @@ public void setReceiptRoot(String receiptRoot) { this.receiptRoot = receiptRoot; } + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + @Override public String toString() { return "BlockHeader{" @@ -76,6 +85,9 @@ public String toString() { + ", receiptRoot='" + receiptRoot + '\'' + + ", timestamp='" + + timestamp + + '\'' + '}'; } } diff --git a/src/main/java/com/webank/wecross/stub/Transaction.java b/src/main/java/com/webank/wecross/stub/Transaction.java index 77e6e3637..238805951 100644 --- a/src/main/java/com/webank/wecross/stub/Transaction.java +++ b/src/main/java/com/webank/wecross/stub/Transaction.java @@ -1,7 +1,5 @@ package com.webank.wecross.stub; -import java.util.Arrays; - public class Transaction { private byte[] txBytes; // raw transaction info private byte[] receiptBytes; // raw transaction receipt info @@ -81,11 +79,7 @@ public void setTransactionByProxy(boolean transactionByProxy) { @Override public String toString() { return "Transaction{" - + "txBytes=" - + Arrays.toString(txBytes) - + ", receiptBytes=" - + Arrays.toString(receiptBytes) - + ", accountIdentity='" + + "accountIdentity='" + accountIdentity + '\'' + ", resource='" diff --git a/src/main/java/com/webank/wecross/stub/TransactionResponse.java b/src/main/java/com/webank/wecross/stub/TransactionResponse.java index e8479a96d..a773cd56e 100644 --- a/src/main/java/com/webank/wecross/stub/TransactionResponse.java +++ b/src/main/java/com/webank/wecross/stub/TransactionResponse.java @@ -11,6 +11,7 @@ public class TransactionResponse { private List extraHashes; private long blockNumber; private String[] result; + private long timestamp; public Integer getErrorCode() { return errorCode; @@ -60,6 +61,14 @@ public List getExtraHashes() { return extraHashes; } + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + public void addExtraHash(String hash) { if (this.extraHashes == null) { this.extraHashes = new ArrayList<>(); @@ -82,6 +91,8 @@ public String toString() { + extraHashes + ", blockNumber=" + blockNumber + + ", timestamp=" + + timestamp + ", result=" + Arrays.toString(result) + '}'; diff --git a/src/test/java/com/webank/wecross/test/rpc/URIHandlerDispatcherTest.java b/src/test/java/com/webank/wecross/test/rpc/URIHandlerDispatcherTest.java index 175080ee6..40efc2bda 100644 --- a/src/test/java/com/webank/wecross/test/rpc/URIHandlerDispatcherTest.java +++ b/src/test/java/com/webank/wecross/test/rpc/URIHandlerDispatcherTest.java @@ -26,7 +26,7 @@ public void URIHandlerDispatcherTest() throws Exception { URIHandlerDispatcher uriHandlerDispatcher = new URIHandlerDispatcher(); uriHandlerDispatcher.initializeRequestMapper(host); - Assert.assertTrue(uriHandlerDispatcher.getRequestURIMapper().size() == 24); + Assert.assertTrue(uriHandlerDispatcher.getRequestURIMapper().size() == 25); Assert.assertTrue( Objects.nonNull(