From e74e470b881e74e87bd0290ce13eb0100df0d4e7 Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Mon, 30 Oct 2023 15:32:59 +0100 Subject: [PATCH 01/20] 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 | 218 +++++++------ .../icon/xcall/CallServiceTest.java | 88 +++--- docs/adr/xcall.md | 293 ++++++++++++------ 11 files changed, 585 insertions(+), 250 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 bdacb60d..2d30dba0 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 @@ -31,6 +31,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 +45,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,50 +95,41 @@ 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); - } + Object[] result = preProcessMessage(sn, dst, envelope); + + boolean needResponse = (boolean) result[0]; + byte[] msg = (byte[]) result[1]; 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(), msg, envelope.getDestinations()); byte[] msgBytes = msgReq.toBytes(); Context.require(msgBytes.length <= MAX_DATA_SIZE, "MaxDataSizeExceeded"); + BigInteger sendSn = needResponse ? sn : BigInteger.ZERO; - if (_sources == null || _sources.length == 0) { + if (envelope.getSources().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); + sendSn, msgBytes); } else { - for (String _src : _sources) { + for (String _src : envelope.getSources()) { 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); + sendSn, msgBytes); } } @@ -149,6 +144,31 @@ public BigInteger sendCallMessage(String _to, return sn; } + @Override + @Payable + @External + public BigInteger sendCallMessage(String _to, + byte[] _data, + @Optional byte[] _rollback, + @Optional String[] _sources, + @Optional String[] _destinations) { + + if (_sources == null || _destinations == null) { + _sources = new String[0]; + _destinations = new String[0]; + } + + 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 @External public void executeCall(BigInteger _reqId, byte[] _data) { @@ -158,55 +178,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); } @@ -267,8 +254,8 @@ public void handleMessage(String _fromNid, byte[] _msg) { case CSMessage.REQUEST: handleRequest(_fromNid, msg.getData()); break; - case CSMessage.RESPONSE: - handleResponse(msg.getData()); + case CSMessage.RESULT: + handleResult(msg.getData()); break; default: Context.revert("UnknownMsgType(" + msg.getType() + ")"); @@ -278,8 +265,8 @@ public void handleMessage(String _fromNid, byte[] _msg) { @Override @External public void handleError(BigInteger _sn) { - CSMessageResponse res = new CSMessageResponse(_sn, CSMessageResponse.FAILURE); - handleResponse(res.toBytes()); + CSMessageResult res = new CSMessageResult(_sn, CSMessageResult.FAILURE); + handleResult(res.toBytes()); } private BigInteger sendMessage(Address _connection, BigInteger value, String netTo, int msgType, BigInteger sn, byte[] data) { @@ -288,21 +275,78 @@ private BigInteger sendMessage(Address _connection, BigInteger value, String net return connection.sendMessage(value, netTo, NAME, sn, msg.toBytes()); } - private void sendToDapp(Address dapp, String from, byte[] data, String[] protocols) { + 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 _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 Object[] preProcessMessage(BigInteger sn, NetworkAddress to, XCallEnvelope envelope) { + switch (envelope.getType()) { + case CallMessage.TYPE: + return new Object[]{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 Object[]{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); + if (protocols.length == 0) { + Address src = defaultConnection.get(from.net()); + Context.require(src != null, "NoDefaultConnection"); + sendMessage(src, BigInteger.ZERO, from.net(), CSMessage.RESULT, sn, response.toBytes()); + } else { + for (String protocol : protocols) { + sendMessage(Address.fromString(protocol), BigInteger.ZERO, from.net(), CSMessage.RESULT, sn, response.toBytes()); + } + } + break; + } + default: + Context.revert("Message type is not yet supported"); + } } 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; } @@ -316,41 +360,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)) { @@ -364,8 +407,9 @@ 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; } 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 2cc58a12..3612859a 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 @@ -23,6 +23,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; @@ -45,7 +46,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); @@ -68,7 +68,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("xcall-multi"), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(xcallSpy).CallMessageSent(dapp.getAddress(), ethDapp.toString(), BigInteger.ONE); @@ -84,7 +85,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("xcall-multi"), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(xcallSpy).CallMessageSent(dapp.getAddress(), ethDapp.toString(), BigInteger.ONE); @@ -116,7 +117,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("xcall-multi"), eq(BigInteger.ZERO), aryEq(msg.toBytes())); verify(connection2.mock).sendMessage(eq(ethNid), eq("xcall-multi"), eq(BigInteger.ZERO), aryEq(msg.toBytes())); @@ -127,7 +128,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 @@ -142,7 +143,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 @@ -157,7 +158,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 @@ -172,7 +173,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(); @@ -191,7 +192,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 @@ -207,7 +208,7 @@ public void handleResponse_multiProtocol() throws Exception { 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, "xcall-multi", BigInteger.ZERO, msg.toBytes()); @@ -224,7 +225,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()); @@ -246,7 +247,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, "xcall-multi", BigInteger.ZERO, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, "xcall-multi", BigInteger.ZERO, msg.toBytes()); @@ -267,7 +268,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, "xcall-multi", BigInteger.ZERO, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, "xcall-multi", BigInteger.ZERO, msg.toBytes()); @@ -276,8 +277,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, "xcall-multi", BigInteger.ONE.negate(), msg.toBytes()); @@ -290,7 +291,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()); @@ -300,8 +301,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, ""); @@ -312,7 +313,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, "xcall-multi", BigInteger.ZERO, msg.toBytes()); // Act @@ -320,8 +321,8 @@ 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, "xcall-multi", BigInteger.ONE.negate(), msg.toBytes()); verify(xcallSpy).CallExecuted(BigInteger.ONE, 0, "score.RevertedException"); } @@ -335,12 +336,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, "xcall-multi", 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)); } @@ -354,12 +355,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, "xcall-multi", 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)); } @@ -374,12 +375,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, "xcall-multi", 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)); } @@ -400,14 +401,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, "xcall-multi", 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, "xcall-multi", 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)); } @@ -420,18 +421,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, "xcall-multi", 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 @@ -441,8 +441,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, "xcall-multi", BigInteger.ONE, msg.toBytes()); // Act @@ -465,8 +465,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, "xcall-multi", BigInteger.ONE, msg.toBytes()); // Act @@ -494,8 +494,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, "xcall-multi", BigInteger.ONE, msg.toBytes()); xcall.invoke(connection2.account, "handleBTPMessage", ethNid, "xcall-multi", BigInteger.ONE, msg.toBytes()); diff --git a/docs/adr/xcall.md b/docs/adr/xcall.md index 74036862..202bfb00 100644 --- a/docs/adr/xcall.md +++ b/docs/adr/xcall.md @@ -31,7 +31,56 @@ connections at all. ### Sending Messages -Sending messages via xCall is simply done by calling sendCallMessage on the xCall contract. +Sending messages via xCall is done by constructing a xCall message envelope and calling `sendCall` with a +destination networkAddress `_to`. +``` +/** + * Sends a call message to the contract on the destination chain. + * + * @param _to The network address of the callee on the destination chain + * @param _data The xCall envelope + * @return The serial number of the request + */ +payable external sendCall(String _to, byte[] _data) returns Integer; +``` + +##### Message Envelope Structure + +All structure are RLP encoded in the order as shown below. + +The Envelope is the structure received by sendCall method. +``` +Envelope { + int messageType, + Message message, + String[] sources, + String[] destinations, +} +``` + +##### Message Objects +All Message objects have a TypeId specifying its type + +``` +TypeId = 1 +CallMessage { + byte[] data +} + +``` + +``` +TypeId = 2 +CallMessageWithRollback { + byte[] data, + byte[] rollback, + +} + +``` + +#### Legacy send Interface +Sending messages via xCall can be done by calling sendCallMessage on the xCall contract. `_to` address is a networkAddress used by xCall to figure out the destination chain. The user can also specify which connections to use, if not specified, the default connections will be used. This also allows dapps to have their messages secured by multiple protocols. @@ -348,8 +397,9 @@ CSMessageRequest { String from; String to; BigInteger sn; - boolean rollback; - bytes data; + int messageType + // RLP encoded message + bytes message; String[] protocols; } ``` @@ -359,7 +409,7 @@ CSMessageRequest { ``` int SUCCESS = 1; int FAILURE = 0; -CSMessageResponse { +CSMessageResult { BigInteger sn; int code; } @@ -369,9 +419,9 @@ CSMessageResponse { ``` int REQUEST = 1; -int RESPONSE = 2; +int RESULT = 2; CSMessage { - // The message type, either REQUEST or RESPONSE + // The message type, either REQUEST or RESULT int type; // RLP encoded bytes of the Message bytes data; @@ -381,7 +431,7 @@ CSMessage { #### Internal structs ``` -CallRequest { +RollbackData { Address from; String netTo; String[] protocols; @@ -399,12 +449,11 @@ NID: sn: reqId: -requests: sn -> CallRequest +rollbacks: sn -> RollbackData proxyReqs: reqId -> CSMessageRequest # default values should be false in case of boolean storage -pendingReqs: msgHash -> connection address -> boolean -pendingResponses: msgHash -> connection address -> boolean +pendingMessages: msgHash -> connection address -> boolean successfulResponses: sn -> boolean admin: @@ -429,71 +478,100 @@ function init(String networkId) { #### Sending messages -`sendCallMessage` sends some arbitrary data to `_to` via a path specified by the caller. +`sendCall` sends some arbitrary data to `_to` via a path specified by the caller. - `_to`: The network address of the target contract. -- `_data`: The data to be sent to the `_to` contract. -- `_rollback`: The data to be returned to the caller in case of failure. -- `_sources`: A set of addresses representing the connections to be used when sending the message. - These connections are also used to verify potential rollbacks -- `_destination`: The addresses that the target contract should wait for messages from before considering it complete. +- `_data`: The rlp encoded xCall envelope. ``` -payable external function sendCallMessage(String _to, - byte[] _data, - @Optional bytes _rollback, - @Optional String[] _sources - @Optional String[] _destinations) returns Integer { +payable external sendCall(String _to, byte[] _data) returns Integer { caller = getCaller() - require(caller.isContract() || _rollback == null, "RollbackNotPossible"); - require(_rollback == null || _rollback.length <= MAX_ROLLBACK_SIZE, "MaxRollbackSizeExceeded") - + Envelope envelope = Envelope.decode(_data) sn++ - dst = NetworkAddress(_to) from = NetworkAddress(NID, caller).toString() + to = NetworkAddress(_to) - needResponse = _rollback != null && _rollback.length > 0 - if needResponse: - req = CallRequest(caller, dst.net(), _sources, _rollback) - requests[sn] = req + needResponse, msg = preProcessMessage(sn, to, envelope) - - msgReq = CSMessageRequest(from, dst.account(), sn, needResponse, _data, _destinations) - msg = CSMessage(CSMessage.REQUEST, msgReq.toBytes()).toBytes(); + msgReq = CSMessageRequest(from, to.account(), sn, envelope.type, msg, envelope.destinations) + msg = CSMessage(CSMessage.REQUEST, msgReq.toBytes()).toBytes() require(msg.length <= MAX_DATA_SIZE, "MaxDataSizeExceeded") sendSn = needResponse ? sn : 0 - if _sources == []: - src = defaultConnection[dst.net()] - fee = src->getFee(dst.net(), needResponse) - src->sendMessage(fee, dst.net(), "xcall-multi", sendSn, msg) + if protocolConfig.sources == []: + src = defaultConnection[to.net()] + fee = src->getFee(to.net(), needResponse) + src->sendMessage(fee, to.net(), "xcall-multi", sendSn, msg) else: - for src in sources: - fee = src->getFee(dst.net(), needResponse) - src->sendMessage(fee, dst.net(), "xcall-multi", sendSn, msg) + for src in protocolConfig.sources: + fee = src->getFee(to.net(), needResponse) + src->sendMessage(fee, to.net(), "xcall-multi", sendSn, msg) - remaningBalance = getBalance(); - require(remaningBalance >= getProtocolFee()) + remainingBalance = getBalance(); + require(remainingBalance >= getProtocolFee()) transfer(feeHandler, balance) emit CallMessageSent(caller, dst.toString(), sn) return sn } +``` +`sendCallMessage` sends some arbitrary data to `_to` via a path specified by the caller. + +- `_to`: The network address of the target contract. +- `_data`: The data to be sent to the `_to` contract. +- `_rollback`: The data to be returned to the caller in case of failure. +- `_sources`: A set of addresses representing the connections to be used when sending the message. + These connections are also used to verify potential rollbacks +- `_destination`: The addresses that the target contract should wait for messages from before considering it complete. + +``` +payable external function sendCallMessage(String _to, + byte[] _data, + @Optional bytes _rollback, + @Optional String[] _sources + @Optional String[] _destinations) returns Integer { + if (_rollback == null || _rollback.length == 0): + msg = new CallMessage(_data); + else: + msg = new CallMessageWithRollback(_data, _rollback) + + envelope = new XCallEnvelope(msg, _sources, _destinations) + return sendCall(_to, envelope.toBytes()); + + +} +``` + +Internal method where message types can implement type specific logic. +``` +internal function preProcessMessage(int sn, NetworkAddress to, XCallEnvelope envelope) return (boolean, byte[]) { + switch (envelope.type) { + case CallMessage.Type: + return false, message; + case CallMessageWithRollback.Type: + require(caller.isContract(), "RollbackNotPossible"); + msg = CallMessageWithRollback(message); + req = CallRequest(caller, to.net(), envelope.sources, msg.rollback); + rollbacks[sn] = req; + + return true, msg.data; + } +} ``` #### Receiving messages `handleMessage` is the external function used by connections to deliver messages. -```javascript +``` external function handleMessage(String _fromNid, bytes _msg) { msg = CSMessage.decode(_msg); switch (msg.type) : case CSMessage.REQUEST: handleRequest(_fromNid, msg.data); break; - case CSMessage.RESPONSE: + case CSMessage.RESULT: handleResponse(msg.data); break; default: @@ -528,28 +606,35 @@ external function handleBTPError(String _src, String _svc, BigInteger _sn, long } ``` +``` +internal function verifyProtocols(String srcNet, String[] protocols, byte[] data) returns boolean { + source = getCaller() + _hash = hash(data) + if (protocols.length > 1): + pendingMessages[_hash][source] = true + for (protocol : protocols): + if (!pendingMessages[_hash][protocol]): + return false + for (protocol : protocols): + pendingMessages[_hash][protocol] = null + else if (protocols.length == 1): + require(source == protocols[0]) + else: + require(source == defaultConnection[srcNet]) + + return true +} +``` + ``` internal function handleRequest(String srcNet, bytes data) { msgReq = CSMessageRequest.decode(data); + if !verifyProtocols(srcNet, msgReq.protocolConfig, hash(data)): + return; + + reqId = getNextReqId(); from = NetworkAddress(msgReq.from); require(from.net() == srcNet); - source = getCaller(); - - if (msgReq.protocols.length > 1): - _hash = hash(data); - pendingReqs[_hash][source] = true; - for (protocol : msgReq.protocols): - if (!pendingReqs[_hash][protocol]): - return; - - for (protocol : msgReq.protocols): - pendingReqs[_hash][protocol] = null; - else if (msgReq.protocols.length == 1): - require(source == msgReq.protocols[0]); - else: - require(source == defaultConnection[srcNet]); - reqId = getNextReqId(); - emit CallMessage(msgReq.from, msgReq.to, msgReq.sn, reqId, msgReq.data); msgReq.data = hash(msgReq.data) proxyReqs[reqId] = msgReq; @@ -560,30 +645,18 @@ internal function handleRequest(String srcNet, bytes data) { internal function handleResponse(data bytes) { response = CSMessageResponse.decode(data); resSn = response.sn; - req = requests[resSn]; - source = getCaller + req = rollbacks[resSn]; if req == null: return; // just ignore - if req.protocols.length > 1: - _hash = hash(data); - pendingResponses.at(_hash).set(source, true); - for protocol : req.protocols: - if !pendingResponses[_hash][protocol]: - return; - - for (String protocol : protocols): - pendingResponses[_hash][protocol] = null - else if (msgReq.protocols.length == 1): - require(source == msgReq.protocols[0]); - else: - require(source == defaultConnection[req.netTo]); + if !verifyProtocols(req.netTo, req.protocolConfig, hash(data)): + return; emit ResponseMessage(resSn, response.getCode()); switch response.getCode(): case CSMessageResponse.SUCCESS: - requests[resSn] = null; + rollbacks[resSn] = null; successfulResponses[resSn] = 1; break; case CSMessageResponse.FAILURE: @@ -591,7 +664,7 @@ internal function handleResponse(data bytes) { // emit rollback event require(req.rollback != null, "NoRollbackData"); req.enabled = true; - requests[resSn] = req; + rollbacks[resSn] = req; emit RollbackMessage(resSn); } ``` @@ -609,49 +682,71 @@ external function executeCall(Integer _reqId, byte[] _data) { proxyReqs[_reqId] == null; assert hash(_data) == req.data + executeCallRequest(_reqId, r) + } - from = NetworkAddress(req.from); - ErrorMessage = "" - try: - if req.protocols == []: - req.to->handleCallMessage(req.from, _data); - else: - req.to->handleCallMessage(req.from, _data, req.protocols); - response = new CSMessageResponse(req.sn, CSMessageResponse.SUCCESS); - catch err: - response = new CSMessageResponse(req.sn, CSMessageResponse.FAILURE); - ErrorMessage = err.message +``` - emit CallExecuted(_reqId, response.code, response.msg, ErrorMessage); +Method where message specific execution logic is handled. +``` +internal function executeMessage(int reqId, CallRequest req) { + switch (req.type) { + case CallMessage.Type: + tryExecute(reqId, req.from, req.data, req.protocols); + case CallMessageWithRollback.Type: + code = tryExecute(reqId, req.from, req.data, req.protocols); + response = new CSMessageResponse(req.sn, code); + msg = CSMessage(CSMessage.RESULT, response.toBytes()); - if req.needRollback(): sn = req.sn.negate(); - msg = CSMessage(CSMessage.RESPONSE, response.toBytes()); if req.protocols == []: protocol = defaultConnection[from.net()] protocol->sendMessage(from.net(), "xcall-multi", sn, msg.toBytes()) else: for (String protocol : req.protocols): protocol->sendMessage(from.net(), "xcall-multi", sn, msg.toBytes()) + default: + revert; } - +} ``` ``` external function executeRollback(Integer _sn) { - req = requests.get(_sn); + req = rollbacks.get(_sn); require(req != null, "InvalidSerialNum"); require(req.enabled, "RollbackNotEnabled"); - requests[_sn] = null; + rollbacks[_sn] = null; if req.protocols == []: - req.from->handleCallMessage(getNetworkAddress(), req.rollback); + req.to->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols); else: - req.from->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols); + req.to->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols); emit RollbackExecuted(_sn); } +``` +``` +internal function tryExecuteCall(int id, String from, bytes data, String[] protocols) returns String { + try: + executeCall(id, from, data, protocols); + catch Error as e: + emit CallExecuted(id, CSMessageResponse.FAILURE, e.message); + return CSMessageResponse.FAILURE; + return CSMessageResponse.SUCCESS; +} +``` + +``` +internal function executeCall(int id, String from, bytes data, String[] protocols) { + if req.protocols == []: + req.to->handleCallMessage(from, data); + else: + req.to->handleCallMessage(from, data, protocols); + + emit CallExecuted(id, CSMessageResponse.SUCCESS, ""); +} ``` ### Admin methods @@ -695,9 +790,9 @@ external readonly function getProtocolFee() returns Integer { ``` ``` -external readonly function getFee(String _net, - boolean _rollback - @Optional String[] _sources) +external readonly function getFee(String _net, + boolean _rollback + @Optional String[] _sources) returns Integer { fee = protocolFee; if _sources == [] { From a81e140f97d25256e8a172e4744fa9893dcbec71 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 9 Nov 2023 10:03:13 +0545 Subject: [PATCH 02/20] feat: add multi message --- Cargo.lock | 1 + contracts/cosmwasm-vm/cw-xcall-lib/Cargo.toml | 2 +- contracts/cosmwasm-vm/cw-xcall-lib/src/lib.rs | 1 + .../cw-xcall-lib/src/message/call_message.rs | 58 +++++++++++++ .../src/message/call_message_rollback.rs | 60 +++++++++++++ .../cw-xcall-lib/src/message/envelope.rs | 70 +++++++++++++++ .../cw-xcall-lib/src/message/mod.rs | 77 ++++++++++++++++ .../cw-xcall-lib/src/message/msg_trait.rs | 22 +++++ .../cw-xcall-lib/src/message/msg_type.rs | 26 ++++++ .../cw-xcall-lib/src/message_types.rs | 17 ++++ .../cosmwasm-vm/cw-xcall/src/assertion.rs | 2 +- .../cosmwasm-vm/cw-xcall/src/execute_call.rs | 2 +- .../cw-xcall/src/handle_call_message.rs | 2 +- .../cw-xcall/src/send_call_message.rs | 87 ++++++++++++++----- .../cosmwasm-vm/cw-xcall/src/types/request.rs | 26 +++--- .../tests/test_handle_call_message.rs | 10 +-- 16 files changed, 421 insertions(+), 42 deletions(-) create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs create mode 100644 contracts/cosmwasm-vm/cw-xcall-lib/src/message_types.rs diff --git a/Cargo.lock b/Cargo.lock index 10d3a098..7904894d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,6 +416,7 @@ name = "cw-xcall-lib" version = "0.1.0" dependencies = [ "anyhow", + "common", "cosmwasm", "cosmwasm-schema", "cosmwasm-std", diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/Cargo.toml b/contracts/cosmwasm-vm/cw-xcall-lib/Cargo.toml index 48467885..0f85bac0 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/Cargo.toml +++ b/contracts/cosmwasm-vm/cw-xcall-lib/Cargo.toml @@ -36,7 +36,7 @@ schemars = {workspace=true} serde = { workspace=true} thiserror = { workspace=true} debug_print={workspace=true} - +common = { git = "https://github.com/icon-project/IBC-Integration.git",branch="main" } [dev-dependencies] diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/lib.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/lib.rs index ae13fdb2..d32be794 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/lib.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/lib.rs @@ -1,5 +1,6 @@ pub mod dapp_msg; pub mod dapp_multi_msg; +pub mod message; pub mod network_address; pub mod xcall_connection_msg; pub mod xcall_msg; diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs new file mode 100644 index 00000000..3aca1b97 --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs @@ -0,0 +1,58 @@ +use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; + +use super::{msg_trait::IMessage, msg_type::MessageType}; + +#[derive(Clone)] +pub struct CallMessage { + pub msg_type: MessageType, + pub data: Vec, +} + +impl Encodable for CallMessage { + fn rlp_append(&self, stream: &mut RlpStream) { + stream + .begin_list(2) + .append(&Into::::into(self.msg_type.clone())) + .append(&self.data); + } +} + +impl Decodable for CallMessage { + fn decode(rlp: &rlp::Rlp) -> Result { + let msg_type: u8 = rlp.val_at(0)?; + + Ok(Self { + msg_type: MessageType::from(msg_type), + data: rlp.val_at(1)?, + }) + } +} + +impl IMessage for CallMessage { + fn rollback(&self) -> Option> { + None + } + + fn data(&self) -> Vec { + self.data.clone() + } + + fn msg_type(&self) -> &MessageType { + &self.msg_type + } + + fn should_persist(&self) -> bool { + false + } + + fn to_bytes(&self) -> Result, DecoderError> { + Ok(rlp::encode(self).to_vec()) + } + + // fn from_bytes(bytes: Vec) -> Result { + // let rlp = rlp::Rlp::new(&bytes); + // let msg = Self::decode(&rlp)?; + + // Ok(msg) + // } +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs new file mode 100644 index 00000000..9b32ad30 --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -0,0 +1,60 @@ +use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; + +use super::{msg_trait::IMessage, msg_type::MessageType}; + +#[derive(Clone)] +pub struct CallMessageWithRollback { + pub msg_type: MessageType, + pub data: Vec, + pub rollback: Vec, +} + +impl Encodable for CallMessageWithRollback { + fn rlp_append(&self, stream: &mut RlpStream) { + stream + .begin_list(2) + .append(&Into::::into(self.msg_type.clone())) + .append(&self.data) + .append(&self.rollback); + } +} + +impl Decodable for CallMessageWithRollback { + fn decode(rlp: &rlp::Rlp) -> Result { + let msg_type: u8 = rlp.val_at(0)?; + + Ok(Self { + msg_type: MessageType::from(msg_type), + data: rlp.val_at(1)?, + rollback: rlp.val_at(2)?, + }) + } +} + +impl IMessage for CallMessageWithRollback { + fn rollback(&self) -> Option> { + Some(self.rollback.clone()) + } + + fn data(&self) -> Vec { + self.data.clone() + } + + fn msg_type(&self) -> &MessageType { + &self.msg_type + } + + fn should_persist(&self) -> bool { + true + } + fn to_bytes(&self) -> Result, DecoderError> { + Ok(rlp::encode(self).to_vec()) + } + + // fn from_bytes(bytes: Vec) -> Result { + // let rlp = rlp::Rlp::new(&bytes); + // let msg = Self::decode(&rlp)?; + + // Ok(msg) + // } +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs new file mode 100644 index 00000000..9ba017aa --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -0,0 +1,70 @@ +use common::rlp::{self, Decodable, DecoderError, Encodable}; + +use super::{ + call_message::CallMessage, call_message_rollback::CallMessageWithRollback, msg_trait::IMessage, + msg_type::MessageType, AnyMessage, +}; + +pub struct Envelope { + pub message: AnyMessage, + pub sources: Vec, + pub destinations: Vec, +} + +impl Envelope { + pub fn new(msg: AnyMessage, sources: Vec, destinations: Vec) -> Self { + Self { + message: msg, + sources: sources, + destinations: destinations, + } + } +} + +impl Encodable for Envelope { + fn rlp_append(&self, stream: &mut common::rlp::RlpStream) { + stream.begin_list(4); + stream.append(&Into::::into(self.message.msg_type().clone())); + stream.append(&self.message.to_bytes().unwrap()); + stream.begin_list(self.sources.len()); + for source in self.sources.iter() { + stream.append(source); + } + for dest in self.destinations.iter() { + stream.append(dest); + } + } +} + +impl Decodable for Envelope { + fn decode(rlp: &rlp::Rlp) -> Result { + let msg_int: u8 = rlp.val_at(0)?; + let msg_type = MessageType::from(msg_int); + let message_bytes: Vec = rlp.val_at(1)?; + let message = decode_message(msg_type, message_bytes)?; + + let sources = rlp.at(2)?; + let sources: Vec = sources.as_list()?; + let destinations = rlp.at(3)?; + let destinations: Vec = destinations.as_list()?; + + Ok(Envelope { + message, + sources, + destinations, + }) + } +} + +pub fn decode_message(msg_type: MessageType, bytes: Vec) -> Result { + match msg_type { + MessageType::BasicMessage => { + let msg: CallMessage = rlp::decode(&bytes)?; + Ok(AnyMessage::CallMessage(msg)) + } + MessageType::MessageWithRollback => { + let msg: CallMessageWithRollback = rlp::decode(&bytes)?; + Ok(AnyMessage::CallMessageWithRollback(msg)) + } + } +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs new file mode 100644 index 00000000..5b88af4c --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs @@ -0,0 +1,77 @@ +use common::rlp::{self, Decodable, DecoderError, Encodable}; + +use self::{ + call_message::CallMessage, call_message_rollback::CallMessageWithRollback, msg_trait::IMessage, + msg_type::MessageType, +}; + +pub mod call_message; +pub mod call_message_rollback; +pub mod envelope; +pub mod msg_trait; +pub mod msg_type; +#[derive(Clone)] +pub enum AnyMessage { + CallMessage(CallMessage), + CallMessageWithRollback(CallMessageWithRollback), +} + +impl IMessage for AnyMessage { + fn rollback(&self) -> Option> { + match self { + AnyMessage::CallMessage(m) => m.rollback(), + AnyMessage::CallMessageWithRollback(m) => m.rollback(), + } + } + + fn data(&self) -> Vec { + match self { + AnyMessage::CallMessage(m) => m.data(), + AnyMessage::CallMessageWithRollback(m) => m.data(), + } + } + + fn msg_type(&self) -> &MessageType { + match self { + AnyMessage::CallMessage(m) => m.msg_type(), + AnyMessage::CallMessageWithRollback(m) => m.msg_type(), + } + } + + fn should_persist(&self) -> bool { + match self { + AnyMessage::CallMessage(m) => m.should_persist(), + AnyMessage::CallMessageWithRollback(m) => m.should_persist(), + } + } + + fn to_bytes(&self) -> Result, DecoderError> { + match self { + AnyMessage::CallMessage(m) => m.to_bytes(), + AnyMessage::CallMessageWithRollback(m) => m.to_bytes(), + } + } + + // fn from_bytes(bytes:Vec)->Result { + // todo!() + // } +} + +// impl Encodable for AnyMessage { +// fn rlp_append(&self, s: &mut common::rlp::RlpStream) { +// match self{ +// AnyMessage::CallMessage(m)=>{ +// s.append(&rlp::encode(m)); +// }, +// AnyMessage::CallMessageWithRollback(m)=>{ +// s.append(&rlp::encode(m)); +// } +// } +// } +// } + +// impl Decodable for AnyMessage { +// fn decode(rlp: &rlp::Rlp) -> Result { + +// } +// } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs new file mode 100644 index 00000000..13c11a2d --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs @@ -0,0 +1,22 @@ +use common::rlp::{self, Decodable, DecoderError, Encodable}; + +use super::msg_type::MessageType; + +pub trait IMessage: Clone { + fn rollback(&self) -> Option>; + fn data(&self) -> Vec; + fn msg_type(&self) -> &MessageType; + // fn from_bytes(bytes: Vec) -> Result { + // let rlp = rlp::Rlp::new(&bytes); + // let msg = Self::decode(&rlp)?; + + // Ok(msg) + // } + + // fn to_bytes(&self) -> Vec { + // rlp::encode(self).to_vec() + // } + fn should_persist(&self) -> bool; + fn to_bytes(&self) -> Result, DecoderError>; + //fn from_bytes(bytes:Vec)->Result; +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs new file mode 100644 index 00000000..3d81f4af --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs @@ -0,0 +1,26 @@ +use serde::Serialize; + +#[derive(Clone,Debug, Serialize, serde::Deserialize, PartialEq, Eq)] +pub enum MessageType { + BasicMessage = 1, + MessageWithRollback = 2, +} + +impl Into for MessageType { + fn into(self) -> u8 { + match self { + Self::BasicMessage => 1, + Self::MessageWithRollback => 2, + } + } +} + +impl From for MessageType { + fn from(value: u8) -> Self { + match value { + 1 => MessageType::BasicMessage, + 2 => MessageType::MessageWithRollback, + _ => panic!("unsupported message type"), + } + } +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message_types.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message_types.rs new file mode 100644 index 00000000..d91a78d8 --- /dev/null +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message_types.rs @@ -0,0 +1,17 @@ +use common::rlp::Encodable; +use common::rlp::Decodable; + + +pub struct Message { + msg_type:MessageType, + data:Vec, +} + + +pub struct MessageWithRollback{ + msg_type:MessageType, + data:Vec, + rollback:Vec, +} + + diff --git a/contracts/cosmwasm-vm/cw-xcall/src/assertion.rs b/contracts/cosmwasm-vm/cw-xcall/src/assertion.rs index 2e608cde..f992acf1 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/assertion.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/assertion.rs @@ -200,6 +200,6 @@ impl<'a> CwCallService<'a> { /// `querier` object to get information about the contract at the given `address`. If the query is /// successful, it returns `true`, indicating that the address is a valid contract. If the query fails, /// it returns false ` -fn is_contract(querier: QuerierWrapper, address: &Addr) -> bool { +pub fn is_contract(querier: QuerierWrapper, address: &Addr) -> bool { querier.query_wasm_contract_info(address).is_ok() } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs index 41536e64..9096b30f 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs @@ -99,7 +99,7 @@ impl<'a> CwCallService<'a> { }; let mut submsgs: Vec = vec![]; let sn: i64 = -(request.sequence_no() as i64); - if request.rollback() { + if request.need_response() { let message: CSMessage = response.into(); let mut reply_address = request.protocols().clone(); let from = request.from().clone(); diff --git a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs index 8af3a9ab..d917397f 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs @@ -64,7 +64,7 @@ impl<'a> CwCallService<'a> { request.from().clone(), request.to().clone(), request.sequence_no(), - request.rollback(), + request.msg_type(), keccak256(request.data().unwrap()).to_vec(), request.protocols().clone(), ); diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index 9f888003..b83d84ae 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -1,7 +1,13 @@ +use common::rlp::{self, Decodable}; use cosmwasm_std::{coins, BankMsg}; +use cw_xcall_lib::message::call_message::CallMessage; +use cw_xcall_lib::message::msg_trait::IMessage; +use cw_xcall_lib::message::msg_type::MessageType; +use cw_xcall_lib::message::AnyMessage; +use cw_xcall_lib::message::{call_message_rollback::CallMessageWithRollback, envelope::Envelope}; use cw_xcall_lib::network_address::NetworkAddress; -use crate::types::LOG_PREFIX; +use crate::{assertion::is_contract, types::LOG_PREFIX}; use super::*; @@ -17,24 +23,54 @@ impl<'a> CwCallService<'a> { sources: Vec, destinations: Vec, ) -> Result { - let caller = info.sender; - let config = self.get_config(deps.as_ref().storage)?; - let nid = config.network_id; - - self.ensure_caller_is_contract_and_rollback_is_null(deps.as_ref(), &caller, &rollback)?; - - let need_response = rollback.is_some(); - - let rollback_data = match rollback { - Some(data) => data, - None => vec![], + let msg = if rollback.is_some() { + AnyMessage::CallMessageWithRollback(CallMessageWithRollback { + msg_type: MessageType::MessageWithRollback, + data: data, + rollback: rollback.unwrap(), + }) + } else { + AnyMessage::CallMessage(CallMessage { + data, + msg_type: MessageType::BasicMessage, + }) }; + let envelope = Envelope::new(msg, sources, destinations); + return self.send_call(deps, info, to, envelope); + } - self.ensure_rollback_length(&rollback_data)?; - println!("{LOG_PREFIX} Packet Validated"); + pub fn validate_payload( + &self, + deps: Deps, + caller: &Addr, + envelope: &Envelope, + ) -> Result<(), ContractError> { + match &envelope.message { + AnyMessage::CallMessage(_m) => Ok(()), + AnyMessage::CallMessageWithRollback(m) => { + if is_contract(deps.querier, caller) { + return Err(ContractError::RollbackNotPossible); + } + self.ensure_rollback_length(&m.rollback().unwrap())?; + Ok(()) + } + } + } + + pub fn send_call( + &self, + deps: DepsMut, + info: MessageInfo, + to: NetworkAddress, + envelope: Envelope, + ) -> Result { + let caller = info.sender.clone(); + let config = self.get_config(deps.as_ref().storage)?; + let nid = config.network_id; + self.validate_payload(deps.as_ref(), &caller, &envelope)?; let sequence_no = self.get_next_sn(deps.storage)?; - let mut confirmed_sources = sources.clone(); + let mut confirmed_sources = envelope.sources.clone(); let from = NetworkAddress::new(&nid, caller.as_ref()); if confirmed_sources.is_empty() { @@ -42,22 +78,29 @@ impl<'a> CwCallService<'a> { confirmed_sources = vec![default.to_string()] } - if need_response { - let request = - CallRequest::new(caller.clone(), to.clone(), sources, rollback_data, false); + if envelope.message.should_persist() { + let rollback_data = envelope.message.rollback().unwrap(); + let request = CallRequest::new( + caller.clone(), + to.clone(), + envelope.sources, + rollback_data, + false, + ); self.store_call_request(deps.storage, sequence_no, &request)?; } - let call_request = CSMessageRequest::new( from, to.account(), sequence_no, - need_response, - data.to_vec(), - destinations, + envelope.message.msg_type().clone(), + envelope.message.data(), + envelope.destinations, ); + let need_response = call_request.need_response(); + let message: CSMessage = call_request.into(); let sn: i64 = if need_response { sequence_no as i64 } else { 0 }; let mut total_spent = 0_u128; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs index 6cdf06ab..e8734a90 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs @@ -1,7 +1,7 @@ use super::*; use common::rlp::Nullable; use cosmwasm_std::Addr; -use cw_xcall_lib::network_address::NetworkAddress; +use cw_xcall_lib::{message::msg_type::MessageType, network_address::NetworkAddress}; use serde::{Deserialize, Serialize}; use std::str::FromStr; @@ -11,7 +11,7 @@ pub struct CSMessageRequest { to: Addr, sequence_no: u128, protocols: Vec, - rollback: bool, + msg_type: MessageType, data: Nullable>, } @@ -20,7 +20,7 @@ impl CSMessageRequest { from: NetworkAddress, to: Addr, sequence_no: u128, - rollback: bool, + msg_type: MessageType, data: Vec, protocols: Vec, ) -> Self { @@ -32,7 +32,7 @@ impl CSMessageRequest { from, to, sequence_no, - rollback, + msg_type, data: Nullable::new(data_bytes), protocols, } @@ -50,8 +50,12 @@ impl CSMessageRequest { self.sequence_no } - pub fn rollback(&self) -> bool { - self.rollback + pub fn msg_type(&self) -> MessageType { + return self.msg_type.clone(); + } + + pub fn need_response(&self) -> bool { + return self.msg_type == MessageType::MessageWithRollback; } pub fn data(&self) -> Result<&[u8], ContractError> { @@ -74,7 +78,7 @@ impl Encodable for CSMessageRequest { stream.append(&self.from.to_string()); stream.append(&self.to.to_string()); stream.append(&self.sequence_no); - stream.append(&self.rollback); + stream.append(&self.msg_type); stream.append(&self.data); stream.begin_list(self.protocols.len()); for protocol in self.protocols.iter() { @@ -94,7 +98,7 @@ impl Decodable for CSMessageRequest { .map_err(|_e| rlp::DecoderError::RlpInvalidLength)?, to: Addr::unchecked(to_str), sequence_no: rlp.val_at(2)?, - rollback: rlp.val_at(3)?, + msg_type: rlp.val_at(3)?, data: rlp.val_at(4)?, protocols: list, }) @@ -170,7 +174,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - false, + 1, data.clone(), vec![], ); @@ -182,7 +186,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - false, + 1, data.clone(), vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); @@ -194,7 +198,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - true, + 1, data, vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); diff --git a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs index 298b114a..127db9cb 100644 --- a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs @@ -9,7 +9,7 @@ use cw_xcall::{ state::{CwCallService, EXECUTE_CALL_ID}, types::{call_request::CallRequest, request::CSMessageRequest}, }; -use cw_xcall_lib::network_address::NetworkAddress; +use cw_xcall_lib::{network_address::NetworkAddress, message::msg_type::MessageType}; mod account; mod setup; use crate::account::alice; @@ -42,7 +42,7 @@ fn test_execute_call_with_wrong_data() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - false, + MessageType::BasicMessage, keccak256(&[104, 106, 108, 108, 111]).to_vec(), vec![], ); @@ -67,7 +67,7 @@ fn test_execute_call_having_request_id_without_rollback() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - false, + MessageType::BasicMessage, keccak256(&data).to_vec(), vec![], ); @@ -119,7 +119,7 @@ fn test_successful_reply_message() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - false, + MessageType::BasicMessage, vec![], vec![], ); @@ -154,7 +154,7 @@ fn test_failed_reply_message() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - false, + MessageType::BasicMessage, vec![], vec![], ); From abcf6afbe456e12403bd846841cc24717964d0c7 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 9 Nov 2023 10:25:24 +0545 Subject: [PATCH 03/20] fix: fix test --- .../cw-xcall-lib/src/message/msg_type.rs | 13 +++++++++++++ contracts/cosmwasm-vm/cw-xcall/src/types/request.rs | 12 +++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs index 3d81f4af..7b6d5591 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs @@ -6,6 +6,8 @@ pub enum MessageType { MessageWithRollback = 2, } + + impl Into for MessageType { fn into(self) -> u8 { match self { @@ -24,3 +26,14 @@ impl From for MessageType { } } } + +impl MessageType { + pub fn as_int(&self)->u8 { + let int= self.clone().into(); + int + } + pub fn from_int(val:u8)->Self { + let msg=MessageType::from(val); + msg + } +} diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs index e8734a90..3adfc4e7 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs @@ -78,7 +78,7 @@ impl Encodable for CSMessageRequest { stream.append(&self.from.to_string()); stream.append(&self.to.to_string()); stream.append(&self.sequence_no); - stream.append(&self.msg_type); + stream.append(&self.msg_type.as_int()); stream.append(&self.data); stream.begin_list(self.protocols.len()); for protocol in self.protocols.iter() { @@ -93,12 +93,13 @@ impl Decodable for CSMessageRequest { let list: Vec = rlp_protocols.as_list()?; let str_from: String = rlp.val_at(0)?; let to_str: String = rlp.val_at(1)?; + let msg_type_int:u8=rlp.val_at(3)?; Ok(Self { from: NetworkAddress::from_str(&str_from) .map_err(|_e| rlp::DecoderError::RlpInvalidLength)?, to: Addr::unchecked(to_str), sequence_no: rlp.val_at(2)?, - msg_type: rlp.val_at(3)?, + msg_type: MessageType::from_int(msg_type_int), data: rlp.val_at(4)?, protocols: list, }) @@ -166,6 +167,7 @@ mod tests { use cw_xcall_lib::network_address::NetworkAddress; use super::CSMessageRequest; + use cw_xcall_lib::message::msg_type::MessageType; #[test] fn test_csmessage_request_encoding() { @@ -174,7 +176,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - 1, + MessageType::BasicMessage, data.clone(), vec![], ); @@ -186,7 +188,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - 1, + MessageType::BasicMessage, data.clone(), vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); @@ -198,7 +200,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - 1, + MessageType::BasicMessage, data, vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); From 55acbfc6ebc257d3d6d5ab3b85e223183b038cd3 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 9 Nov 2023 11:51:22 +0545 Subject: [PATCH 04/20] refactor: csresponse to scresult --- .../cosmwasm-vm/cw-xcall/src/execute_call.rs | 6 +++--- .../cw-xcall/src/handle_call_message.rs | 4 ++-- contracts/cosmwasm-vm/cw-xcall/src/lib.rs | 2 +- .../cosmwasm-vm/cw-xcall/src/types/message.rs | 4 ++-- .../cosmwasm-vm/cw-xcall/src/types/mod.rs | 2 +- .../cosmwasm-vm/cw-xcall/src/types/response.rs | 18 +++++++++--------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs index 9096b30f..4052c1b8 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs @@ -7,7 +7,7 @@ use crate::{ state::{CwCallService, EXECUTE_CALL_ID}, types::{ message::CSMessage, - response::{CSMessageResponse, CallServiceResponseType}, + response::{CSMessageResult, CallServiceResponseType}, }, }; @@ -82,7 +82,7 @@ impl<'a> CwCallService<'a> { cosmwasm_std::SubMsgResult::Ok(_res) => { let code = CallServiceResponseType::CallServiceResponseSuccess.into(); - let message_response = CSMessageResponse::new( + let message_response = CSMessageResult::new( request.sequence_no(), CallServiceResponseType::CallServiceResponseSuccess, ); @@ -92,7 +92,7 @@ impl<'a> CwCallService<'a> { cosmwasm_std::SubMsgResult::Err(err) => { let code = CallServiceResponseType::CallServiceResponseFailure; let error_message = format!("CallService Reverted : {err}"); - let message_response = CSMessageResponse::new(request.sequence_no(), code.clone()); + let message_response = CSMessageResult::new(request.sequence_no(), code.clone()); let event = event_call_executed(req_id, code.into(), &error_message); (message_response, event) } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs index d917397f..f4dd8e18 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs @@ -90,7 +90,7 @@ impl<'a> CwCallService<'a> { info: MessageInfo, data: &[u8], ) -> Result { - let message: CSMessageResponse = rlp::decode(data).unwrap(); + let message: CSMessageResult = rlp::decode(data).unwrap(); let response_sequence_no = message.sequence_no(); @@ -190,7 +190,7 @@ impl<'a> CwCallService<'a> { info: MessageInfo, sn: u128, ) -> Result { - let msg = CSMessageResponse::new(sn, CallServiceResponseType::CallServiceResponseFailure); + let msg = CSMessageResult::new(sn, CallServiceResponseType::CallServiceResponseFailure); self.handle_response(deps, info, &rlp::encode(&msg)) } } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/lib.rs b/contracts/cosmwasm-vm/cw-xcall/src/lib.rs index 457df968..4316a381 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/lib.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/lib.rs @@ -28,7 +28,7 @@ use crate::{ call_request::CallRequest, message::{CSMessage, CallServiceMessageType}, request::CSMessageRequest, - response::{CSMessageResponse, CallServiceResponseType}, + response::{CSMessageResult, CallServiceResponseType}, storage_keys::StorageKey, }, }; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs index 1ab718bf..6621228c 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs @@ -62,8 +62,8 @@ impl From for CSMessage { } } -impl From for CSMessage { - fn from(value: CSMessageResponse) -> Self { +impl From for CSMessage { + fn from(value: CSMessageResult) -> Self { Self { message_type: CallServiceMessageType::CallServiceResponse, payload: rlp::encode(&value).to_vec(), diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs index 4f2d8210..6791c72f 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs @@ -13,4 +13,4 @@ use common::rlp::{Decodable, Encodable}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{to_binary, Binary}; use request::CSMessageRequest; -use response::CSMessageResponse; +use response::CSMessageResult; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/response.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/response.rs index e52addab..05e18181 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/response.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/response.rs @@ -25,12 +25,12 @@ impl TryFrom for CallServiceResponseType { } #[cw_serde] -pub struct CSMessageResponse { +pub struct CSMessageResult { sequence_no: u128, response_code: CallServiceResponseType, } -impl CSMessageResponse { +impl CSMessageResult { pub fn new(sequence_no: u128, response_code: CallServiceResponseType) -> Self { Self { sequence_no, @@ -52,7 +52,7 @@ impl CSMessageResponse { } } -impl Encodable for CSMessageResponse { +impl Encodable for CSMessageResult { fn rlp_append(&self, stream: &mut rlp::RlpStream) { let code: u8 = self.response_code.clone().into(); @@ -63,7 +63,7 @@ impl Encodable for CSMessageResponse { } } -impl Decodable for CSMessageResponse { +impl Decodable for CSMessageResult { fn decode(rlp: &rlp::Rlp) -> Result { let code: u8 = rlp.val_at(1)?; @@ -74,7 +74,7 @@ impl Decodable for CSMessageResponse { } } -impl TryFrom<&Vec> for CSMessageResponse { +impl TryFrom<&Vec> for CSMessageResult { type Error = ContractError; fn try_from(value: &Vec) -> Result { let rlp = rlp::Rlp::new(value as &[u8]); @@ -84,7 +84,7 @@ impl TryFrom<&Vec> for CSMessageResponse { } } -impl TryFrom<&[u8]> for CSMessageResponse { +impl TryFrom<&[u8]> for CSMessageResult { type Error = ContractError; fn try_from(value: &[u8]) -> Result { let rlp = rlp::Rlp::new(value); @@ -112,18 +112,18 @@ mod tests { use common::rlp; - use super::{CSMessageResponse, CallServiceResponseType}; + use super::{CSMessageResult, CallServiceResponseType}; #[test] fn test_cs_message_response_encoding() { let cs_response = - CSMessageResponse::new(1, CallServiceResponseType::CallServiceResponseSuccess); + CSMessageResult::new(1, CallServiceResponseType::CallServiceResponseSuccess); let encoded = rlp::encode(&cs_response); assert_eq!("c20101", hex::encode(encoded)); let cs_response = - CSMessageResponse::new(2, CallServiceResponseType::CallServiceResponseFailure); + CSMessageResult::new(2, CallServiceResponseType::CallServiceResponseFailure); let encoded = rlp::encode(&cs_response); assert_eq!("c20200", hex::encode(encoded)); From 02cc2f59a898ac01c074425983db2f2bbdcb5edb Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 9 Nov 2023 11:56:08 +0545 Subject: [PATCH 05/20] refactor: csmessage type --- .../cosmwasm-vm/cw-xcall/src/types/message.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs index 6621228c..86d5cbe0 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs @@ -1,26 +1,26 @@ use super::*; #[cw_serde] -pub enum CallServiceMessageType { - CallServiceRequest = 1, - CallServiceResponse, +pub enum CSMessageType { + CSMessageRequest = 1, + CSMessageResult, } #[cw_serde] pub struct CSMessage { - pub message_type: CallServiceMessageType, + pub message_type: CSMessageType, pub payload: Vec, } impl CSMessage { - pub fn new(message_type: CallServiceMessageType, payload: Vec) -> Self { + pub fn new(message_type: CSMessageType, payload: Vec) -> Self { Self { message_type, payload: payload.to_vec(), } } - pub fn message_type(&self) -> &CallServiceMessageType { + pub fn message_type(&self) -> &CSMessageType { &self.message_type } pub fn payload(&self) -> &[u8] { @@ -31,8 +31,8 @@ impl CSMessage { impl Encodable for CSMessage { fn rlp_append(&self, stream: &mut rlp::RlpStream) { let msg_type: u8 = match self.message_type { - CallServiceMessageType::CallServiceRequest => 1, - CallServiceMessageType::CallServiceResponse => 2, + CSMessageType::CSMessageRequest => 1, + CSMessageType::CSMessageResult => 2, }; stream.begin_list(2).append(&msg_type).append(&self.payload); } @@ -44,8 +44,8 @@ impl Decodable for CSMessage { Ok(Self { message_type: match msg_type { - 1 => Ok(CallServiceMessageType::CallServiceRequest), - 2 => Ok(CallServiceMessageType::CallServiceResponse), + 1 => Ok(CSMessageType::CSMessageRequest), + 2 => Ok(CSMessageType::CSMessageResult), _ => Err(rlp::DecoderError::Custom("Invalid type")), }?, payload: rlp.val_at(1)?, @@ -56,7 +56,7 @@ impl Decodable for CSMessage { impl From for CSMessage { fn from(value: CSMessageRequest) -> Self { Self { - message_type: CallServiceMessageType::CallServiceRequest, + message_type: CSMessageType::CSMessageRequest, payload: rlp::encode(&value).to_vec(), } } @@ -65,7 +65,7 @@ impl From for CSMessage { impl From for CSMessage { fn from(value: CSMessageResult) -> Self { Self { - message_type: CallServiceMessageType::CallServiceResponse, + message_type: CSMessageType::CSMessageResult, payload: rlp::encode(&value).to_vec(), } } @@ -120,7 +120,7 @@ mod tests { fn test_csmessage_encoding() { let data = hex::decode("7465737431").unwrap(); let message = CSMessage::new( - super::CallServiceMessageType::CallServiceRequest, + super::CSMessageType::CSMessageRequest, data.clone(), ); let encoded = rlp::encode(&message); @@ -128,7 +128,7 @@ mod tests { assert_eq!("c701857465737431", hex::encode(encoded)); let message = CSMessage::new( - crate::types::message::CallServiceMessageType::CallServiceResponse, + crate::types::message::CSMessageType::CSMessageResult, data, ); let encoded = rlp::encode(&message); From 055416f1b1acbf225c8883654f1c73019ff95e18 Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Fri, 10 Nov 2023 08:49:33 +0100 Subject: [PATCH 06/20] docs: Add new message strucute to xCall design doc --- docs/adr/xcall.md | 459 +++++++++++++++++++++++++++------------------- 1 file changed, 275 insertions(+), 184 deletions(-) diff --git a/docs/adr/xcall.md b/docs/adr/xcall.md index e2d7bded..6531cd69 100644 --- a/docs/adr/xcall.md +++ b/docs/adr/xcall.md @@ -18,6 +18,13 @@ A network address is represented as a string with "networkId" and "account" sepa A networkId is a unique id of a network, and there can't be two networks with the same id connected to the same xCall network. +``` +NetworkAddress { + String account, + String net +} +``` + ### Connections XCall is designed to utilize a wide range of bridging protocols that facilitate data transfer, known as connections. @@ -31,7 +38,56 @@ connections at all. ### Sending Messages -Sending messages via xCall is simply done by calling sendCallMessage on the xCall contract. +Sending messages via xCall is done by constructing a xCall message envelope and calling `sendCall` with a +destination networkAddress `_to`. +``` +/** + * Sends a call message to the contract on the destination chain. + * + * @param _to The network address of the callee on the destination chain + * @param _data The xCall envelope + * @return The serial number of the request + */ +payable external sendCall(String _to, byte[] _data) returns Integer +``` + +##### Message Envelope Structure + +All structure are RLP encoded in the order as shown below. + +The Envelope is the structure received by sendCall method. +``` +Envelope { + int messageType, + Message message, + String[] sources, + String[] destinations, +} +``` + +##### Message Objects +All Message objects have a TypeId specifying its type + +A CallMessage will try to execute on the destination chain, and will be removed even if the execution fails and no response will be relayed back +``` +TypeId = 1 +CallMessage { + byte[] data +} + +``` + +``` +TypeId = 2 +CallMessageWithRollback { + byte[] data, + byte[] rollback, + +} +``` + +#### Legacy send Interface +Sending messages via xCall can be done by calling sendCallMessage on the xCall contract. `_to` address is a networkAddress used by xCall to figure out the destination chain. The user can also specify which connections to use, if not specified, the default connections will be used. This also allows dapps to have their messages secured by multiple protocols. @@ -54,9 +110,9 @@ The `_rollback` data is limited to 1024KB. */ payable external sendCallMessage(String _to, byte[] _data, - @Optional bytes _rollback, + @Optional byte[] _rollback, @Optional String[] _sources - @Optional String[] _destinations) return Integer; + @Optional String[] _destinations) return Integer ``` ### Events @@ -173,7 +229,7 @@ Then `xcall` compares it with the saved hash value to validate its integrity. * @param _reqId The request Id * @param _data The calldata */ -external executeCall(BigInteger _reqId, byte[] _data); +external executeCall(BigInteger _reqId, byte[] _data) ``` The user on the source chain recognizes the rollback situation and invokes the following method on xcall with the @@ -187,7 +243,7 @@ It should be reverted when there is no failure response with the call request. * * @param _sn The serial number of the previous request */ -external executeRollback(BigInteger _sn); +external executeRollback(BigInteger _sn) ``` #### Handling @@ -205,8 +261,8 @@ If only using default protocols, implementing only the two parameter versions of * @param _data The calldata delivered from the caller * @param _protocols The contract addresses that delivered the data, if omitted the default protocol was used */ -external handleCallMessage(String _from, byte[] _data); -external handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols); +external handleCallMessage(String _from, byte[] _data) +external handleCallMessage(String _from, byte[] _data, @Optional String[] _protocols) ``` In case of rollback, the `_from` will be the network address of the xCall contract. @@ -250,7 +306,7 @@ If rollback was specified and the call was successful, the success can be verifi * * @return If the '_sn' has received a success response */ -external readonly verifySuccess(BigInteger _sn) returns boolean; +external readonly verifySuccess(BigInteger _sn) returns boolean ``` ### Fee Management @@ -271,7 +327,7 @@ Sending a message through xCall has two types of fees. One for using the protoco */ external readonly getFee(String _net, boolean _rollback - @Optional String[] _sources) returns Integer; + @Optional String[] _sources) returns Integer ``` ``` @@ -280,7 +336,7 @@ external readonly getFee(String _net, * * @return the xCall protocol fee */ -external readonly getProtocolFee() Returns Integer; +external readonly getProtocolFee() Returns Integer ``` ### Security Considerations @@ -345,48 +401,49 @@ RLP encoding order is the same as the order they are defined in below. ``` CSMessageRequest { - String from; - String to; - BigInteger sn; - boolean rollback; - bytes data; - String[] protocols; + String from + String to + BigInteger sn + int messageType + // RLP encoded message + byte[] message + String[] protocols } ``` -##### CSMessageResponse +##### CSMessageResult ``` -int SUCCESS = 1; -int FAILURE = 0; -CSMessageResponse { - BigInteger sn; - int code; +int SUCCESS = 1 +int FAILURE = 0 +CSMessageResult { + BigInteger sn + int code } ``` ##### CSMessage ``` -int REQUEST = 1; -int RESPONSE = 2; +int REQUEST = 1 +int RESULT = 2 CSMessage { - // The message type, either REQUEST or RESPONSE - int type; + // The message type, either REQUEST or RESULT + int type // RLP encoded bytes of the Message - bytes data; + byte[] data } ``` #### Internal structs ``` -CallRequest { - Address from; - String netTo; - String[] protocols; - bytes rollback; - boolean enabled = false; // defaults to false +RollbackData { + Address from + String netTo + String[] protocols + byte[] rollback + boolean enabled = false // defaults to false } ``` @@ -396,16 +453,14 @@ CallRequest { MAX_DATA_SIZE: 2048 MAX_ROLLBACK_SIZE: 1024 NID: -SVC_NAME = xcallM sn: reqId: -requests: sn -> CallRequest +rollbacks: sn -> RollbackData proxyReqs: reqId -> CSMessageRequest -# default values should be false in case of boolean storage -pendingReqs: msgHash -> connection address -> boolean -pendingResponses: msgHash -> connection address -> boolean +// default values should be false in case of boolean storage +pendingMessages: msgHash -> connection address -> boolean successfulResponses: sn -> boolean admin: @@ -417,19 +472,55 @@ feeHandler:
### Contract initialization ``` -function init(String networkId) { +function init(String networkId): NID = networkId - if admin == null - admin = getCaller(); - feeHandler = getCaller(); - -} + admin = getCaller() + feeHandler = getCaller() ``` ### Communication #### Sending messages +`sendCall` sends some arbitrary data to `_to` via a path specified by the caller. + +- `_to`: The network address of the target contract. +- `_data`: The rlp encoded xCall envelope. + +``` +payable external sendCall(String _to, byte[] _data) returns Integer { + caller = getCaller() + envelope = Envelope.decode(_data) + sn++ + from = NetworkAddress(NID, caller) + to = NetworkAddress(_to) + + needResponse, msg = preProcessMessage(sn, to, envelope) + + msgReq = CSMessageRequest(from, to.account(), sn, envelope.type, msg, envelope.destinations) + msg = CSMessage(CSMessage.REQUEST, msgReq.toBytes()).toBytes() + assert msg.length <= MAX_DATA_SIZE + + sendSn = needResponse ? sn : 0 + if protocolConfig.sources == []: + src = defaultConnection[to.net()] + fee = src->getFee(to.net(), needResponse) + src->sendMessage(fee, to.net(), "xcall-multi", sendSn, msg) + else: + for src in protocolConfig.sources: + fee = src->getFee(to.net(), needResponse) + src->sendMessage(fee, to.net(), "xcall-multi", sendSn, msg) + + + remainingBalance = getBalance() + assert remainingBalance >= getProtocolFee() + transfer(feeHandler, balance) + emit CallMessageSent(caller, dst.toString(), sn) + + return sn +} + +``` `sendCallMessage` sends some arbitrary data to `_to` via a path specified by the caller. - `_to`: The network address of the target contract. @@ -442,64 +533,53 @@ function init(String networkId) { ``` payable external function sendCallMessage(String _to, byte[] _data, - @Optional bytes _rollback, + @Optional byte[] _rollback, @Optional String[] _sources @Optional String[] _destinations) returns Integer { - caller = getCaller() - require(caller.isContract() || _rollback == null, "RollbackNotPossible"); - require(_rollback == null || _rollback.length <= MAX_ROLLBACK_SIZE, "MaxRollbackSizeExceeded") - - sn++ - dst = NetworkAddress(_to) - from = NetworkAddress(NID, caller).toString() - - needResponse = _rollback != null && _rollback.length > 0 - if needResponse: - req = CallRequest(caller, dst.net(), _sources, _rollback) - requests[sn] = req - - - msgReq = CSMessageRequest(from, dst.account(), sn, needResponse, _data, _destinations) - msg = CSMessage(CSMessage.REQUEST, msgReq.toBytes()).toBytes(); - require(msg.length <= MAX_DATA_SIZE, "MaxDataSizeExceeded") - - sendSn = needResponse ? sn : 0 - if _sources == []: - src = defaultConnection[dst.net()] - fee = src->getFee(dst.net(), needResponse) - src->sendMessage(fee, dst.net(), SVC_NAME, sendSn, msg) + if (_rollback == null || _rollback.length == 0): + msg = new CallMessage(_data) else: - for src in sources: - fee = src->getFee(dst.net(), needResponse) - src->sendMessage(fee, dst.net(), SVC_NAME, sendSn, msg) + msg = new CallMessageWithRollback(_data, _rollback) + envelope = new Envelope(msg, _sources, _destinations) + return sendCall(_to, envelope.toBytes()) - remaningBalance = getBalance(); - require(remaningBalance >= getProtocolFee()) - transfer(feeHandler, balance) - emit CallMessageSent(caller, dst.toString(), sn) - return sn } +``` + +Internal method where message types can implement type specific logic. +``` +internal function preProcessMessage(int sn, NetworkAddress to, Envelope envelope) return (boolean, byte[]) { + switch (envelope.type) { + case CallMessage.Type: + return false, message + case CallMessageWithRollback.Type: + assert caller.isContract() + msg = CallMessageWithRollback(message) + req = CallRequest(caller, to.net(), envelope.sources, msg.rollback) + rollbacks[sn] = req + return true, msg.data + } +} ``` #### Receiving messages `handleMessage` is the external function used by connections to deliver messages. -```javascript -external function handleMessage(String _fromNid, bytes _msg) { - msg = CSMessage.decode(_msg); - assert _fromNid != nid +``` +external function handleMessage(String _fromNid, byte[] _msg) { + msg = CSMessage.decode(_msg) switch (msg.type) : case CSMessage.REQUEST: - handleRequest(_fromNid, msg.data); - break; - case CSMessage.RESPONSE: - handleResponse(msg.data); - break; + handleRequest(_fromNid, msg.data) + break + case CSMessage.RESULT: + handleResult(msg.data) + break default: - Context.revert("UnknownMsgType(" + msg.type + ")"); + Context.revert("UnknownMsgType(" + msg.type + ")") } ``` @@ -507,16 +587,15 @@ external function handleMessage(String _fromNid, bytes _msg) { ``` external function handleError(BigInteger _sn) { - CSMessageResponse res = CSMessageResponse(_sn, CSMessageResponse.FAILURE); - handleResponse(res.toBytes()); + CSMessageResult res = CSMessageResult(_sn, CSMessageResult.FAILURE) + handleResult(res.toBytes()) } ``` `handleBTPMessage` Can be added to natively support the BTP protocol without a standalone connection. ``` -external function handleBTPMessage(String _from, _svc String, Integer _sn, bytes _msg) { - // verify svc is as registered +external function handleBTPMessage(String _from, _svc String, Integer _sn, byte[] _msg) { handleMessage(_from, _msg) } ``` @@ -525,135 +604,147 @@ external function handleBTPMessage(String _from, _svc String, Integer _sn, bytes ``` external function handleBTPError(String _src, String _svc, BigInteger _sn, long _code, String _msg) { - // verify svc is as registered handleError(_sn) } ``` ``` -internal function handleRequest(String srcNet, bytes data) { - msgReq = CSMessageRequest.decode(data); - from = NetworkAddress(msgReq.from); - require(from.net() == srcNet); - source = getCaller(); +internal function verifyProtocols(String srcNet, String[] protocols, byte[] data) returns boolean { + source = getCaller() + _hash = hash(data) + if (protocols.length > 1): + pendingMessages[_hash][source] = true + for (protocol : protocols): + if (!pendingMessages[_hash][protocol]): + return false + for (protocol : protocols): + pendingMessages[_hash][protocol] = null + else if (protocols.length == 1): + assert source == protocols[0] + else: + assert source == defaultConnection[srcNet] - if (msgReq.protocols.length > 1): - _hash = hash(data); - pendingReqs[_hash][source] = true; - for (protocol : msgReq.protocols): - if (!pendingReqs[_hash][protocol]): - return; + return true +} +``` - for (protocol : msgReq.protocols): - pendingReqs[_hash][protocol] = null; - else if (msgReq.protocols.length == 1): - require(source == msgReq.protocols[0]); - else: - require(source == defaultConnection[srcNet]); - reqId = getNextReqId(); +``` +internal function handleRequest(String srcNet, byte[] data) { + msgReq = CSMessageRequest.decode(data) + if !verifyProtocols(srcNet, msgReq.protocolConfig, hash(data)): + return - emit CallMessage(msgReq.from, msgReq.to, msgReq.sn, reqId, msgReq.data); + reqId = getNextReqId() + from = NetworkAddress(msgReq.from) + assert from.net == srcNet + emit CallMessage(msgReq.from, msgReq.to, msgReq.sn, reqId, msgReq.data) msgReq.data = hash(msgReq.data) - proxyReqs[reqId] = msgReq; + proxyReqs[reqId] = msgReq } ``` ``` -internal function handleResponse(data bytes) { - response = CSMessageResponse.decode(data); - resSn = response.sn; - req = requests[resSn]; - source = getCaller +internal function handleResult(data byte[]) { + result = CSMessageResult.decode(data) + resSn = result.sn + req = rollbacks[resSn] if req == null: - return; // just ignore - - if req.protocols.length > 1: - _hash = hash(data); - pendingResponses.at(_hash).set(source, true); - for protocol : req.protocols: - if !pendingResponses[_hash][protocol]: - return; - - for (String protocol : protocols): - pendingResponses[_hash][protocol] = null - else if (msgReq.protocols.length == 1): - require(source == msgReq.protocols[0]); - else: - require(source == defaultConnection[req.netTo]); - - emit ResponseMessage(resSn, response.getCode()); - switch response.getCode(): - case CSMessageResponse.SUCCESS: - requests[resSn] = null; - successfulResponses[resSn] = 1; - break; - case CSMessageResponse.FAILURE: + return + + if !verifyProtocols(req.netTo, req.protocolConfig, hash(data)): + return + + emit ResponseMessage(resSn, result.getCode()) + switch result.getCode(): + case CSMessageResult.SUCCESS: + rollbacks[resSn] = null + successfulResponses[resSn] = 1 + break + case CSMessageResult.FAILURE: default: - // emit rollback event - require(req.rollback != null, "NoRollbackData"); - req.enabled = true; - requests[resSn] = req; - emit RollbackMessage(resSn); + assert req.rollback != null + req.enabled = true + rollbacks[resSn] = req + emit RollbackMessage(resSn) } ``` #### Message Execution -In case of a two-message call, -the function should allow the call to fail and send a new message to roll back the message. -While if a one way message fails, re-execution should be allowed. - ``` external function executeCall(Integer _reqId, byte[] _data) { - req = proxyReqs[_reqId]; - require(req != null, "InvalidRequestId"); - proxyReqs[_reqId] == null; + req = proxyReqs[_reqId] + assert req != null + proxyReqs[_reqId] == null assert hash(_data) == req.data + executeCallRequest(_reqId, r) + } - from = NetworkAddress(req.from); - ErrorMessage = "" - try: - if req.protocols == []: - req.to->handleCallMessage(req.from, _data); - else: - req.to->handleCallMessage(req.from, _data, req.protocols); - response = new CSMessageResponse(req.sn, CSMessageResponse.SUCCESS); - catch err: - response = new CSMessageResponse(req.sn, CSMessageResponse.FAILURE); - ErrorMessage = err.message +``` - emit CallExecuted(_reqId, response.code, response.msg, ErrorMessage); +Method where message specific execution logic is handled. +``` +internal function executeMessage(int reqId, CallRequest req) { + switch (req.type) { + case CallMessage.Type: + tryExecute(reqId, req.from, req.data, req.protocols) + case CallMessageWithRollback.Type: + code = tryExecute(reqId, req.from, req.data, req.protocols) + result = new CSMessageResult(req.sn, code) + msg = CSMessage(CSMessage.RESULT, result.toBytes()) - if req.needRollback(): - sn = req.sn.negate(); - msg = CSMessage(CSMessage.RESPONSE, response.toBytes()); + sn = req.sn.negate() if req.protocols == []: protocol = defaultConnection[from.net()] - protocol->sendMessage(from.net(), SVC_NAME, sn, msg.toBytes()) + protocol->sendMessage(from.net(), "xcall-multi", sn, msg.toBytes()) else: for (String protocol : req.protocols): - protocol->sendMessage(from.net(), SVC_NAME, sn, msg.toBytes()) + protocol->sendMessage(from.net(), "xcall-multi", sn, msg.toBytes()) + default: + revert } - +} ``` ``` external function executeRollback(Integer _sn) { - req = requests.get(_sn); - require(req != null, "InvalidSerialNum"); - require(req.enabled, "RollbackNotEnabled"); - requests[_sn] = null; + req = rollbacks.get(_sn) + assert req != null + assert req.enabled + rollbacks[_sn] = null if req.protocols == []: - req.from->handleCallMessage(getNetworkAddress(), req.rollback); + req.to->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols) else: - req.from->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols); + req.to->handleCallMessage(getNetworkAddress(), req.rollback, req.protocols) + + emit RollbackExecuted(_sn) +} + +``` +``` +internal function tryExecuteCall(int id, String from, byte[] data, String[] protocols) returns String { + try: + executeCall(id, from, data, protocols) + catch Error as e: + emit CallExecuted(id, CSMessageResult.FAILURE, e.message) + return CSMessageResult.FAILURE - emit RollbackExecuted(_sn); + return CSMessageResult.SUCCESS } +``` + +``` +internal function executeCall(int id, String from, byte[] data, String[] protocols) { + if req.protocols == []: + req.to->handleCallMessage(from, data) + else: + req.to->handleCallMessage(from, data, protocols) + emit CallExecuted(id, CSMessageResult.SUCCESS, "") +} ``` ### Admin methods @@ -680,28 +771,28 @@ adminOnly function setDefaultConnection(String _nid, Address _connection){ ``` external readonly function getNetworkAddress() returns String { - return NetworkAddress(NID, this.address); + return NetworkAddress(NID, this.address) } ``` ``` external readonly function getNetworkId() returns String { - return NID; + return NID } ``` ``` external readonly function getProtocolFee() returns Integer { - return protocolFee; + return protocolFee } ``` ``` -external readonly function getFee(String _net, - boolean _rollback - @Optional String[] _sources) +external readonly function getFee(String _net, + boolean _rollback + @Optional String[] _sources) returns Integer { - fee = protocolFee; + fee = protocolFee if _sources == [] { return defaultConnection[_net]->getFee(_net, _rollback) + fee } @@ -715,7 +806,7 @@ external readonly function getFee(String _net, ``` external readonly function verifySuccess(Integer sn) returns boolean { - return successfulResponses[sn]; + return successfulResponses[sn] } ``` From df934eb633a736a51e5bb13fe0bc14abde118892 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Fri, 10 Nov 2023 14:56:54 +0545 Subject: [PATCH 07/20] refactor: rename result --- contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs | 2 +- .../cosmwasm-vm/cw-xcall/src/handle_call_message.rs | 10 +++++----- contracts/cosmwasm-vm/cw-xcall/src/lib.rs | 4 ++-- contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs | 4 ++-- .../cw-xcall/src/types/{response.rs => result.rs} | 0 5 files changed, 10 insertions(+), 10 deletions(-) rename contracts/cosmwasm-vm/cw-xcall/src/types/{response.rs => result.rs} (100%) diff --git a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs index 4052c1b8..40b69f99 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/execute_call.rs @@ -7,7 +7,7 @@ use crate::{ state::{CwCallService, EXECUTE_CALL_ID}, types::{ message::CSMessage, - response::{CSMessageResult, CallServiceResponseType}, + result::{CSMessageResult, CallServiceResponseType}, }, }; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs index f4dd8e18..22524170 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/handle_call_message.rs @@ -14,11 +14,11 @@ impl<'a> CwCallService<'a> { let call_service_message: CSMessage = CSMessage::try_from(message)?; match call_service_message.message_type() { - CallServiceMessageType::CallServiceRequest => { + CSMessageType::CSMessageRequest => { self.handle_request(deps, info, from_nid, call_service_message.payload()) } - CallServiceMessageType::CallServiceResponse => { - self.handle_response(deps, info, call_service_message.payload()) + CSMessageType::CSMessageResult => { + self.handle_result(deps, info, call_service_message.payload()) } } } @@ -84,7 +84,7 @@ impl<'a> CwCallService<'a> { .add_event(event)) } - pub fn handle_response( + pub fn handle_result( &self, deps: DepsMut, info: MessageInfo, @@ -191,6 +191,6 @@ impl<'a> CwCallService<'a> { sn: u128, ) -> Result { let msg = CSMessageResult::new(sn, CallServiceResponseType::CallServiceResponseFailure); - self.handle_response(deps, info, &rlp::encode(&msg)) + self.handle_result(deps, info, &rlp::encode(&msg)) } } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/lib.rs b/contracts/cosmwasm-vm/cw-xcall/src/lib.rs index 4316a381..b3554e3c 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/lib.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/lib.rs @@ -26,9 +26,9 @@ use crate::{ state::{CwCallService, EXECUTE_CALL_ID}, types::{ call_request::CallRequest, - message::{CSMessage, CallServiceMessageType}, + message::{CSMessage, CSMessageType}, request::CSMessageRequest, - response::{CSMessageResult, CallServiceResponseType}, + result::{CSMessageResult, CallServiceResponseType}, storage_keys::StorageKey, }, }; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs index 6791c72f..be99eac4 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/mod.rs @@ -2,7 +2,7 @@ pub mod call_request; pub mod config; pub mod message; pub mod request; -pub mod response; +pub mod result; pub mod storage_keys; pub const LOG_PREFIX: &str = "[xcall_app]:"; @@ -13,4 +13,4 @@ use common::rlp::{Decodable, Encodable}; use cosmwasm_schema::cw_serde; use cosmwasm_std::{to_binary, Binary}; use request::CSMessageRequest; -use response::CSMessageResult; +use result::CSMessageResult; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/response.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/result.rs similarity index 100% rename from contracts/cosmwasm-vm/cw-xcall/src/types/response.rs rename to contracts/cosmwasm-vm/cw-xcall/src/types/result.rs From 1f2fb8f8b4852308c62df350fa00317fc8d7e240 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Fri, 10 Nov 2023 17:24:38 +0545 Subject: [PATCH 08/20] fix: fix test --- .../cw-xcall/src/send_call_message.rs | 2 +- .../cosmwasm-vm/cw-xcall/src/types/request.rs | 23 +++++++++++-------- .../cw-xcall/tests/test_call_message.rs | 4 +++- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index b83d84ae..54a7ae8b 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -48,7 +48,7 @@ impl<'a> CwCallService<'a> { match &envelope.message { AnyMessage::CallMessage(_m) => Ok(()), AnyMessage::CallMessageWithRollback(m) => { - if is_contract(deps.querier, caller) { + if !is_contract(deps.querier, caller) { return Err(ContractError::RollbackNotPossible); } self.ensure_rollback_length(&m.rollback().unwrap())?; diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs index 3adfc4e7..72d0c385 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs @@ -134,28 +134,28 @@ mod tests { from: 0x1.ETH/0xa to: cx0000000000000000000000000000000000000102 sn: 21 - rollback: false + messageType: 1 data: 74657374 protocol: [] - RLP: F83F8B3078312E4554482F307861AA63783030303030303030303030303030303030303030303030303030303030303030303030303031303215008474657374C0 + RLP: f83f8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374c0 CSMessageRequest from: 0x1.ETH/0xa to: cx0000000000000000000000000000000000000102 sn: 21 - rollback: false + messageType: 1 data: 74657374 protocol: [abc, cde, efg] - RLP: F84B8B3078312E4554482F307861AA63783030303030303030303030303030303030303030303030303030303030303030303030303031303215008474657374CC836162638363646583656667 + RLP: f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374cc836162638363646583656667 CSMessageRequest from: 0x1.ETH/0xa to: cx0000000000000000000000000000000000000102 sn: 21 - rollback: true + messageType: 2 data: 74657374 protocol: [abc, cde, efg] - RLP: F84B8B3078312E4554482F307861AA63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374CC836162638363646583656667 + RLP: f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215028474657374cc836162638363646583656667 */ @@ -182,7 +182,8 @@ mod tests { ); let encoded = rlp::encode(&msg); - assert_eq!("f83f8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215008474657374c0",hex::encode(encoded)); + + assert_eq!("f83f8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374c0",hex::encode(encoded)); let msg = CSMessageRequest::new( NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), @@ -194,18 +195,20 @@ mod tests { ); let encoded = rlp::encode(&msg); - assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215008474657374cc836162638363646583656667",hex::encode(encoded)); + + assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374cc836162638363646583656667",hex::encode(encoded)); let msg = CSMessageRequest::new( NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - MessageType::BasicMessage, + MessageType::MessageWithRollback, data, vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); let encoded = rlp::encode(&msg); - assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374cc836162638363646583656667",hex::encode(encoded)); + + assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215028474657374cc836162638363646583656667",hex::encode(encoded)); } } diff --git a/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs index 068e3c24..81eeaa0d 100644 --- a/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs @@ -1,6 +1,6 @@ mod account; mod setup; -use std::{collections::HashMap, vec}; +use std::{collections::HashMap, vec, str::FromStr}; use crate::account::*; use cosmwasm_std::{ @@ -34,6 +34,8 @@ fn send_packet_by_non_contract_and_rollback_data_is_not_null() { }, ) .unwrap(); + contract.set_admin(mock_deps.as_mut().storage, Addr::unchecked(&alice().to_string())).unwrap(); + contract.set_default_connection(mock_deps.as_mut(), mock_info.clone(), NetId::from_str("nid").unwrap(), Addr::unchecked("defaultconn".to_string())).unwrap(); contract .send_call_message( From 2b7d3fd39eea66ce983d1ab8e3e2e4585c50d169 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Fri, 10 Nov 2023 17:29:14 +0545 Subject: [PATCH 09/20] chore: cleanup --- .../cw-xcall-lib/src/message/envelope.rs | 4 ++-- .../cw-xcall-lib/src/message/mod.rs | 2 +- .../cw-xcall-lib/src/message/msg_trait.rs | 2 +- .../cw-xcall-lib/src/message/msg_type.rs | 24 ++++++++----------- .../cw-xcall/src/send_call_message.rs | 5 ++-- .../cosmwasm-vm/cw-xcall/src/types/message.rs | 10 ++------ .../cosmwasm-vm/cw-xcall/src/types/request.rs | 16 ++++++------- .../cosmwasm-vm/cw-xcall/src/types/result.rs | 4 ++-- .../cw-xcall/tests/test_call_message.rs | 18 +++++++++++--- .../tests/test_handle_call_message.rs | 2 +- scripts/optimize-cosmwasm.sh | 2 +- 11 files changed, 45 insertions(+), 44 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index 9ba017aa..fc0d69b3 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -15,8 +15,8 @@ impl Envelope { pub fn new(msg: AnyMessage, sources: Vec, destinations: Vec) -> Self { Self { message: msg, - sources: sources, - destinations: destinations, + sources, + destinations, } } } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs index 5b88af4c..7c35a53b 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs @@ -1,4 +1,4 @@ -use common::rlp::{self, Decodable, DecoderError, Encodable}; +use common::rlp::DecoderError; use self::{ call_message::CallMessage, call_message_rollback::CallMessageWithRollback, msg_trait::IMessage, diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs index 13c11a2d..4172a044 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs @@ -1,4 +1,4 @@ -use common::rlp::{self, Decodable, DecoderError, Encodable}; +use common::rlp::DecoderError; use super::msg_type::MessageType; diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs index 7b6d5591..e7e3ddc7 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs @@ -1,18 +1,16 @@ use serde::Serialize; -#[derive(Clone,Debug, Serialize, serde::Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, serde::Deserialize, PartialEq, Eq)] pub enum MessageType { BasicMessage = 1, MessageWithRollback = 2, } - - -impl Into for MessageType { - fn into(self) -> u8 { - match self { - Self::BasicMessage => 1, - Self::MessageWithRollback => 2, +impl From for u8 { + fn from(val: MessageType) -> Self { + match val { + MessageType::BasicMessage => 1, + MessageType::MessageWithRollback => 2, } } } @@ -28,12 +26,10 @@ impl From for MessageType { } impl MessageType { - pub fn as_int(&self)->u8 { - let int= self.clone().into(); - int + pub fn as_int(&self) -> u8 { + self.clone().into() } - pub fn from_int(val:u8)->Self { - let msg=MessageType::from(val); - msg + pub fn from_int(val: u8) -> Self { + MessageType::from(val) } } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index 54a7ae8b..8ff2c6e2 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -1,4 +1,3 @@ -use common::rlp::{self, Decodable}; use cosmwasm_std::{coins, BankMsg}; use cw_xcall_lib::message::call_message::CallMessage; use cw_xcall_lib::message::msg_trait::IMessage; @@ -26,7 +25,7 @@ impl<'a> CwCallService<'a> { let msg = if rollback.is_some() { AnyMessage::CallMessageWithRollback(CallMessageWithRollback { msg_type: MessageType::MessageWithRollback, - data: data, + data, rollback: rollback.unwrap(), }) } else { @@ -36,7 +35,7 @@ impl<'a> CwCallService<'a> { }) }; let envelope = Envelope::new(msg, sources, destinations); - return self.send_call(deps, info, to, envelope); + self.send_call(deps, info, to, envelope) } pub fn validate_payload( diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs index 86d5cbe0..0a6d5864 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/message.rs @@ -119,18 +119,12 @@ mod tests { #[test] fn test_csmessage_encoding() { let data = hex::decode("7465737431").unwrap(); - let message = CSMessage::new( - super::CSMessageType::CSMessageRequest, - data.clone(), - ); + let message = CSMessage::new(super::CSMessageType::CSMessageRequest, data.clone()); let encoded = rlp::encode(&message); assert_eq!("c701857465737431", hex::encode(encoded)); - let message = CSMessage::new( - crate::types::message::CSMessageType::CSMessageResult, - data, - ); + let message = CSMessage::new(crate::types::message::CSMessageType::CSMessageResult, data); let encoded = rlp::encode(&message); assert_eq!("c702857465737431", hex::encode(encoded)); } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs index 72d0c385..37d08e36 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs @@ -51,11 +51,11 @@ impl CSMessageRequest { } pub fn msg_type(&self) -> MessageType { - return self.msg_type.clone(); + self.msg_type.clone() } pub fn need_response(&self) -> bool { - return self.msg_type == MessageType::MessageWithRollback; + self.msg_type == MessageType::MessageWithRollback } pub fn data(&self) -> Result<&[u8], ContractError> { @@ -93,7 +93,7 @@ impl Decodable for CSMessageRequest { let list: Vec = rlp_protocols.as_list()?; let str_from: String = rlp.val_at(0)?; let to_str: String = rlp.val_at(1)?; - let msg_type_int:u8=rlp.val_at(3)?; + let msg_type_int: u8 = rlp.val_at(3)?; Ok(Self { from: NetworkAddress::from_str(&str_from) .map_err(|_e| rlp::DecoderError::RlpInvalidLength)?, @@ -182,8 +182,8 @@ mod tests { ); let encoded = rlp::encode(&msg); - - assert_eq!("f83f8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374c0",hex::encode(encoded)); + + assert_eq!("f83f8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374c0",hex::encode(encoded)); let msg = CSMessageRequest::new( NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), @@ -195,8 +195,8 @@ mod tests { ); let encoded = rlp::encode(&msg); - - assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374cc836162638363646583656667",hex::encode(encoded)); + + assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215018474657374cc836162638363646583656667",hex::encode(encoded)); let msg = CSMessageRequest::new( NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), @@ -208,7 +208,7 @@ mod tests { ); let encoded = rlp::encode(&msg); - + assert_eq!("f84b8b3078312e4554482f307861aa63783030303030303030303030303030303030303030303030303030303030303030303030303031303215028474657374cc836162638363646583656667",hex::encode(encoded)); } } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/result.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/result.rs index 05e18181..dfb3d63c 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/result.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/result.rs @@ -117,13 +117,13 @@ mod tests { #[test] fn test_cs_message_response_encoding() { let cs_response = - CSMessageResult::new(1, CallServiceResponseType::CallServiceResponseSuccess); + CSMessageResult::new(1, CallServiceResponseType::CallServiceResponseSuccess); let encoded = rlp::encode(&cs_response); assert_eq!("c20101", hex::encode(encoded)); let cs_response = - CSMessageResult::new(2, CallServiceResponseType::CallServiceResponseFailure); + CSMessageResult::new(2, CallServiceResponseType::CallServiceResponseFailure); let encoded = rlp::encode(&cs_response); assert_eq!("c20200", hex::encode(encoded)); diff --git a/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs index 81eeaa0d..747d5901 100644 --- a/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/tests/test_call_message.rs @@ -1,6 +1,6 @@ mod account; mod setup; -use std::{collections::HashMap, vec, str::FromStr}; +use std::{collections::HashMap, str::FromStr, vec}; use crate::account::*; use cosmwasm_std::{ @@ -34,8 +34,20 @@ fn send_packet_by_non_contract_and_rollback_data_is_not_null() { }, ) .unwrap(); - contract.set_admin(mock_deps.as_mut().storage, Addr::unchecked(&alice().to_string())).unwrap(); - contract.set_default_connection(mock_deps.as_mut(), mock_info.clone(), NetId::from_str("nid").unwrap(), Addr::unchecked("defaultconn".to_string())).unwrap(); + contract + .set_admin( + mock_deps.as_mut().storage, + Addr::unchecked(alice().to_string()), + ) + .unwrap(); + contract + .set_default_connection( + mock_deps.as_mut(), + mock_info.clone(), + NetId::from_str("nid").unwrap(), + Addr::unchecked("defaultconn".to_string()), + ) + .unwrap(); contract .send_call_message( diff --git a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs index 127db9cb..c660bd68 100644 --- a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs @@ -9,7 +9,7 @@ use cw_xcall::{ state::{CwCallService, EXECUTE_CALL_ID}, types::{call_request::CallRequest, request::CSMessageRequest}, }; -use cw_xcall_lib::{network_address::NetworkAddress, message::msg_type::MessageType}; +use cw_xcall_lib::{message::msg_type::MessageType, network_address::NetworkAddress}; mod account; mod setup; use crate::account::alice; diff --git a/scripts/optimize-cosmwasm.sh b/scripts/optimize-cosmwasm.sh index be2cfee0..434b672f 100755 --- a/scripts/optimize-cosmwasm.sh +++ b/scripts/optimize-cosmwasm.sh @@ -33,7 +33,7 @@ cargo fmt --all cargo clean rustup target add wasm32-unknown-unknown -cargo install cosmwasm-check --locked +cargo install cosmwasm-check@1.4.1 --locked RUSTFLAGS='-C link-arg=-s' cargo build --workspace --exclude test-utils --release --lib --target wasm32-unknown-unknown From f740e2b3ebbc0200835d6125d29d9644a7f2ad45 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Fri, 10 Nov 2023 17:47:43 +0545 Subject: [PATCH 10/20] test: add test for envelope encoding --- .../cw-xcall-lib/src/message/call_message.rs | 2 +- .../src/message/call_message_rollback.rs | 2 +- .../cw-xcall-lib/src/message/envelope.rs | 49 ++++++++++++++++++- .../cw-xcall-lib/src/message/mod.rs | 2 +- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs index 3aca1b97..431efcea 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs @@ -2,7 +2,7 @@ use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; use super::{msg_trait::IMessage, msg_type::MessageType}; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct CallMessage { pub msg_type: MessageType, pub data: Vec, diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs index 9b32ad30..20ba32b0 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -2,7 +2,7 @@ use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; use super::{msg_trait::IMessage, msg_type::MessageType}; -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct CallMessageWithRollback { pub msg_type: MessageType, pub data: Vec, diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index fc0d69b3..cfb990fa 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -4,7 +4,7 @@ use super::{ call_message::CallMessage, call_message_rollback::CallMessageWithRollback, msg_trait::IMessage, msg_type::MessageType, AnyMessage, }; - +#[derive(Clone, Debug, PartialEq)] pub struct Envelope { pub message: AnyMessage, pub sources: Vec, @@ -30,6 +30,7 @@ impl Encodable for Envelope { for source in self.sources.iter() { stream.append(source); } + stream.begin_list(self.destinations.len()); for dest in self.destinations.iter() { stream.append(dest); } @@ -68,3 +69,49 @@ pub fn decode_message(msg_type: MessageType, bytes: Vec) -> Result Date: Fri, 10 Nov 2023 17:48:57 +0545 Subject: [PATCH 11/20] test: add envelope encoding test --- contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index cfb990fa..32bbfbae 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -73,7 +73,6 @@ pub fn decode_message(msg_type: MessageType, bytes: Vec) -> Result Date: Fri, 10 Nov 2023 17:55:39 +0545 Subject: [PATCH 12/20] chore: fix lint --- contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index 32bbfbae..b5155cf0 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -113,4 +113,4 @@ mod tests { assert_eq!(envelope, decoded); } -} \ No newline at end of file +} From 146d710172b6c8f1e0e3b56a91a540e2e155bfef Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Mon, 30 Oct 2023 15:32:59 +0100 Subject: [PATCH 13/20] 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 From 15f761dfe77127e4e282da0935911850fab713a6 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 23 Nov 2023 10:26:50 +0545 Subject: [PATCH 14/20] fix: remove should persist --- .../cw-xcall-lib/src/message/call_message.rs | 11 ------- .../src/message/call_message_rollback.rs | 10 ------- .../cw-xcall-lib/src/message/mod.rs | 30 ------------------- .../cw-xcall-lib/src/message/msg_trait.rs | 11 ------- .../cw-xcall/src/send_call_message.rs | 2 +- 5 files changed, 1 insertion(+), 63 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs index 431efcea..87aa9112 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs @@ -41,18 +41,7 @@ impl IMessage for CallMessage { &self.msg_type } - fn should_persist(&self) -> bool { - false - } - fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) } - - // fn from_bytes(bytes: Vec) -> Result { - // let rlp = rlp::Rlp::new(&bytes); - // let msg = Self::decode(&rlp)?; - - // Ok(msg) - // } } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs index 20ba32b0..452102ac 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -44,17 +44,7 @@ impl IMessage for CallMessageWithRollback { &self.msg_type } - fn should_persist(&self) -> bool { - true - } fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) } - - // fn from_bytes(bytes: Vec) -> Result { - // let rlp = rlp::Rlp::new(&bytes); - // let msg = Self::decode(&rlp)?; - - // Ok(msg) - // } } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs index 3f47f62c..8b82eff8 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs @@ -38,40 +38,10 @@ impl IMessage for AnyMessage { } } - fn should_persist(&self) -> bool { - match self { - AnyMessage::CallMessage(m) => m.should_persist(), - AnyMessage::CallMessageWithRollback(m) => m.should_persist(), - } - } - fn to_bytes(&self) -> Result, DecoderError> { match self { AnyMessage::CallMessage(m) => m.to_bytes(), AnyMessage::CallMessageWithRollback(m) => m.to_bytes(), } } - - // fn from_bytes(bytes:Vec)->Result { - // todo!() - // } } - -// impl Encodable for AnyMessage { -// fn rlp_append(&self, s: &mut common::rlp::RlpStream) { -// match self{ -// AnyMessage::CallMessage(m)=>{ -// s.append(&rlp::encode(m)); -// }, -// AnyMessage::CallMessageWithRollback(m)=>{ -// s.append(&rlp::encode(m)); -// } -// } -// } -// } - -// impl Decodable for AnyMessage { -// fn decode(rlp: &rlp::Rlp) -> Result { - -// } -// } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs index 4172a044..157fac41 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs @@ -6,17 +6,6 @@ pub trait IMessage: Clone { fn rollback(&self) -> Option>; fn data(&self) -> Vec; fn msg_type(&self) -> &MessageType; - // fn from_bytes(bytes: Vec) -> Result { - // let rlp = rlp::Rlp::new(&bytes); - // let msg = Self::decode(&rlp)?; - // Ok(msg) - // } - - // fn to_bytes(&self) -> Vec { - // rlp::encode(self).to_vec() - // } - fn should_persist(&self) -> bool; fn to_bytes(&self) -> Result, DecoderError>; - //fn from_bytes(bytes:Vec)->Result; } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index 8ff2c6e2..be8b38f3 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -77,7 +77,7 @@ impl<'a> CwCallService<'a> { confirmed_sources = vec![default.to_string()] } - if envelope.message.should_persist() { + if envelope.message.rollback().is_some() { let rollback_data = envelope.message.rollback().unwrap(); let request = CallRequest::new( caller.clone(), From ac716605222013abfe572390251fdf0cb7ebda31 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 23 Nov 2023 10:50:23 +0545 Subject: [PATCH 15/20] fix: remove duplicate merge --- .../icon/xcall/CallServiceImpl.java | 25 ------------------- 1 file changed, 25 deletions(-) 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 b1dc1f3d..a9650ff4 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 @@ -144,31 +144,6 @@ public BigInteger sendCallMessage(String _to, return sendCall(_to, envelope.toBytes()); } - @Override - @Payable - @External - public BigInteger sendCallMessage(String _to, - byte[] _data, - @Optional byte[] _rollback, - @Optional String[] _sources, - @Optional String[] _destinations) { - - if (_sources == null || _destinations == null) { - _sources = new String[0]; - _destinations = new String[0]; - } - - 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 @External public void executeCall(BigInteger _reqId, byte[] _data) { From cf8954b347fe9f8933d3ef2804c80cc88c224689 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Tue, 28 Nov 2023 13:34:37 +0545 Subject: [PATCH 16/20] fix: encode length --- .../cw-xcall-lib/src/message/call_message_rollback.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs index 452102ac..aa8dbb20 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -12,7 +12,7 @@ pub struct CallMessageWithRollback { impl Encodable for CallMessageWithRollback { fn rlp_append(&self, stream: &mut RlpStream) { stream - .begin_list(2) + .begin_list(3) .append(&Into::::into(self.msg_type.clone())) .append(&self.data) .append(&self.rollback); From b7e1f3ed23a417d4e9b673f115a7bac3d2b76bf3 Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Thu, 30 Nov 2023 18:17:27 +0545 Subject: [PATCH 17/20] fix: remove msg type --- .../cw-xcall-lib/src/message/call_message.rs | 17 ++++++++--------- .../src/message/call_message_rollback.rs | 19 +++++++++---------- .../cw-xcall-lib/src/message/envelope.rs | 8 ++++---- .../cw-xcall-lib/src/message/mod.rs | 17 +++++++++++------ .../cw-xcall-lib/src/message/msg_trait.rs | 2 +- .../cw-xcall-lib/src/message/msg_type.rs | 12 ++++++------ .../cw-xcall/src/send_call_message.rs | 4 ++-- .../cosmwasm-vm/cw-xcall/src/types/request.rs | 8 ++++---- .../tests/test_handle_call_message.rs | 8 ++++---- 9 files changed, 49 insertions(+), 46 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs index 87aa9112..5d4792e2 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs @@ -4,26 +4,25 @@ use super::{msg_trait::IMessage, msg_type::MessageType}; #[derive(Clone, Debug, PartialEq)] pub struct CallMessage { - pub msg_type: MessageType, pub data: Vec, } impl Encodable for CallMessage { fn rlp_append(&self, stream: &mut RlpStream) { stream - .begin_list(2) - .append(&Into::::into(self.msg_type.clone())) + .begin_list(1) + .append(&self.data); } } impl Decodable for CallMessage { fn decode(rlp: &rlp::Rlp) -> Result { - let msg_type: u8 = rlp.val_at(0)?; + Ok(Self { - msg_type: MessageType::from(msg_type), - data: rlp.val_at(1)?, + + data: rlp.val_at(0)?, }) } } @@ -37,9 +36,9 @@ impl IMessage for CallMessage { self.data.clone() } - fn msg_type(&self) -> &MessageType { - &self.msg_type - } + // fn msg_type(&self) -> &MessageType { + // &self.msg_type + // } fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs index aa8dbb20..446ff687 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -4,7 +4,6 @@ use super::{msg_trait::IMessage, msg_type::MessageType}; #[derive(Clone, Debug, PartialEq)] pub struct CallMessageWithRollback { - pub msg_type: MessageType, pub data: Vec, pub rollback: Vec, } @@ -12,8 +11,8 @@ pub struct CallMessageWithRollback { impl Encodable for CallMessageWithRollback { fn rlp_append(&self, stream: &mut RlpStream) { stream - .begin_list(3) - .append(&Into::::into(self.msg_type.clone())) + .begin_list(2) + .append(&self.data) .append(&self.rollback); } @@ -21,12 +20,12 @@ impl Encodable for CallMessageWithRollback { impl Decodable for CallMessageWithRollback { fn decode(rlp: &rlp::Rlp) -> Result { - let msg_type: u8 = rlp.val_at(0)?; + Ok(Self { - msg_type: MessageType::from(msg_type), - data: rlp.val_at(1)?, - rollback: rlp.val_at(2)?, + + data: rlp.val_at(0)?, + rollback: rlp.val_at(1)?, }) } } @@ -40,9 +39,9 @@ impl IMessage for CallMessageWithRollback { self.data.clone() } - fn msg_type(&self) -> &MessageType { - &self.msg_type - } + // fn msg_type(&self) -> &MessageType { + // &self.msg_type + // } fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index b5155cf0..869fd652 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -59,11 +59,11 @@ impl Decodable for Envelope { pub fn decode_message(msg_type: MessageType, bytes: Vec) -> Result { match msg_type { - MessageType::BasicMessage => { + MessageType::CallMessage => { let msg: CallMessage = rlp::decode(&bytes)?; Ok(AnyMessage::CallMessage(msg)) } - MessageType::MessageWithRollback => { + MessageType::CallMessageWithRollback => { let msg: CallMessageWithRollback = rlp::decode(&bytes)?; Ok(AnyMessage::CallMessageWithRollback(msg)) } @@ -78,7 +78,7 @@ mod tests { fn test_encoding_decoding_envelope_call_message() { // Create a sample Envelope let message = AnyMessage::CallMessage(CallMessage { - msg_type: MessageType::BasicMessage, + data: vec![1, 2, 3], }); let sources = vec!["source1".to_string(), "source2".to_string()]; @@ -99,7 +99,7 @@ mod tests { fn test_encoding_decoding_envelope_call_message_rollback() { // Create a sample Envelope let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { - msg_type: MessageType::MessageWithRollback, + data: vec![1, 2, 3], rollback: vec![1, 2, 3], }); diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs index 8b82eff8..f1616b42 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs @@ -31,12 +31,7 @@ impl IMessage for AnyMessage { } } - fn msg_type(&self) -> &MessageType { - match self { - AnyMessage::CallMessage(m) => m.msg_type(), - AnyMessage::CallMessageWithRollback(m) => m.msg_type(), - } - } + fn to_bytes(&self) -> Result, DecoderError> { match self { @@ -45,3 +40,13 @@ impl IMessage for AnyMessage { } } } + +impl AnyMessage { + pub fn msg_type(&self) -> &MessageType { + match self { + AnyMessage::CallMessage(m) => &MessageType::CallMessage, + AnyMessage::CallMessageWithRollback(m) => &MessageType::CallMessageWithRollback, + } + } + +} \ No newline at end of file diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs index 157fac41..fc4137c9 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs @@ -5,7 +5,7 @@ use super::msg_type::MessageType; pub trait IMessage: Clone { fn rollback(&self) -> Option>; fn data(&self) -> Vec; - fn msg_type(&self) -> &MessageType; + // fn msg_type(&self) -> &MessageType; fn to_bytes(&self) -> Result, DecoderError>; } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs index e7e3ddc7..d7ad3d6e 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs @@ -2,15 +2,15 @@ use serde::Serialize; #[derive(Clone, Debug, Serialize, serde::Deserialize, PartialEq, Eq)] pub enum MessageType { - BasicMessage = 1, - MessageWithRollback = 2, + CallMessage = 1, + CallMessageWithRollback = 2, } impl From for u8 { fn from(val: MessageType) -> Self { match val { - MessageType::BasicMessage => 1, - MessageType::MessageWithRollback => 2, + MessageType::CallMessage => 1, + MessageType::CallMessageWithRollback => 2, } } } @@ -18,8 +18,8 @@ impl From for u8 { impl From for MessageType { fn from(value: u8) -> Self { match value { - 1 => MessageType::BasicMessage, - 2 => MessageType::MessageWithRollback, + 1 => MessageType::CallMessage, + 2 => MessageType::CallMessageWithRollback, _ => panic!("unsupported message type"), } } diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index be8b38f3..55520ee8 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -24,14 +24,14 @@ impl<'a> CwCallService<'a> { ) -> Result { let msg = if rollback.is_some() { AnyMessage::CallMessageWithRollback(CallMessageWithRollback { - msg_type: MessageType::MessageWithRollback, + data, rollback: rollback.unwrap(), }) } else { AnyMessage::CallMessage(CallMessage { data, - msg_type: MessageType::BasicMessage, + }) }; let envelope = Envelope::new(msg, sources, destinations); diff --git a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs index 37d08e36..155af4bf 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/types/request.rs @@ -55,7 +55,7 @@ impl CSMessageRequest { } pub fn need_response(&self) -> bool { - self.msg_type == MessageType::MessageWithRollback + self.msg_type == MessageType::CallMessageWithRollback } pub fn data(&self) -> Result<&[u8], ContractError> { @@ -176,7 +176,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - MessageType::BasicMessage, + MessageType::CallMessage, data.clone(), vec![], ); @@ -189,7 +189,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - MessageType::BasicMessage, + MessageType::CallMessage, data.clone(), vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); @@ -202,7 +202,7 @@ mod tests { NetworkAddress::from_str("0x1.ETH/0xa").unwrap(), Addr::unchecked("cx0000000000000000000000000000000000000102"), 21, - MessageType::MessageWithRollback, + MessageType::CallMessageWithRollback, data, vec!["abc".to_string(), "cde".to_string(), "efg".to_string()], ); diff --git a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs index c660bd68..19404dff 100644 --- a/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/tests/test_handle_call_message.rs @@ -42,7 +42,7 @@ fn test_execute_call_with_wrong_data() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - MessageType::BasicMessage, + MessageType::CallMessage, keccak256(&[104, 106, 108, 108, 111]).to_vec(), vec![], ); @@ -67,7 +67,7 @@ fn test_execute_call_having_request_id_without_rollback() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - MessageType::BasicMessage, + MessageType::CallMessage, keccak256(&data).to_vec(), vec![], ); @@ -119,7 +119,7 @@ fn test_successful_reply_message() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - MessageType::BasicMessage, + MessageType::CallMessage, vec![], vec![], ); @@ -154,7 +154,7 @@ fn test_failed_reply_message() { NetworkAddress::new("nid", "mockaddress"), Addr::unchecked("88bd05442686be0a5df7da33b6f1089ebfea3769b19dbb2477fe0cd6e0f123t7"), 123, - MessageType::BasicMessage, + MessageType::CallMessage, vec![], vec![], ); From 9cf281be26bcb66988f07a9665aa4eafa0ef72ee Mon Sep 17 00:00:00 2001 From: ibrizsabin Date: Fri, 1 Dec 2023 13:12:21 +0545 Subject: [PATCH 18/20] test: fix tests --- .../cw-xcall-lib/src/message/call_message.rs | 14 ++------------ .../src/message/call_message_rollback.rs | 10 +--------- .../cw-xcall-lib/src/message/envelope.rs | 9 +++++---- .../cosmwasm-vm/cw-xcall-lib/src/message/mod.rs | 9 +++------ .../cw-xcall-lib/src/message/msg_trait.rs | 3 --- .../cw-xcall-lib/src/message/msg_type.rs | 4 ++-- .../cosmwasm-vm/cw-xcall/src/send_call_message.rs | 8 ++------ 7 files changed, 15 insertions(+), 42 deletions(-) diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs index 5d4792e2..67061ea7 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message.rs @@ -1,6 +1,6 @@ use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; -use super::{msg_trait::IMessage, msg_type::MessageType}; +use super::msg_trait::IMessage; #[derive(Clone, Debug, PartialEq)] pub struct CallMessage { @@ -9,19 +9,13 @@ pub struct CallMessage { impl Encodable for CallMessage { fn rlp_append(&self, stream: &mut RlpStream) { - stream - .begin_list(1) - - .append(&self.data); + stream.begin_list(1).append(&self.data); } } impl Decodable for CallMessage { fn decode(rlp: &rlp::Rlp) -> Result { - - Ok(Self { - data: rlp.val_at(0)?, }) } @@ -36,10 +30,6 @@ impl IMessage for CallMessage { self.data.clone() } - // fn msg_type(&self) -> &MessageType { - // &self.msg_type - // } - fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs index 446ff687..78222e8a 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/call_message_rollback.rs @@ -1,6 +1,6 @@ use common::rlp::{self, Decodable, DecoderError, Encodable, RlpStream}; -use super::{msg_trait::IMessage, msg_type::MessageType}; +use super::msg_trait::IMessage; #[derive(Clone, Debug, PartialEq)] pub struct CallMessageWithRollback { @@ -12,7 +12,6 @@ impl Encodable for CallMessageWithRollback { fn rlp_append(&self, stream: &mut RlpStream) { stream .begin_list(2) - .append(&self.data) .append(&self.rollback); } @@ -20,10 +19,7 @@ impl Encodable for CallMessageWithRollback { impl Decodable for CallMessageWithRollback { fn decode(rlp: &rlp::Rlp) -> Result { - - Ok(Self { - data: rlp.val_at(0)?, rollback: rlp.val_at(1)?, }) @@ -39,10 +35,6 @@ impl IMessage for CallMessageWithRollback { self.data.clone() } - // fn msg_type(&self) -> &MessageType { - // &self.msg_type - // } - fn to_bytes(&self) -> Result, DecoderError> { Ok(rlp::encode(self).to_vec()) } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs index 869fd652..1f9ba610 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/envelope.rs @@ -78,7 +78,6 @@ mod tests { fn test_encoding_decoding_envelope_call_message() { // Create a sample Envelope let message = AnyMessage::CallMessage(CallMessage { - data: vec![1, 2, 3], }); let sources = vec!["source1".to_string(), "source2".to_string()]; @@ -87,7 +86,7 @@ mod tests { let encoded_data = rlp::encode(&envelope).to_vec(); assert_eq!( - "e60186c50183010203d087736f757263653187736f7572636532cc856465737431856465737432", + "e50185c483010203d087736f757263653187736f7572636532cc856465737431856465737432", hex::encode(&encoded_data) ); let decoded: Envelope = rlp::decode(&encoded_data).unwrap(); @@ -99,7 +98,6 @@ mod tests { fn test_encoding_decoding_envelope_call_message_rollback() { // Create a sample Envelope let message = AnyMessage::CallMessageWithRollback(CallMessageWithRollback { - data: vec![1, 2, 3], rollback: vec![1, 2, 3], }); @@ -108,7 +106,10 @@ mod tests { let envelope = Envelope::new(message, sources, destinations); let encoded_data = rlp::encode(&envelope).to_vec(); - assert_eq!("ea028ac5028301020383010203d087736f757263653187736f7572636532cc856465737431856465737432",hex::encode(&encoded_data)); + assert_eq!( + "e90289c88301020383010203d087736f757263653187736f7572636532cc856465737431856465737432", + hex::encode(&encoded_data) + ); let decoded: Envelope = rlp::decode(&encoded_data).unwrap(); assert_eq!(envelope, decoded); diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs index f1616b42..bf8f215c 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/mod.rs @@ -31,8 +31,6 @@ impl IMessage for AnyMessage { } } - - fn to_bytes(&self) -> Result, DecoderError> { match self { AnyMessage::CallMessage(m) => m.to_bytes(), @@ -44,9 +42,8 @@ impl IMessage for AnyMessage { impl AnyMessage { pub fn msg_type(&self) -> &MessageType { match self { - AnyMessage::CallMessage(m) => &MessageType::CallMessage, - AnyMessage::CallMessageWithRollback(m) => &MessageType::CallMessageWithRollback, + AnyMessage::CallMessage(_m) => &MessageType::CallMessage, + AnyMessage::CallMessageWithRollback(_m) => &MessageType::CallMessageWithRollback, } } - -} \ No newline at end of file +} diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs index fc4137c9..5f89edc0 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_trait.rs @@ -1,11 +1,8 @@ use common::rlp::DecoderError; -use super::msg_type::MessageType; - pub trait IMessage: Clone { fn rollback(&self) -> Option>; fn data(&self) -> Vec; - // fn msg_type(&self) -> &MessageType; fn to_bytes(&self) -> Result, DecoderError>; } diff --git a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs index d7ad3d6e..2d59c3b7 100644 --- a/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs +++ b/contracts/cosmwasm-vm/cw-xcall-lib/src/message/msg_type.rs @@ -2,8 +2,8 @@ use serde::Serialize; #[derive(Clone, Debug, Serialize, serde::Deserialize, PartialEq, Eq)] pub enum MessageType { - CallMessage = 1, - CallMessageWithRollback = 2, + CallMessage = 1, + CallMessageWithRollback = 2, } impl From for u8 { diff --git a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs index 55520ee8..25b8849d 100644 --- a/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs +++ b/contracts/cosmwasm-vm/cw-xcall/src/send_call_message.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{coins, BankMsg}; use cw_xcall_lib::message::call_message::CallMessage; use cw_xcall_lib::message::msg_trait::IMessage; -use cw_xcall_lib::message::msg_type::MessageType; + use cw_xcall_lib::message::AnyMessage; use cw_xcall_lib::message::{call_message_rollback::CallMessageWithRollback, envelope::Envelope}; use cw_xcall_lib::network_address::NetworkAddress; @@ -24,15 +24,11 @@ impl<'a> CwCallService<'a> { ) -> Result { let msg = if rollback.is_some() { AnyMessage::CallMessageWithRollback(CallMessageWithRollback { - data, rollback: rollback.unwrap(), }) } else { - AnyMessage::CallMessage(CallMessage { - data, - - }) + AnyMessage::CallMessage(CallMessage { data }) }; let envelope = Envelope::new(msg, sources, destinations); self.send_call(deps, info, to, envelope) From 34b4442cf1e043259661338a7dd9c55da19e93d3 Mon Sep 17 00:00:00 2001 From: AntonAndell Date: Fri, 1 Dec 2023 09:05:09 +0100 Subject: [PATCH 19/20] fix: Revert change of rollback db name Break out db paths into static String variables --- .../icon/xcall/CallServiceImpl.java | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) 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 487ab0ec..de04ce3b 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 @@ -40,20 +40,31 @@ public class CallServiceImpl implements CallService, FeeManage { public static final int MAX_ROLLBACK_SIZE = 1024; public static String NID; - private final VarDB sn = Context.newVarDB("sn", BigInteger.class); - private final VarDB reqId = Context.newVarDB("reqId", BigInteger.class); - - private final DictDB rollbacks = Context.newDictDB("rollbacks", RollbackData.class); - private final DictDB proxyReqs = Context.newDictDB("proxyReqs", CSMessageRequest.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); + public static final String SN = "sn"; + public static final String REQUEST_ID = "reqId"; + public static final String ROLLBACKS = "requests"; + public static final String PROXY_REQUESTS = "proxyReqs"; + public static final String PENDING_MESSAGES = "pendingMessages"; + public static final String SUCCESSFUL_RESPONSES = "successfulResponses"; + public static final String DEFAULT_CONNECTION = "defaultConnection"; + public static final String ADMIN = "admin"; + public static final String PROTOCOL_FEE = "protocolFee"; + public static final String FEE_HANDLER = "feeHandler"; + + private final VarDB sn = Context.newVarDB(SN, BigInteger.class); + private final VarDB reqId = Context.newVarDB(REQUEST_ID, BigInteger.class); + + private final DictDB rollbacks = Context.newDictDB(ROLLBACKS, RollbackData.class); + private final DictDB proxyReqs = Context.newDictDB(PROXY_REQUESTS, CSMessageRequest.class); + private final BranchDB> pendingMessages = Context.newBranchDB(PENDING_MESSAGES, Boolean.class); + private final DictDB successfulResponses = Context.newDictDB(SUCCESSFUL_RESPONSES, Boolean.class); + + private final DictDB defaultConnection = Context.newDictDB(DEFAULT_CONNECTION, Address.class); // for fee-related operations - private final VarDB
admin = Context.newVarDB("admin", Address.class); - private final VarDB protocolFee = Context.newVarDB("protocolFee", BigInteger.class); - private final VarDB
feeHandler = Context.newVarDB("feeHandler", Address.class); + private final VarDB
admin = Context.newVarDB(ADMIN, Address.class); + private final VarDB protocolFee = Context.newVarDB(PROTOCOL_FEE, BigInteger.class); + private final VarDB
feeHandler = Context.newVarDB(FEE_HANDLER, Address.class); public CallServiceImpl(String networkId) { NID = networkId; From 28b1eb4a7cc2f57e7c2c9f2b74f063736e0ac16e Mon Sep 17 00:00:00 2001 From: ibrizsabin <101165234+ibrizsabin@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:00:42 +0545 Subject: [PATCH 20/20] Update docs/adr/xcall.md Co-authored-by: AntonAndell --- docs/adr/xcall.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/adr/xcall.md b/docs/adr/xcall.md index eb8428a3..2512813b 100644 --- a/docs/adr/xcall.md +++ b/docs/adr/xcall.md @@ -544,8 +544,7 @@ payable external function sendCallMessage(String _to, envelope = new Envelope(msg, _sources, _destinations) return sendCall(_to, envelope.toBytes()) - envelope = new XCallEnvelope(msg, _sources, _destinations) - return sendCall(_to, envelope.toBytes()); + } ```