From 146d710172b6c8f1e0e3b56a91a540e2e155bfef Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Mon, 30 Oct 2023 15:32:59 +0100 Subject: [PATCH] feat: Add message types to xCall --- .../java/foundation/icon/xcall/CSMessage.java | 2 +- .../icon/xcall/CSMessageRequest.java | 14 +- ...sageResponse.java => CSMessageResult.java} | 14 +- .../{CallRequest.java => RollbackData.java} | 10 +- .../icon/xcall/messages/CallMessage.java | 27 ++ .../messages/CallMessageWithRollback.java | 55 +++ .../icon/xcall/messages/Message.java | 7 + .../icon/xcall/messages/XCallEnvelope.java | 107 +++++ .../icon/xcall/CallServiceImpl.java | 437 ++++++++++-------- .../icon/xcall/CallServiceTest.java | 91 ++-- docs/adr/xcall.md | 2 +- 11 files changed, 512 insertions(+), 254 deletions(-) rename contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/{CSMessageResponse.java => CSMessageResult.java} (80%) rename contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/{CallRequest.java => RollbackData.java} (89%) create mode 100644 contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessage.java create mode 100644 contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessageWithRollback.java create mode 100644 contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/Message.java create mode 100644 contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/XCallEnvelope.java diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessage.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessage.java index 46e921cb..24b9198a 100644 --- a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessage.java +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessage.java @@ -23,7 +23,7 @@ public class CSMessage { public static final int REQUEST = 1; - public static final int RESPONSE = 2; + public static final int RESULT = 2; private final int type; private final byte[] data; diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageRequest.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageRequest.java index c2f64bf3..11c8993d 100644 --- a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageRequest.java +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageRequest.java @@ -29,16 +29,16 @@ public class CSMessageRequest { private final String from; private final String to; private final BigInteger sn; - private final boolean rollback; + private final int type; private byte[] data; private final String[] protocols; - public CSMessageRequest(String from, String to, BigInteger sn, boolean rollback, byte[] data, String[] protocols) { + public CSMessageRequest(String from, String to, BigInteger sn, int type, byte[] data, String[] protocols) { this.from = from; this.to = to; this.sn = sn; - this.rollback = rollback; + this.type = type; this.data = data; if (protocols == null) { protocols = new String[]{}; @@ -63,8 +63,8 @@ public BigInteger getSn() { return sn; } - public boolean needRollback() { - return rollback; + public int getType() { + return type; } public byte[] getData() { @@ -81,7 +81,7 @@ public static void writeObject(ObjectWriter w, CSMessageRequest m) { w.write(m.to); w.write(m.sn); - w.write(m.rollback); + w.write(m.type); w.writeNullable(m.data); w.beginList(m.protocols.length); for(String protocol : m.protocols) { @@ -97,7 +97,7 @@ public static CSMessageRequest readObject(ObjectReader r) { r.readString(), r.readString(), r.readBigInteger(), - r.readBoolean(), + r.readInt(), r.readNullable(byte[].class), readProtocols(r) ); diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResponse.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResult.java similarity index 80% rename from contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResponse.java rename to contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResult.java index 6b0e4fe9..2d158152 100644 --- a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResponse.java +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CSMessageResult.java @@ -23,14 +23,14 @@ import java.math.BigInteger; -public class CSMessageResponse { +public class CSMessageResult { public static final int SUCCESS = 1; public static final int FAILURE = 0; private final BigInteger sn; private final int code; - public CSMessageResponse(BigInteger sn, int code) { + public CSMessageResult(BigInteger sn, int code) { this.sn = sn; this.code = code; } @@ -43,16 +43,16 @@ public int getCode() { return code; } - public static void writeObject(ObjectWriter w, CSMessageResponse m) { + public static void writeObject(ObjectWriter w, CSMessageResult m) { w.beginList(2); w.write(m.sn); w.write(m.code); w.end(); } - public static CSMessageResponse readObject(ObjectReader r) { + public static CSMessageResult readObject(ObjectReader r) { r.beginList(); - CSMessageResponse m = new CSMessageResponse( + CSMessageResult m = new CSMessageResult( r.readBigInteger(), r.readInt() ); @@ -62,11 +62,11 @@ public static CSMessageResponse readObject(ObjectReader r) { public byte[] toBytes() { ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); - CSMessageResponse.writeObject(writer, this); + CSMessageResult.writeObject(writer, this); return writer.toByteArray(); } - public static CSMessageResponse fromBytes(byte[] bytes) { + public static CSMessageResult fromBytes(byte[] bytes) { ObjectReader reader = Context.newByteArrayObjectReader("RLPn", bytes); return readObject(reader); } diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CallRequest.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/RollbackData.java similarity index 89% rename from contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CallRequest.java rename to contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/RollbackData.java index d50ffab6..b63dbd7f 100644 --- a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/CallRequest.java +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/RollbackData.java @@ -23,14 +23,14 @@ import score.ObjectWriter; import scorex.util.ArrayList; -public class CallRequest { +public class RollbackData { private final Address from; private final String to; private final String[] protocols; private final byte[] rollback; private boolean enabled; - public CallRequest(Address from, String to, String[] protocols, byte[] rollback) { + public RollbackData(Address from, String to, String[] protocols, byte[] rollback) { this.from = from; this.to = to; if (protocols == null) { @@ -57,7 +57,7 @@ public byte[] getRollback() { return rollback; } - public static void writeObject(ObjectWriter w, CallRequest req) { + public static void writeObject(ObjectWriter w, RollbackData req) { w.beginList(5); w.write(req.from); w.write(req.to); @@ -71,9 +71,9 @@ public static void writeObject(ObjectWriter w, CallRequest req) { w.end(); } - public static CallRequest readObject(ObjectReader r) { + public static RollbackData readObject(ObjectReader r) { r.beginList(); - CallRequest req = new CallRequest( + RollbackData req = new RollbackData( r.readAddress(), r.readString(), readProtocols(r), diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessage.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessage.java new file mode 100644 index 00000000..9cae7cac --- /dev/null +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessage.java @@ -0,0 +1,27 @@ + +package foundation.icon.xcall.messages; + +public class CallMessage extends Message { + public static final int TYPE = 1; + private byte[] data; + + public CallMessage(byte[] data) { + this.data = data; + } + + public int getType() { + return TYPE; + } + + public byte[] getData() { + return data; + } + + public byte[] toBytes() { + return data; + } + + public static CallMessage fromBytes(byte[] bytes) { + return new CallMessage(bytes); + } +} \ No newline at end of file diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessageWithRollback.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessageWithRollback.java new file mode 100644 index 00000000..e6caed97 --- /dev/null +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/CallMessageWithRollback.java @@ -0,0 +1,55 @@ +package foundation.icon.xcall.messages; + +import score.ByteArrayObjectWriter; +import score.Context; +import score.ObjectReader; +import score.ObjectWriter; + +public class CallMessageWithRollback extends Message { + public static final int TYPE = 2; + private byte[] data; + private byte[] rollback; + public CallMessageWithRollback(byte[] data, byte[] rollback) { + this.data = data; + this.rollback = rollback; + } + + public int getType() { + return TYPE; + } + + public byte[] getData() { + return data; + } + + public byte[] getRollback() { + return rollback; + } + + public static void writeObject(ObjectWriter w, CallMessageWithRollback call) { + w.beginList(2); + w.write(call.data); + w.write(call.rollback); + w.end(); + } + + public static CallMessageWithRollback readObject(ObjectReader r) { + r.beginList(); + CallMessageWithRollback call = new CallMessageWithRollback( + r.readByteArray(), + r.readByteArray() + ); + return call; + } + + public byte[] toBytes() { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + CallMessageWithRollback.writeObject(writer, this); + return writer.toByteArray(); + } + + public static CallMessageWithRollback fromBytes(byte[] bytes) { + ObjectReader reader = Context.newByteArrayObjectReader("RLPn", bytes); + return readObject(reader); + } +} diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/Message.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/Message.java new file mode 100644 index 00000000..d7869bb3 --- /dev/null +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/Message.java @@ -0,0 +1,7 @@ +package foundation.icon.xcall.messages; + +public abstract class Message { + public abstract int getType(); + + public abstract byte[] toBytes(); +} diff --git a/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/XCallEnvelope.java b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/XCallEnvelope.java new file mode 100644 index 00000000..d48808e9 --- /dev/null +++ b/contracts/javascore/xcall-lib/src/main/java/foundation/icon/xcall/messages/XCallEnvelope.java @@ -0,0 +1,107 @@ +package foundation.icon.xcall.messages; + +import java.util.List; + +import score.ByteArrayObjectWriter; +import score.Context; +import score.ObjectReader; +import score.ObjectWriter; +import scorex.util.ArrayList; + +public class XCallEnvelope { + public int type; + public byte[] message; + public String[] sources = new String[]{}; + public String[] destinations = new String[]{};; + + + public XCallEnvelope(int type, byte[] message, String[] sources, String[] destinations) { + this.type = type; + this.message = message; + this.sources = sources; + this.destinations = destinations; + } + + public XCallEnvelope(Message message, String[] sources, String[] destinations) { + this.type = message.getType(); + this.message = message.toBytes(); + this.sources = sources; + this.destinations = destinations; + } + + public XCallEnvelope(Message message) { + this.type = message.getType(); + this.message = message.toBytes(); + } + + public int getType() { + return type; + } + + public byte[] getMessage() { + return message; + } + + public String[] getSources() { + return sources; + } + + public String[] getDestinations() { + return destinations; + } + + public static void writeObject(ObjectWriter w, XCallEnvelope envelope) { + w.beginList(3); + w.write(envelope.type); + w.write(envelope.message); + w.beginList(envelope.sources.length); + for(String protocol : envelope.sources) { + w.write(protocol); + } + w.end(); + w.beginList(envelope.destinations.length); + for(String protocol : envelope.destinations) { + w.write(protocol); + } + w.end(); + w.end(); + } + + public static XCallEnvelope readObject(ObjectReader r) { + r.beginList(); + XCallEnvelope call = new XCallEnvelope( + r.readInt(), + r.readByteArray(), + readProtocols(r), + readProtocols(r) + ); + return call; + } + + private static String[] readProtocols(ObjectReader r) { + r.beginList(); + List protocolsList = new ArrayList<>(); + while(r.hasNext()) { + protocolsList.add(r.readString()); + } + int size = protocolsList.size(); + String[] protocols = new String[size]; + for(int i=0; i < size; i++) { + protocols[i] = protocolsList.get(i); + } + r.end(); + return protocols; + } + + public byte[] toBytes() { + ByteArrayObjectWriter writer = Context.newByteArrayObjectWriter("RLPn"); + XCallEnvelope.writeObject(writer, this); + return writer.toByteArray(); + } + + public static XCallEnvelope fromBytes(byte[] bytes) { + ObjectReader reader = Context.newByteArrayObjectReader("RLPn", bytes); + return readObject(reader); + } + +} diff --git a/contracts/javascore/xcall/src/main/java/foundation/icon/xcall/CallServiceImpl.java b/contracts/javascore/xcall/src/main/java/foundation/icon/xcall/CallServiceImpl.java index f69e4934..487ab0ec 100644 --- a/contracts/javascore/xcall/src/main/java/foundation/icon/xcall/CallServiceImpl.java +++ b/contracts/javascore/xcall/src/main/java/foundation/icon/xcall/CallServiceImpl.java @@ -20,8 +20,6 @@ import score.BranchDB; import score.Context; import score.DictDB; -import score.RevertedException; -import score.UserRevertedException; import score.VarDB; import score.annotation.EventLog; import score.annotation.External; @@ -31,6 +29,11 @@ import java.math.BigInteger; import java.util.Arrays; +import foundation.icon.xcall.messages.CallMessage; +import foundation.icon.xcall.messages.CallMessageWithRollback; +import foundation.icon.xcall.messages.Message; +import foundation.icon.xcall.messages.XCallEnvelope; + public class CallServiceImpl implements CallService, FeeManage { public static final int MAX_DATA_SIZE = 2048; @@ -40,10 +43,9 @@ public class CallServiceImpl implements CallService, FeeManage { private final VarDB sn = Context.newVarDB("sn", BigInteger.class); private final VarDB reqId = Context.newVarDB("reqId", BigInteger.class); - private final DictDB requests = Context.newDictDB("requests", CallRequest.class); + private final DictDB rollbacks = Context.newDictDB("rollbacks", RollbackData.class); private final DictDB proxyReqs = Context.newDictDB("proxyReqs", CSMessageRequest.class); - private final BranchDB> pendingReqs = Context.newBranchDB("pendingReqs", Boolean.class); - private final BranchDB> pendingResponses = Context.newBranchDB("pendingResponses", Boolean.class); + private final BranchDB> pendingMessages = Context.newBranchDB("pendingMessages", Boolean.class); private final DictDB successfulResponses = Context.newDictDB("successfulResponses", Boolean.class); private final DictDB defaultConnection = Context.newDictDB("defaultConnection", Address.class); @@ -91,62 +93,56 @@ private BigInteger getNextReqId() { } private void cleanupCallRequest(BigInteger sn) { - requests.set(sn, null); + rollbacks.set(sn, null); } - @Override @Payable @External - public BigInteger sendCallMessage(String _to, - byte[] _data, - @Optional byte[] _rollback, - @Optional String[] _sources, - @Optional String[] _destinations) { + public BigInteger sendCall(String _to, byte[] _data) { Address caller = Context.getCaller(); - // check if caller is a contract or rollback data is null in case of EOA - Context.require(_rollback == null || caller.isContract(), "RollbackNotPossible"); - // check size of payloads to avoid abusing - Context.require(_rollback == null || _rollback.length <= MAX_ROLLBACK_SIZE, "MaxRollbackSizeExceeded"); - - boolean needResponse = _rollback != null && _rollback.length > 0; + XCallEnvelope envelope = XCallEnvelope.fromBytes(_data); + BigInteger sn = getNextSn(); NetworkAddress dst = NetworkAddress.valueOf(_to); - BigInteger sn = getNextSn(); - if (needResponse) { - CallRequest req = new CallRequest(caller, dst.net(), _sources, _rollback); - requests.set(sn, req); - } + ProcessResult result = preProcessMessage(sn, dst, envelope); String from = new NetworkAddress(NID, caller.toString()).toString(); - CSMessageRequest msgReq = new CSMessageRequest(from, dst.account(), sn, needResponse, _data, _destinations); + CSMessageRequest msgReq = new CSMessageRequest(from, dst.account(), sn, envelope.getType(), result.data, envelope.getDestinations()); byte[] msgBytes = msgReq.toBytes(); Context.require(msgBytes.length <= MAX_DATA_SIZE, "MaxDataSizeExceeded"); + BigInteger sendSn = result.needResponse ? sn : BigInteger.ZERO; - if (_sources == null || _sources.length == 0) { - Address src = defaultConnection.get(dst.net()); - Context.require(src != null, "NoDefaultConnection"); - BigInteger fee = Context.call(BigInteger.class, src, "getFee", dst.net(), needResponse); - sendMessage(src, fee, dst.net(), CSMessage.REQUEST, - needResponse ? sn : BigInteger.ZERO, msgBytes); - } else { - for (String _src : _sources) { - Address src = Address.fromString(_src); - BigInteger fee = Context.call(BigInteger.class, src, "getFee", dst.net(), needResponse); - sendMessage(src, fee, dst.net(), CSMessage.REQUEST, - needResponse ? sn : BigInteger.ZERO, msgBytes); - } + sendMessage(envelope.getSources(), dst.net(), CSMessage.REQUEST, sendSn, msgBytes); + claimProtocolFee(); + CallMessageSent(caller, dst.toString(), sn); - } + return sn; + } - BigInteger protocolFee = getProtocolFee(); - BigInteger balance = Context.getBalance(Context.getAddress()); - Context.require(balance.compareTo(protocolFee) >= 0, "InsufficientBalance"); - Context.transfer(feeHandler.get(), balance); + @Override + @Payable + @External + public BigInteger sendCallMessage(String _to, + byte[] _data, + @Optional byte[] _rollback, + @Optional String[] _sources, + @Optional String[] _destinations) { - CallMessageSent(caller, dst.toString(), sn); + if (_sources == null || _destinations == null) { + _sources = new String[0]; + _destinations = new String[0]; + } - return sn; + Message msg; + if (_rollback == null || _rollback.length == 0) { + msg = new CallMessage(_data); + } else { + msg = new CallMessageWithRollback(_data, _rollback); + } + + XCallEnvelope envelope = new XCallEnvelope(msg, _sources, _destinations); + return sendCall(_to, envelope.toBytes()); } @Override @@ -158,55 +154,22 @@ public void executeCall(BigInteger _reqId, byte[] _data) { proxyReqs.set(_reqId, null); // compare the given data hash with the saved one Context.require(Arrays.equals(getDataHash(_data), req.getData()), "DataHashMismatch"); - - NetworkAddress from = NetworkAddress.valueOf(req.getFrom()); - CSMessageResponse msgRes = null; - String msg = ""; - - try { - Address to = Address.fromString(req.getTo()); - sendToDapp(to, req.getFrom(), _data, req.getProtocols()); - msgRes = new CSMessageResponse(req.getSn(), CSMessageResponse.SUCCESS); - } catch (UserRevertedException e) { - int code = e.getCode(); - msg = "UserReverted(" + code + ")"; - msgRes = new CSMessageResponse(req.getSn(), CSMessageResponse.FAILURE); - } catch (IllegalArgumentException | RevertedException e) { - msgRes = new CSMessageResponse(req.getSn(), CSMessageResponse.FAILURE); - msg = e.toString(); - } finally { - if (msgRes == null) { - msgRes = new CSMessageResponse(req.getSn(), CSMessageResponse.FAILURE); - msg = "UnknownFailure"; - } - CallExecuted(_reqId, msgRes.getCode(), msg); - // send response only when there was a rollback - if (!req.needRollback()) { - return; - } - - BigInteger sn = req.getSn().negate(); - if (req.getProtocols().length == 0) { - Address src = defaultConnection.get(from.net()); - Context.require(src != null, "NoDefaultConnection"); - sendMessage(src, BigInteger.ZERO, from.net(), CSMessage.RESPONSE, sn, msgRes.toBytes()); - } else { - for (String protocol : req.getProtocols()) { - sendMessage(Address.fromString(protocol), BigInteger.ZERO, from.net(), CSMessage.RESPONSE, sn, msgRes.toBytes()); - } - } - } + executeMessage(_reqId, req, _data); } @Override @External public void executeRollback(BigInteger _sn) { - CallRequest req = requests.get(_sn); + RollbackData req = rollbacks.get(_sn); Context.require(req != null, "InvalidSerialNum"); Context.require(req.enabled(), "RollbackNotEnabled"); cleanupCallRequest(_sn); - - sendToDapp(req.getFrom(), getNetworkAddress(), req.getRollback(), req.getProtocols()); + String[] protocols = req.getProtocols(); + if (protocols.length == 0) { + Context.call(req.getFrom(), "handleCallMessage", getNetworkAddress(), req.getRollback()); + } else { + Context.call(req.getFrom(), "handleCallMessage", getNetworkAddress(), req.getRollback(), protocols); + } RollbackExecuted(_sn); } @@ -216,6 +179,101 @@ public boolean verifySuccess(BigInteger _sn) { return successfulResponses.getOrDefault(_sn, false); } + /* ========== Interfaces with BMC ========== */ + @External + public void handleBTPMessage(String _from, String _svc, BigInteger _sn, byte[] _msg) { + handleMessage(_from, _msg); + } + + @External + public void handleBTPError(String _src, String _svc, BigInteger _sn, long _code, String _msg) { + handleError(_sn); + } + /* ========================================= */ + + + @Override + @External + public void handleMessage(String _fromNid, byte[] _msg) { + CSMessage msg = CSMessage.fromBytes(_msg); + Context.require(!_fromNid.equals(NID), "Invalid network ID"); + switch (msg.getType()) { + case CSMessage.REQUEST: + handleRequest(_fromNid, msg.getData()); + break; + case CSMessage.RESULT: + handleResult(msg.getData()); + break; + default: + Context.revert("UnknownMsgType(" + msg.getType() + ")"); + } + } + + @Override + @External + public void handleError(BigInteger _sn) { + CSMessageResult res = new CSMessageResult(_sn, CSMessageResult.FAILURE); + handleResult(res.toBytes()); + } + + @External(readonly = true) + public Address admin() { + return admin.get(); + } + + @External + public void setAdmin(Address _address) { + checkCallerOrThrow(admin(), "OnlyAdmin"); + admin.set(_address); + } + + @External + public void setProtocolFee(BigInteger _protocolFee) { + checkCallerOrThrow(admin(), "OnlyAdmin"); + Context.require(_protocolFee.signum() >= 0, "ValueShouldBePositive"); + protocolFee.set(_protocolFee); + } + + @External + public void setProtocolFeeHandler(Address _address) { + checkCallerOrThrow(admin(), "OnlyAdmin"); + feeHandler.set(_address); + } + + @External + public void setDefaultConnection(String _nid, Address _connection) { + checkCallerOrThrow(admin(), "OnlyAdmin"); + defaultConnection.set(_nid, _connection); + } + + @External + public void getDefaultConnection(String _nid, Address _connection) { + checkCallerOrThrow(admin(), "OnlyAdmin"); + defaultConnection.set(_nid, _connection); + } + + @External(readonly = true) + public BigInteger getProtocolFee() { + return protocolFee.getOrDefault(BigInteger.ZERO); + } + + @External(readonly = true) + public BigInteger getFee(String _net, boolean _rollback, @Optional String[] _sources) { + BigInteger fee = getProtocolFee(); + if (_sources == null || _sources.length == 0) { + Address src = defaultConnection.get(_net); + Context.require(src != null, "NoDefaultConnection"); + return fee.add(Context.call(BigInteger.class, src, "getFee", _net, _rollback)); + } + + for (String protocol : _sources) { + Address address = Address.fromString(protocol); + fee = fee.add(Context.call(BigInteger.class, address, "getFee", _net, _rollback)); + } + + return fee; + } + @Override @EventLog(indexed = 3) public void CallMessage(String _from, String _to, BigInteger _sn, BigInteger _reqId, byte[] _data) { @@ -246,64 +304,121 @@ public void RollbackExecuted(BigInteger _sn) { public void CallMessageSent(Address _from, String _to, BigInteger _sn) { } - /* ========== Interfaces with BMC ========== */ - @External - public void handleBTPMessage(String _from, String _svc, BigInteger _sn, byte[] _msg) { - handleMessage(_from, _msg); - } - @External - public void handleBTPError(String _src, String _svc, BigInteger _sn, long _code, String _msg) { - handleError(_sn); + private void sendMessage(String[] _sources, String netTo, int msgType, BigInteger sn, byte[] data) { + Address[] sources = prepareProtocols(_sources, netTo); + CSMessage msg = new CSMessage(msgType, data); + BigInteger value; + for (Address src : sources) { + value = _getFee(src, netTo, sn); + Context.call(value, src, "sendMessage", netTo, NAME, sn, msg.toBytes()); + } } - /* ========================================= */ - - @Override - @External - public void handleMessage(String _fromNid, byte[] _msg) { - CSMessage msg = CSMessage.fromBytes(_msg); - Context.require(!_fromNid.equals(NID), "Invalid network ID"); - switch (msg.getType()) { - case CSMessage.REQUEST: - handleRequest(_fromNid, msg.getData()); - break; - case CSMessage.RESPONSE: - handleResponse(msg.getData()); - break; - default: - Context.revert("UnknownMsgType(" + msg.getType() + ")"); + private BigInteger _getFee(Address conn, String net, BigInteger sn) { + if (sn.signum() == -1) { + return BigInteger.ZERO; } - } - @Override - @External - public void handleError(BigInteger _sn) { - CSMessageResponse res = new CSMessageResponse(_sn, CSMessageResponse.FAILURE); - handleResponse(res.toBytes()); + return Context.call(BigInteger.class, conn, "getFee", net, sn.signum() == 1); } - private BigInteger sendMessage(Address _connection, BigInteger value, String netTo, int msgType, BigInteger sn, byte[] data) { - CSMessage msg = new CSMessage(msgType, data); - ConnectionScoreInterface connection = new ConnectionScoreInterface(_connection); - return connection.sendMessage(value, netTo, NAME, sn, msg.toBytes()); + private int tryExecuteCall(BigInteger id, Address dapp, String from, byte[] data, String[] protocols) { + try { + _executeCall(id, dapp, from, data, protocols); + } catch (Exception e) { + CallExecuted(id, CSMessageResult.FAILURE, e.toString()); + return CSMessageResult.FAILURE; + }; + + return CSMessageResult.SUCCESS; } - private void sendToDapp(Address dapp, String from, byte[] data, String[] protocols) { + private void _executeCall(BigInteger id, Address dapp, String from, byte[] data, String[] protocols) { if (protocols.length == 0) { Context.call(dapp, "handleCallMessage", from, data); } else { Context.call(dapp, "handleCallMessage", from, data, protocols); } + CallExecuted(id, CSMessageResult.SUCCESS, ""); + } + + private Address[] prepareProtocols(String[] protocols, String toNid) { + if (protocols.length == 0) { + Address src = defaultConnection.get(toNid); + Context.require(src != null, "NoDefaultConnection"); + return new Address[]{src}; + } + + Address[] _protocols = new Address[protocols.length]; + for (int i = 0; i < protocols.length; i++) { + _protocols[i] = Address.fromString(protocols[i]); + } + + return _protocols; + } + + private class ProcessResult { + public boolean needResponse; + public byte[] data; + + public ProcessResult(boolean needResponse, byte[] data) { + this.needResponse = needResponse; + this.data = data; + } + } + + private ProcessResult preProcessMessage(BigInteger sn, NetworkAddress to, XCallEnvelope envelope) { + switch (envelope.getType()) { + case CallMessage.TYPE: + return new ProcessResult(false, envelope.getMessage()); + case CallMessageWithRollback.TYPE: + Address caller = Context.getCaller(); + CallMessageWithRollback msg = CallMessageWithRollback.fromBytes(envelope.getMessage()); + Context.require(caller.isContract(), "RollbackNotPossible"); + RollbackData req = new RollbackData(caller, to.net(), envelope.getSources(), msg.getRollback()); + rollbacks.set(sn, req); + return new ProcessResult(true, msg.getData()); + } + + Context.revert("Message type is not supported"); + return null; + } + + private void executeMessage(BigInteger reqId, CSMessageRequest req, byte[] data) { + Address to = Address.fromString(req.getTo()); + String[] protocols = req.getProtocols(); + switch (req.getType() ) { + case CallMessage.TYPE: + tryExecuteCall(reqId, to, req.getFrom(), data, protocols); + break; + case CallMessageWithRollback.TYPE: { + int code = tryExecuteCall(reqId, to, req.getFrom(), data, protocols); + BigInteger sn = req.getSn().negate(); + NetworkAddress from = NetworkAddress.valueOf(req.getFrom()); + + CSMessageResult response = new CSMessageResult(req.getSn(), code); + sendMessage(protocols, from.net(), CSMessage.RESULT, sn, response.toBytes()); + break; + } + default: + Context.revert("Message type is not yet supported"); + } + } + + private void claimProtocolFee() { + BigInteger protocolFee = getProtocolFee(); + BigInteger balance = Context.getBalance(Context.getAddress()); + Context.require(balance.compareTo(protocolFee) >= 0, "InsufficientBalance"); + Context.transfer(feeHandler.get(), balance); } private void handleRequest(String netFrom, byte[] data) { CSMessageRequest msgReq = CSMessageRequest.fromBytes(data); String from = msgReq.getFrom(); Context.require(NetworkAddress.valueOf(from).net().equals(netFrom)); - Address caller = Context.getCaller(); - if (!verifyProtocols(pendingReqs, netFrom,msgReq.getProtocols(), caller, data)) { + if (!verifyProtocols(netFrom, msgReq.getProtocols(), data)) { return; } @@ -317,41 +432,40 @@ private void handleRequest(String netFrom, byte[] data) { proxyReqs.set(reqId, msgReq); } - private void handleResponse(byte[] data) { - CSMessageResponse msgRes = CSMessageResponse.fromBytes(data); + private void handleResult(byte[] data) { + CSMessageResult msgRes = CSMessageResult.fromBytes(data); BigInteger resSn = msgRes.getSn(); - CallRequest req = requests.get(resSn); - Address caller = Context.getCaller(); + RollbackData req = rollbacks.get(resSn); if (req == null) { - Context.println("handleResponse: no request for " + resSn); + Context.println("handleResult: no request for " + resSn); return; // just ignore } - - if (!verifyProtocols(pendingResponses, req.getTo(), req.getProtocols(), caller, data)) { + if (!verifyProtocols(req.getTo(), req.getProtocols(), data)) { return; } ResponseMessage(resSn, msgRes.getCode()); switch (msgRes.getCode()) { - case CSMessageResponse.SUCCESS: + case CSMessageResult.SUCCESS: cleanupCallRequest(resSn); successfulResponses.set(resSn, true); break; - case CSMessageResponse.FAILURE: + case CSMessageResult.FAILURE: default: // emit rollback event Context.require(req.getRollback() != null, "NoRollbackData"); req.setEnabled(); - requests.set(resSn, req); + rollbacks.set(resSn, req); RollbackMessage(resSn); } } - private boolean verifyProtocols(BranchDB> db, String net, String[] protocols, Address caller, byte[] data) { + private boolean verifyProtocols(String fromNid, String[] protocols, byte[] data) { + Address caller = Context.getCaller(); if (protocols.length > 1) { byte[] hash = Context.hash("sha-256", data); - DictDB pending = db.at(hash); + DictDB pending = pendingMessages.at(hash); pending.set(caller.toString(), true); for (String protocol : protocols) { if (!pending.getOrDefault(protocol, false)) { @@ -365,64 +479,13 @@ private boolean verifyProtocols(BranchDB> db, St } else if (protocols.length == 1) { Context.require(caller.toString().equals(protocols[0]), "ProtocolSourceMismatch"); } else { - Context.require(caller.equals(defaultConnection.get(net)), "ProtocolSourceMismatch"); + Context.require(caller.equals(defaultConnection.get(fromNid)), "ProtocolSourceMismatch"); } + return true; } private byte[] getDataHash(byte[] data) { return Context.hash("keccak-256", data); } - - @External(readonly = true) - public Address admin() { - return admin.get(); - } - - @External - public void setAdmin(Address _address) { - checkCallerOrThrow(admin(), "OnlyAdmin"); - admin.set(_address); - } - - @External - public void setProtocolFee(BigInteger _protocolFee) { - checkCallerOrThrow(admin(), "OnlyAdmin"); - Context.require(_protocolFee.signum() >= 0, "ValueShouldBePositive"); - protocolFee.set(_protocolFee); - } - - @External - public void setProtocolFeeHandler(Address _address) { - checkCallerOrThrow(admin(), "OnlyAdmin"); - feeHandler.set(_address); - } - - @External - public void setDefaultConnection(String _nid, Address _connection) { - checkCallerOrThrow(admin(), "OnlyAdmin"); - defaultConnection.set(_nid, _connection); - } - - @External(readonly = true) - public BigInteger getProtocolFee() { - return protocolFee.getOrDefault(BigInteger.ZERO); - } - - @External(readonly = true) - public BigInteger getFee(String _net, boolean _rollback, @Optional String[] _sources) { - BigInteger fee = getProtocolFee(); - if (_sources == null || _sources.length == 0) { - Address src = defaultConnection.get(_net); - Context.require(src != null, "NoDefaultConnection"); - return fee.add(Context.call(BigInteger.class, src, "getFee", _net, _rollback)); - } - - for (String protocol : _sources) { - Address address = Address.fromString(protocol); - fee = fee.add(Context.call(BigInteger.class, address, "getFee", _net, _rollback)); - } - - return fee; - } } diff --git a/contracts/javascore/xcall/src/test/java/foundation/icon/xcall/CallServiceTest.java b/contracts/javascore/xcall/src/test/java/foundation/icon/xcall/CallServiceTest.java index ecf9134d..5940c1cb 100644 --- a/contracts/javascore/xcall/src/test/java/foundation/icon/xcall/CallServiceTest.java +++ b/contracts/javascore/xcall/src/test/java/foundation/icon/xcall/CallServiceTest.java @@ -24,6 +24,7 @@ import com.iconloop.score.test.ServiceManager; import com.iconloop.score.test.TestBase; +import foundation.icon.xcall.messages.CallMessageWithRollback; import score.UserRevertedException; import xcall.icon.test.MockContract; @@ -46,7 +47,6 @@ public class CallServiceTest extends TestBase { String[] baseSource; String[] baseDestination; - @BeforeEach public void setup() throws Exception { dapp = new MockContract<>(CallServiceReceiverScoreInterface.class, CallServiceReceiver.class, sm, owner); @@ -69,7 +69,8 @@ public void sendMessage_singleProtocol() { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, null, baseSource, baseDestination); // Assert - CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, false, data, new String[]{baseEthConnection}); + CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, 1, data, baseDestination); + CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); verify(baseConnection.mock).sendMessage(eq(ethNid), eq(CallService.NAME), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(xcallSpy).CallMessageSent(dapp.getAddress(), ethDapp.toString(), BigInteger.ONE); @@ -85,7 +86,7 @@ public void sendMessage_defaultProtocol() { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data); // Assert - CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, false, data, null); + CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, 1, data, null); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); verify(baseConnection.mock).sendMessage(eq(ethNid), eq(CallService.NAME), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(xcallSpy).CallMessageSent(dapp.getAddress(), ethDapp.toString(), BigInteger.ONE); @@ -117,7 +118,7 @@ public void sendMessage_multiProtocol() throws Exception { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, null, sources, destinations); // Assert - CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, false, data, destinations); + CSMessageRequest request = new CSMessageRequest(iconDappAddress.toString(), ethDapp.account.toString(), BigInteger.ONE, 1, data, destinations); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); verify(connection1.mock).sendMessage(eq(ethNid), eq(CallService.NAME), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(connection2.mock).sendMessage(eq(ethNid), eq(CallService.NAME), eq(BigInteger.ZERO), aryEq(msg.toBytes())); @@ -128,7 +129,7 @@ public void sendMessage_multiProtocol() throws Exception { public void handleResponse_singleProtocol() { // Arrange byte[] data = "test".getBytes(); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, new String[]{baseConnection.getAddress().toString()}); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, baseSource); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); // Act @@ -143,7 +144,7 @@ public void handleResponse_singleProtocol_invalidSender() { // Arrange byte[] data = "test".getBytes(); Account otherConnection = sm.createAccount(); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, new String[]{baseConnection.getAddress().toString()}); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, baseSource); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); // Act @@ -158,7 +159,7 @@ public void handleResponse_defaultProtocol() { // Arrange byte[] data = "test".getBytes(); xcall.invoke(owner, "setDefaultConnection", ethDapp.net(), baseConnection.getAddress()); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, null); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, null); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); // Act @@ -173,7 +174,7 @@ public void handleResponse_defaultProtocol_invalidSender() { // Arrange byte[] data = "test".getBytes(); xcall.invoke(owner, "setDefaultConnection", ethDapp.net(), baseConnection.getAddress()); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, null); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, null); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); Account invalidConnection = sm.createAccount(); @@ -192,7 +193,7 @@ public void handleResponse_multiProtocol() throws Exception { MockContract connection2 = new MockContract<>(ConnectionScoreInterface.class, Connection.class, sm, owner); String[] connections = {connection1.getAddress().toString(), connection2.getAddress().toString()}; - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, connections); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, connections); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); // Act @@ -208,7 +209,7 @@ public void handleResponse_multiProtocol() throws Exception { public void handleRequest_same_network_id() { // Arrange byte[] data = "test".getBytes(); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, new String[]{baseConnection.getAddress().toString()}); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, new String[]{baseConnection.getAddress().toString()}); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); // Act @@ -223,7 +224,7 @@ public void handleRequest_same_network_id() { public void executeCall_singleProtocol() { // Arrange byte[] data = "test".getBytes(); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, new String[]{baseConnection.getAddress().toString()}); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, baseSource); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); @@ -240,7 +241,7 @@ public void executeCall_defaultProtocol() throws Exception { // Arrange byte[] data = "test".getBytes(); MockContract defaultDapp = new MockContract<>(DefaultCallServiceReceiverScoreInterface.class, DefaultCallServiceReceiver.class, sm, owner); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), defaultDapp.getAddress().toString(), BigInteger.ONE, false, data, null); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), defaultDapp.getAddress().toString(), BigInteger.ONE, 1, data, null); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(owner, "setDefaultConnection", ethDapp.net(), baseConnection.getAddress()); @@ -262,7 +263,7 @@ public void executeCall_multiProtocol() throws Exception{ MockContract connection2 = new MockContract<>(ConnectionScoreInterface.class, Connection.class, sm, owner); String[] connections = {connection1.getAddress().toString(), connection2.getAddress().toString()}; - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, false, data, connections); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 1, data, connections); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(connection1.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); @@ -283,7 +284,7 @@ public void executeCall_multiProtocol_rollback() throws Exception { MockContract connection2 = new MockContract<>(ConnectionScoreInterface.class, Connection.class, sm, owner); String[] connections = {connection1.getAddress().toString(), connection2.getAddress().toString()}; - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, true, data, connections); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, 2, data, connections); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(connection1.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); @@ -292,8 +293,8 @@ public void executeCall_multiProtocol_rollback() throws Exception { xcall.invoke(user, "executeCall", BigInteger.ONE, data); // Assert - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.SUCCESS); - msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.SUCCESS); + msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); verify(dapp.mock).handleCallMessage(ethDapp.toString(), data, connections); verify(connection1.mock).sendMessage(ethNid, CallService.NAME, BigInteger.ONE.negate(), msg.toBytes()); @@ -306,7 +307,7 @@ public void executeCall_defaultProtocol_rollback() throws Exception { // Arrange byte[] data = "test".getBytes(); MockContract defaultDapp = new MockContract<>(DefaultCallServiceReceiverScoreInterface.class, DefaultCallServiceReceiver.class, sm, owner); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), defaultDapp.getAddress().toString(), BigInteger.ONE, true, data, null); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), defaultDapp.getAddress().toString(), BigInteger.ONE, CallMessageWithRollback.TYPE, data, null); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(owner, "setDefaultConnection", ethDapp.net(), baseConnection.getAddress()); @@ -316,8 +317,8 @@ public void executeCall_defaultProtocol_rollback() throws Exception { xcall.invoke(user, "executeCall", BigInteger.ONE, data); // Assert - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.SUCCESS); - msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.SUCCESS); + msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); verify(defaultDapp.mock).handleCallMessage(ethDapp.toString(), data); verify(xcallSpy).CallExecuted(BigInteger.ONE, 1, ""); @@ -328,7 +329,7 @@ public void executeCall_defaultProtocol_rollback() throws Exception { public void executeCall_failedExecution() { // Arrange byte[] data = "test".getBytes(); - CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, true, data, new String[]{baseConnection.getAddress().toString()}); + CSMessageRequest request = new CSMessageRequest(ethDapp.toString(), dapp.getAddress().toString(), BigInteger.ONE, CallMessageWithRollback.TYPE, data, baseSource); CSMessage msg = new CSMessage(CSMessage.REQUEST, request.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ZERO, msg.toBytes()); // Act @@ -336,13 +337,12 @@ public void executeCall_failedExecution() { xcall.invoke(user, "executeCall", BigInteger.ONE, data); // Assert - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); verify(baseConnection.mock).sendMessage(ethNid, CallService.NAME, BigInteger.ONE.negate(), msg.toBytes()); verify(xcallSpy).CallExecuted(BigInteger.ONE, 0, "score.RevertedException"); } - @Test public void rollback_singleProtocol() { // Arrange @@ -351,12 +351,12 @@ public void rollback_singleProtocol() { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback, baseSource, baseDestination); // Act - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Assert - verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResponse.FAILURE); + verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResult.FAILURE); verify(xcallSpy).RollbackMessage(BigInteger.ONE); assertTrue(!xcall.call(Boolean.class, "verifySuccess", BigInteger.ONE)); } @@ -370,12 +370,12 @@ public void rollback_defaultProtocol() { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback); // Act - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Assert - verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResponse.FAILURE); + verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResult.FAILURE); verify(xcallSpy).RollbackMessage(BigInteger.ONE); assertTrue(!xcall.call(Boolean.class, "verifySuccess", BigInteger.ONE)); } @@ -390,12 +390,12 @@ public void rollback_defaultProtocol_invalidSender() { Account invalidConnection = sm.createAccount(); // Act - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); assertThrows(Exception.class, ()-> xcall.invoke(invalidConnection, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes())); // Assert - verify(xcallSpy, times(0)).ResponseMessage(BigInteger.ONE, CSMessageResponse.FAILURE); + verify(xcallSpy, times(0)).ResponseMessage(BigInteger.ONE, CSMessageResult.FAILURE); verify(xcallSpy, times(0)).RollbackMessage(BigInteger.ONE); assertTrue(!xcall.call(Boolean.class, "verifySuccess", BigInteger.ONE)); } @@ -416,14 +416,14 @@ public void rollback_multiProtocol() throws Exception { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback, sources, destinations); // Act - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(connection1.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); - verify(xcallSpy, times(0)).ResponseMessage(BigInteger.ONE, CSMessageResponse.FAILURE); + verify(xcallSpy, times(0)).ResponseMessage(BigInteger.ONE, CSMessageResult.FAILURE); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Assert - verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResponse.FAILURE); + verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResult.FAILURE); verify(xcallSpy).RollbackMessage(BigInteger.ONE); assertTrue(!xcall.call(Boolean.class, "verifySuccess", BigInteger.ONE)); } @@ -436,18 +436,17 @@ public void rollback_success() throws Exception { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback, baseSource, baseDestination); // Act - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.SUCCESS); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.SUCCESS); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Assert - verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResponse.SUCCESS); + verify(xcallSpy).ResponseMessage(BigInteger.ONE, CSMessageResult.SUCCESS); verify(xcallSpy, times(0)).RollbackMessage(BigInteger.ONE); assertTrue(xcall.call(Boolean.class, "verifySuccess", BigInteger.ONE)); } - @Test public void executeRollback_singleProtocol() { // Arrange @@ -457,8 +456,8 @@ public void executeRollback_singleProtocol() { xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback, baseSource, baseDestination); - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Act @@ -481,8 +480,8 @@ public void executeRollback_defaultProtocol() throws Exception { xcall.invoke(owner, "setDefaultConnection", ethDapp.net(), baseConnection.getAddress()); xcall.invoke(defaultDapp.account, "sendCallMessage", ethDapp.toString(), data, rollback); - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(baseConnection.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); // Act @@ -510,8 +509,8 @@ public void executeRollback_multiProtocol() throws Exception { String[] sources = {connection1.getAddress().toString(), connection2.getAddress().toString()}; xcall.invoke(dapp.account, "sendCallMessage", ethDapp.toString(), data, rollback, sources, destinations); - CSMessageResponse msgRes = new CSMessageResponse(BigInteger.ONE, CSMessageResponse.FAILURE); - CSMessage msg = new CSMessage(CSMessage.RESPONSE, msgRes.toBytes()); + CSMessageResult msgRes = new CSMessageResult(BigInteger.ONE, CSMessageResult.FAILURE); + CSMessage msg = new CSMessage(CSMessage.RESULT, msgRes.toBytes()); xcall.invoke(connection1.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, CallService.NAME, BigInteger.ONE, msg.toBytes()); diff --git a/docs/adr/xcall.md b/docs/adr/xcall.md index 6531cd69..b703acd5 100644 --- a/docs/adr/xcall.md +++ b/docs/adr/xcall.md @@ -855,4 +855,4 @@ in [IIP52](https://github.com/icon-project/IIPs/blob/master/IIPS/iip-52.md). ## FAQs -... +... \ No newline at end of file