Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ message Empty {}
// 监管节点作为客户端向监管系统请求验证ucp的合法性(VerifyCrossChainMessage方法中调用)
message VerifyCrossChainMessageInMonitorSystemRequest {
bytes rawUcp = 1;
string ucpId = 2;
}

// 接收无需监管的跨链消息,并转发给课题四监管系统供其分析(VerifyCrossChainMessage方法中调用)
message RelayUcpToMonitorSystemRequest {
bytes rawUcp = 1;
string ucpId = 2;
}

message MonitorSystemResponse {
Expand Down
13 changes: 12 additions & 1 deletion SimpleMonitorSystem/MonitorSystemServer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@
<artifactId>MonitorAPI</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alipay.antchain.bridge</groupId>
<artifactId>antchain-bridge-commons</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -61,4 +72,4 @@
</plugins>
</build>

</project>
</project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import io.grpc.Server;
import io.grpc.stub.StreamObserver;
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
import com.alipay.antchain.bridge.commons.core.base.UniformCrosschainPacket;
import com.alipay.antchain.bridge.ptc.committee.monitor.system.grpc.*;

import java.io.File;
Expand All @@ -20,8 +21,15 @@ public class MonitorSystemServer {

private Server server;

// 控制返回成功或失败,默认返回成功
private volatile boolean verifySuccess = true;
enum VerifyMode {
SUCCESS,
FAILURE,
INTERNAL_ERROR,
UNAVAILABLE
}

// 控制 verify 的返回结果,默认返回成功
private volatile VerifyMode verifyMode = VerifyMode.SUCCESS;

public void start(int port) throws Exception {
server = NettyServerBuilder.forPort(port)
Expand All @@ -42,32 +50,42 @@ public void start(int port) throws Exception {
logInfo("Server shut down.");
}));

// 仅在交互式终端中启动控制线程。systemd/nohup 后台运行时没有可用的 stdin,
// 此时保持默认的验证成功行为,避免 Scanner.nextLine() 因 EOF 退出并打印异常。
if (System.console() != null) {
new Thread(this::startCommandListener, "CommandListenerThread").start();
} else {
logInfo("No interactive console detected; command listener disabled and verify result defaults to success.");
}
// 仅在交互式终端中启动控制线程。systemd/nohup 后台运行时没有可用的 stdin,
// 此时保持默认的验证成功行为,避免 Scanner.nextLine() 因 EOF 退出并打印异常。
if (System.console() != null) {
new Thread(this::startCommandListener, "CommandListenerThread").start();
} else {
logInfo("No interactive console detected; command listener disabled and verify result defaults to success.");
}
}

private void startCommandListener() {
Scanner scanner = new Scanner(System.in);
logInfo("请输入 'success' 或 'fail' 来控制 verifyCrossChainMessageInMonitorSystem 返回结果:");
logInfo("请输入 'success'、'fail'、'500' 或 '503' 来控制 verifyCrossChainMessageInMonitorSystem 返回结果:");
while (true) {
String input = scanner.nextLine();
if ("success".equalsIgnoreCase(input)) {
verifySuccess = true;
verifyMode = VerifyMode.SUCCESS;
logInfo("切换为:返回成功");
} else if ("fail".equalsIgnoreCase(input)) {
verifySuccess = false;
verifyMode = VerifyMode.FAILURE;
logInfo("切换为:返回失败");
} else if ("500".equals(input)) {
verifyMode = VerifyMode.INTERNAL_ERROR;
logInfo("切换为:返回内部错误(code=500)");
} else if ("503".equals(input)) {
verifyMode = VerifyMode.UNAVAILABLE;
logInfo("切换为:返回服务不可用(code=503)");
} else {
logInfo("无效指令,请输入 'success' 或 'fail'");
logInfo("无效指令,请输入 'success'、'fail'、'500' 或 '503'");
}
}
}

void setVerifyMode(VerifyMode verifyMode) {
this.verifyMode = verifyMode;
}

public void stop() {
if (server != null) {
server.shutdown();
Expand Down Expand Up @@ -97,15 +115,44 @@ public void verifyCrossChainMessageInMonitorSystem(
VerifyCrossChainMessageInMonitorSystemRequest request,
StreamObserver<MonitorSystemResponse> responseObserver) {

MonitorSystemResponse response;
try {
response = buildVerifyResponse(request);
} catch (RuntimeException e) {
logWarning("Unexpected error while processing verify request", e);
response = errorResponse(500, "internal monitor system error: " + errorMessage(e));
}

responseObserver.onNext(response);
responseObserver.onCompleted();
}

MonitorSystemResponse buildVerifyResponse(VerifyCrossChainMessageInMonitorSystemRequest request) {

byte[] rawUcp = request.getRawUcp().toByteArray();
logInfo("Received verifyCrossChainMessageInMonitorSystem request:");
logInfo("ucpId: " + request.getUcpId());
logInfo("rawUcp (hex): " + bytesToHex(rawUcp));

if (verifyMode == VerifyMode.INTERNAL_ERROR) {
return errorResponse(500, "simulated internal monitor system error");
}
if (verifyMode == VerifyMode.UNAVAILABLE) {
return errorResponse(503, "simulated monitor system unavailable");
}

try {
if (UniformCrosschainPacket.decode(rawUcp) == null) {
return errorResponse(400, "failed to decode rawUcp: decoded UCP is null");
}
} catch (RuntimeException e) {
return errorResponse(400, "failed to decode rawUcp: " + errorMessage(e));
}

MonitorSystemResponse.Builder responseBuilder = MonitorSystemResponse.newBuilder()
.setCode(0)
.setErrorMsg("");

if (verifySuccess) {
if (verifyMode == VerifyMode.SUCCESS) {
responseBuilder.setVerifyCrossChainMessageInMonitorSystemResp(
VerifyCrossChainMessageInMonitorSystemResponse.newBuilder()
.setResult(0)
Expand All @@ -116,32 +163,39 @@ public void verifyCrossChainMessageInMonitorSystem(
responseBuilder.setVerifyCrossChainMessageInMonitorSystemResp(
VerifyCrossChainMessageInMonitorSystemResponse.newBuilder()
.setResult(1)
.setMsg("fail")
.setMsg("simulated regulation rejection: matched test rule")
.build());
logInfo("返回:失败");
}

responseObserver.onNext(responseBuilder.build());
responseObserver.onCompleted();
return responseBuilder.build();
}

@Override
public void relayUcpToMonitorSystem(
RelayUcpToMonitorSystemRequest request,
StreamObserver<MonitorSystemResponse> responseObserver) {

byte[] rawUcp = request.getRawUcp().toByteArray();
logInfo("Received relayUcpToMonitorSystem request:");
logInfo("rawUcp (hex): " + bytesToHex(rawUcp));
responseObserver.onNext(buildRelayResponse(request));
responseObserver.onCompleted();
}

MonitorSystemResponse response = MonitorSystemResponse.newBuilder()
MonitorSystemResponse buildRelayResponse(RelayUcpToMonitorSystemRequest request) {

try {
byte[] rawUcp = request.getRawUcp().toByteArray();
logInfo("Received relayUcpToMonitorSystem request:");
logInfo("ucpId: " + request.getUcpId());
logInfo("rawUcp (hex): " + bytesToHex(rawUcp));
} catch (RuntimeException e) {
// relay 是旁路留存接口,内部处理失败只记录日志,不能影响跨链流程。
logWarning("Failed to process relay request, returning success as required", e);
}

return MonitorSystemResponse.newBuilder()
.setCode(0)
.setErrorMsg("")
.build();

responseObserver.onNext(response);
responseObserver.onCompleted();

}

private String bytesToHex(byte[] bytes) {
Expand All @@ -151,12 +205,27 @@ private String bytesToHex(byte[] bytes) {
}
return sb.toString();
}

private MonitorSystemResponse errorResponse(int code, String errorMsg) {
return MonitorSystemResponse.newBuilder()
.setCode(code)
.setErrorMsg(errorMsg)
.build();
}

private String errorMessage(RuntimeException e) {
return e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage();
}
}

private static void logInfo(String message) {
LOGGER.info(message);
}

private static void logWarning(String message, Throwable throwable) {
LOGGER.log(Level.WARNING, message, throwable);
}

private static Logger createLogger() {
Logger logger = Logger.getLogger(MonitorSystemServer.class.getName());
logger.setUseParentHandlers(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import com.alipay.antchain.bridge.commons.core.base.CrossChainDomain;
import com.alipay.antchain.bridge.commons.core.base.CrossChainMessage;
import com.alipay.antchain.bridge.commons.core.base.UniformCrosschainPacket;
import com.alipay.antchain.bridge.ptc.committee.monitor.system.grpc.MonitorSystemResponse;
import com.alipay.antchain.bridge.ptc.committee.monitor.system.grpc.RelayUcpToMonitorSystemRequest;
import com.alipay.antchain.bridge.ptc.committee.monitor.system.grpc.VerifyCrossChainMessageInMonitorSystemRequest;
import com.google.protobuf.ByteString;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class MonitorSystemServerTest {

private MonitorSystemServer server;

private MonitorSystemServer.MonitorSystemServiceImpl service;

private byte[] validRawUcp;

@Before
public void setUp() {
server = new MonitorSystemServer();
service = server.new MonitorSystemServiceImpl();
validRawUcp = new UniformCrosschainPacket(
new CrossChainDomain("test-domain"),
CrossChainMessage.createCrossChainMessage(
CrossChainMessage.CrossChainMessageType.DEVELOPER_DESIGN,
1L,
1L,
new byte[]{1},
new byte[]{2},
new byte[]{3},
new byte[]{4},
new byte[]{5}
),
null
).encode();
}

@Test
public void testVerifySuccessAndFailureResponses() {
VerifyCrossChainMessageInMonitorSystemRequest request = verifyRequest(validRawUcp);

server.setVerifyMode(MonitorSystemServer.VerifyMode.SUCCESS);
MonitorSystemResponse response = service.buildVerifyResponse(request);
Assert.assertEquals(0, response.getCode());
Assert.assertEquals("", response.getErrorMsg());
Assert.assertTrue(response.hasVerifyCrossChainMessageInMonitorSystemResp());
Assert.assertEquals(0, response.getVerifyCrossChainMessageInMonitorSystemResp().getResult());
Assert.assertEquals("ok", response.getVerifyCrossChainMessageInMonitorSystemResp().getMsg());

server.setVerifyMode(MonitorSystemServer.VerifyMode.FAILURE);
response = service.buildVerifyResponse(request);
Assert.assertEquals(0, response.getCode());
Assert.assertEquals("", response.getErrorMsg());
Assert.assertTrue(response.hasVerifyCrossChainMessageInMonitorSystemResp());
Assert.assertEquals(1, response.getVerifyCrossChainMessageInMonitorSystemResp().getResult());
Assert.assertFalse(response.getVerifyCrossChainMessageInMonitorSystemResp().getMsg().isEmpty());
}

@Test
public void testInvalidRawUcpReturns400WithoutVerifyResponse() {
MonitorSystemResponse response = service.buildVerifyResponse(verifyRequest(new byte[]{1, 2, 3, 4}));

Assert.assertEquals(400, response.getCode());
Assert.assertTrue(response.getErrorMsg().contains("failed to decode rawUcp"));
Assert.assertFalse(response.hasVerifyCrossChainMessageInMonitorSystemResp());
}

@Test
public void testForced500And503ResponsesDoNotContainVerifyResponse() {
VerifyCrossChainMessageInMonitorSystemRequest request = verifyRequest(validRawUcp);

server.setVerifyMode(MonitorSystemServer.VerifyMode.INTERNAL_ERROR);
MonitorSystemResponse response = service.buildVerifyResponse(request);
Assert.assertEquals(500, response.getCode());
Assert.assertFalse(response.getErrorMsg().isEmpty());
Assert.assertFalse(response.hasVerifyCrossChainMessageInMonitorSystemResp());

server.setVerifyMode(MonitorSystemServer.VerifyMode.UNAVAILABLE);
response = service.buildVerifyResponse(request);
Assert.assertEquals(503, response.getCode());
Assert.assertFalse(response.getErrorMsg().isEmpty());
Assert.assertFalse(response.hasVerifyCrossChainMessageInMonitorSystemResp());
}

@Test
public void testRelayAlwaysReturnsSuccessWithoutVerifyResponse() {
for (byte[] rawUcp : new byte[][]{validRawUcp, new byte[]{1, 2, 3, 4}}) {
MonitorSystemResponse response = service.buildRelayResponse(
RelayUcpToMonitorSystemRequest.newBuilder()
.setRawUcp(ByteString.copyFrom(rawUcp))
.setUcpId("ucp-id")
.build()
);
Assert.assertEquals(0, response.getCode());
Assert.assertEquals("", response.getErrorMsg());
Assert.assertFalse(response.hasVerifyCrossChainMessageInMonitorSystemResp());
}

MonitorSystemResponse responseAfterInternalError = service.buildRelayResponse(null);
Assert.assertEquals(0, responseAfterInternalError.getCode());
Assert.assertEquals("", responseAfterInternalError.getErrorMsg());
Assert.assertFalse(responseAfterInternalError.hasVerifyCrossChainMessageInMonitorSystemResp());
}

private VerifyCrossChainMessageInMonitorSystemRequest verifyRequest(byte[] rawUcp) {
return VerifyCrossChainMessageInMonitorSystemRequest.newBuilder()
.setRawUcp(ByteString.copyFrom(rawUcp))
.setUcpId("ucp-id")
.build();
}
}
2 changes: 2 additions & 0 deletions SimpleMonitorSystem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ sudo ./bin/stop.sh
systemd模式会把服务文件安装到`/etc/systemd/system/simple-monitor-system.service`。
后台模式没有交互式终端,监管验证结果保持默认的成功状态;前台直接运行Jar时仍可输入`success`或`fail`切换结果。

前台模式还支持输入`500`或`503`,用于模拟监管系统内部错误和暂时不可用。`verifyCrossChainMessageInMonitorSystem`会先校验`rawUcp`,无法解析时返回`code=400`且不填充判定响应;`relayUcpToMonitorSystem`始终返回`code=0`且不填充判定响应。

## MonitorSystemClient

仅用于测试MonitorSystemServer功能是否正常。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,12 @@ public void verifyCrossChainMessage(VerifyCrossChainMessageRequest request, Stre
if (ObjectUtil.isNull(crossChainLane)) {
throw new InvalidRequestException("crossChainLane is null");
}
String ucpId = request.getUcpId();

// 为dioxide链定制的逻辑,支持在无实际监管逻辑和PTC逻辑的情形下将跨链信息传递给外部监管系统
if (Objects.equals(crossChainLane.getSenderDomain().getDomain(), "dioxide2")) {
log.info("receive crosschain message from Dioxide, relay to monitor system directly without verification");
MonitorNodeVerifyResult verifyResult = endorserService.relayUcpToMonitorSystem(ucp);
MonitorNodeVerifyResult verifyResult = endorserService.relayUcpToMonitorSystem(ucp, ucpId);
responseObserver.onNext(
Response.newBuilder()
.setCode(0)
Expand Down Expand Up @@ -372,11 +373,11 @@ public void verifyCrossChainMessage(VerifyCrossChainMessageRequest request, Stre
verifyResult = MonitorNodeVerifyResult.approved(endorserService.verifyUcp(crossChainLane, ucp));
} else if (monitorMessage.getMonitorType() == MonitorTypeEnum.MONITOR_OPEN.getCode()) {
log.info("crosschain message: need monitor");
verifyResult = endorserService.verifyUcpWithMonitorSystem(crossChainLane, ucp);
verifyResult = endorserService.verifyUcpWithMonitorSystem(crossChainLane, ucp, ucpId);
} else {
// 不监管 把跨链消息发给监管系统即可
log.info("crosschain message: don't need monitor");
MonitorNodeVerifyResult relayResult = endorserService.relayUcpToMonitorSystem(ucp);
MonitorNodeVerifyResult relayResult = endorserService.relayUcpToMonitorSystem(ucp, ucpId);
verifyResult = new MonitorNodeVerifyResult(
endorserService.verifyUcp(crossChainLane, ucp),
relayResult.getRegulationStatus(),
Expand Down
Loading