Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: response message solidity #234

Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e29e98b
feat: xcall upgradeable (#179)
gcranju Dec 15, 2023
d2995c1
fix: network address validation fixed (#212)
gcranju Dec 15, 2023
a0de612
fix: not authorized issue by making handleMessage public (#202)
gcranju Dec 15, 2023
7a8de78
ci: add job to update CHANGELOG.md (#207)
DeepakBomjan Dec 15, 2023
048a65a
fix: added rpsc in foundry.toml
gcranju Dec 22, 2023
3c33770
fix: fix env.example
gcranju Dec 22, 2023
1b64d8d
Merge pull request #221 from icon-project/deploy-script-fix
izyak Dec 22, 2023
9694787
fix: new message type added in solidity
gcranju Dec 27, 2023
5972a5c
Merge remote-tracking branch 'origin/main' into 182-solidity-implemen…
gcranju Dec 27, 2023
d703295
feat: add centralized connections in solidity and java (#196)
gcranju Dec 28, 2023
6729816
fix: unnecessary event log removed
gcranju Dec 29, 2023
b8dc3a8
fix: sendBTPMessage renamed to sendToConnection
gcranju Dec 29, 2023
d0d8f54
fix: unnecessary event log removed
gcranju Dec 29, 2023
99f68b6
feat: add centralized connections in solidity and java (#196)
gcranju Dec 28, 2023
dea884d
fix: centralized-connection test fixed
gcranju Dec 29, 2023
4206ef6
fix: proxy request structure with data hash added
gcranju Dec 29, 2023
396c2da
Merge branch 'main' into 182-solidity-implement-new-message-flow
gcranju Jan 3, 2024
239e025
fix: getFee method
gcranju Jan 4, 2024
c6a8f07
fix: message encoding decoding fixed
gcranju Jan 4, 2024
5beac56
fix: logs removed
gcranju Jan 4, 2024
c891144
feat: response message solidity
gcranju Jan 14, 2024
8e7676d
Merge branch 'development/177-xcall-future-proof-messaging' into feat…
gcranju Jan 15, 2024
a8c8495
fix: review changes
gcranju Jan 15, 2024
0ef234b
feat: tests added
gcranju Jan 15, 2024
d72a678
Merge branch 'development/177-xcall-future-proof-messaging' into feat…
gcranju Jan 18, 2024
5bb2a6c
fix merge issues
gcranju Jan 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 139 additions & 62 deletions contracts/evm/contracts/xcall/CallService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
mapping(uint256 => mapping(string => bool)) private pendingResponses;

mapping(string => address) private defaultConnections;
bytes private callReply;
Types.ProxyRequest private replyState;

address private owner;
address private adminAddress;
Expand Down Expand Up @@ -125,8 +127,6 @@
return _sendCallMessage(_to, _data, _rollback, src, dst);
}



function sendCall(
string memory _to,
bytes memory _data
Expand Down Expand Up @@ -157,16 +157,21 @@
bytes memory _msg = req.encodeCSMessageRequest();
require(_msg.length <= MAX_DATA_SIZE, "MaxDataSizeExceeded");

uint256 sendSn = result.needResponse ? sn : 0;
if (isReply(netTo, envelope.sources) && !result.needResponse) {
delete replyState;
callReply = _msg;

Check warning on line 162 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L161-L162

Added lines #L161 - L162 were not covered by tests
} else {
uint256 sendSn = result.needResponse ? sn : 0;

sendMessage(
envelope.sources,
netTo,
Types.CS_REQUEST,
int(sendSn),
_msg
);
claimProtocolFee();
sendMessage(
envelope.sources,
netTo,
Types.CS_REQUEST,
int(sendSn),
_msg
);
claimProtocolFee();
}
emit CallMessageSent(caller, _to, sn);
return sn;
}
Expand All @@ -187,14 +192,7 @@
for (uint i = 0; i < sources.length; i++) {
address conn = sources[i].parseAddress("IllegalArgument");
uint256 requiredFee = _getFee(conn, netTo, sn);
sendToConnection(
conn,
requiredFee,
netTo,
msgType,
sn,
data
);
sendToConnection(conn, requiredFee, netTo, msgType, sn, data);
}
}
}
Expand Down Expand Up @@ -245,28 +243,23 @@
Types.XCallEnvelope memory envelope;

if (_rollback.length == 0) {

Types.CallMessage memory _msg = Types.CallMessage(_data);
envelope = Types.XCallEnvelope(
Types.CALL_MESSAGE_TYPE,
_msg.data,
sources,
destinations
);
} else {

Types.CallMessageWithRollback memory _msg = Types.CallMessageWithRollback(
_data,
_rollback
Types.CALL_MESSAGE_TYPE,
_msg.data,
sources,
destinations
);
} else {
Types.CallMessageWithRollback memory _msg = Types
.CallMessageWithRollback(_data, _rollback);

envelope = Types.XCallEnvelope(
Types.CALL_MESSAGE_ROLLBACK_TYPE,
_msg.encodeCallMessageWithRollback(),
sources,
destinations
);

Types.CALL_MESSAGE_ROLLBACK_TYPE,
_msg.encodeCallMessageWithRollback(),
sources,
destinations
);
}

return sendCall(_to, envelope.encodeXCallEnvelope());
Expand All @@ -283,23 +276,36 @@

if (req.messageType == Types.CALL_MESSAGE_TYPE) {
tryExecuteCall(_reqId, req.to, req.from, _data, protocols);
} else if (
req.messageType == Types.CALL_MESSAGE_ROLLBACK_TYPE
) {
int256 code = tryExecuteCall(_reqId, req.to, req.from, _data, protocols);
} else if (req.messageType == Types.CALL_MESSAGE_ROLLBACK_TYPE) {
replyState = req;
int256 code = tryExecuteCall(
_reqId,
req.to,
req.from,
_data,
protocols
);
delete replyState;

bytes memory message;

if (callReply.length > 0 && code == Types.CS_RESP_SUCCESS) {
message = callReply;
delete callReply;

Check warning on line 294 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L293-L294

Added lines #L293 - L294 were not covered by tests
}
Types.CSMessageResult memory response = Types.CSMessageResult(
req.sn,
code
code,
message
);

sendMessage(
protocols,
req.from.nid(),
Types.CS_RESULT,
int256(req.sn)*-1,
int256(req.sn) * -1,
response.encodeCSMessageResult()
);
);
} else {
revert("Message type is not yet supported");
}
Expand Down Expand Up @@ -397,7 +403,7 @@
if (csMsg.msgType == Types.CS_REQUEST) {
handleRequest(_from, csMsg.payload);
} else if (csMsg.msgType == Types.CS_RESULT) {
handlResult(csMsg.payload.decodeCSMessageResult());
handleResult(csMsg.payload.decodeCSMessageResult());
} else {
string memory errMsg = string("UnknownMsgType(")
.concat(uint(csMsg.msgType).toString())
Expand All @@ -407,7 +413,9 @@
}

function handleError(uint256 _sn) public override {
handlResult(Types.CSMessageResult(_sn, Types.CS_RESP_FAILURE));
handleResult(
Types.CSMessageResult(_sn, Types.CS_RESP_FAILURE, bytes(""))
);
}

function sendToConnection(
Expand All @@ -432,8 +440,8 @@
) internal {
Types.CSMessageRequest memory req = msgPayload.decodeCSMessageRequest();
string memory fromNID = req.from.nid();
require(netFrom.compareTo(fromNID),"Invalid NID");

require(netFrom.compareTo(fromNID), "Invalid NID");
bytes32 dataHash = keccak256(req.data);
if (req.protocols.length > 1) {
pendingReqs[dataHash][msg.sender.toString()] = true;
Expand All @@ -446,7 +454,10 @@
delete pendingReqs[dataHash][req.protocols[i]];
}
} else if (req.protocols.length == 1) {
require(msg.sender == req.protocols[0].parseAddress("IllegalArgument"), "NotAuthorized");
require(
msg.sender == req.protocols[0].parseAddress("IllegalArgument"),
"NotAuthorized"
);
} else {
require(msg.sender == defaultConnections[fromNID], "NotAuthorized");
}
Expand All @@ -463,41 +474,74 @@
emit CallMessage(req.from, req.to, req.sn, reqId, req.data);
}

function handlResult(Types.CSMessageResult memory res) internal {
Types.RollbackData memory req = rollbacks[res.sn];
if (req.from == address(0)) {
function handleReply(
Types.RollbackData memory rollback,
Types.CSMessageRequest memory reply
) internal {
require(

Check warning on line 481 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L481

Added line #L481 was not covered by tests
rollback.from == reply.to.parseAddress("IllegalArgument") &&
gcranju marked this conversation as resolved.
Show resolved Hide resolved
keccak256(bytes(rollback.to.nid())) ==
keccak256(bytes(reply.from.nid())),
"Invalid Reply"
);

uint256 reqId = getNextReqId();

Check warning on line 488 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L488

Added line #L488 was not covered by tests

emit CallMessage(reply.from, reply.to, reply.sn, reqId, reply.data);

Check warning on line 490 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L490

Added line #L490 was not covered by tests

proxyReqs[reqId] = Types.ProxyRequest(

Check warning on line 492 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L492

Added line #L492 was not covered by tests
reply.from,
reply.to,
reply.sn,
reply.messageType,
keccak256(reply.data),
rollback.sources
);
}

function handleResult(Types.CSMessageResult memory res) internal {
Types.RollbackData memory rollback = rollbacks[res.sn];
if (rollback.from == address(0)) {
return;
}

if (req.sources.length > 1) {
if (rollback.sources.length > 1) {
pendingResponses[res.sn][msg.sender.toString()] = true;
for (uint i = 0; i < req.sources.length; i++) {
if (!pendingResponses[res.sn][req.sources[i]]) {
for (uint i = 0; i < rollback.sources.length; i++) {
if (!pendingResponses[res.sn][rollback.sources[i]]) {
return;
}
}

for (uint i = 0; i < req.sources.length; i++) {
delete pendingResponses[res.sn][req.sources[i]];
for (uint i = 0; i < rollback.sources.length; i++) {
delete pendingResponses[res.sn][rollback.sources[i]];
}
} else if (req.sources.length == 1) {
} else if (rollback.sources.length == 1) {
require(
msg.sender == req.sources[0].parseAddress("IllegalArgument"),
msg.sender ==
rollback.sources[0].parseAddress("IllegalArgument"),
"NotAuthorized"
);
} else {
require(msg.sender == defaultConnections[req.to], "NotAuthorized");
require(
msg.sender == defaultConnections[rollback.to],
"NotAuthorized"
);
}

emit ResponseMessage(res.sn, res.code);
if (res.code == Types.CS_RESP_SUCCESS) {
cleanupCallRequest(res.sn);
if (res.message.length > 0) {
handleReply(rollback, res.message.decodeCSMessageRequest());

Check warning on line 536 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L536

Added line #L536 was not covered by tests
}
successfulResponses[res.sn] = true;
} else {
//emit rollback event
require(req.rollback.length > 0, "NoRollbackData");
req.enabled = true;
rollbacks[res.sn] = req;
require(rollback.rollback.length > 0, "NoRollbackData");
rollback.enabled = true;
rollbacks[res.sn] = rollback;

emit RollbackMessage(res.sn);
}
}
Expand Down Expand Up @@ -588,6 +632,9 @@
string[] memory _sources
) external view override returns (uint256) {
uint256 fee = protocolFee;
if (isReply(_net, _sources) && !_rollback) {
return fee;

Check warning on line 636 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L635-L636

Added lines #L635 - L636 were not covered by tests
}
for (uint i = 0; i < _sources.length; i++) {
address conn = _sources[i].parseAddress("IllegalArgument");
fee = fee + _getFee(conn, _net, _rollback);
Expand All @@ -596,6 +643,36 @@
return fee;
}

function isReply(
string memory _net,
string[] memory _sources
) internal view returns (bool) {
if (keccak256(bytes(replyState.from)) != keccak256(bytes(""))) {
return
keccak256(bytes(replyState.from.nid())) ==
keccak256(bytes(_net)) &&
areArraysEqual(replyState.protocols, _sources);

Check warning on line 654 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L651-L654

Added lines #L651 - L654 were not covered by tests
}
return false;
}

function areArraysEqual(
string[] memory array1,
string[] memory array2
) internal pure returns (bool) {
if (array1.length != array2.length) {
return false;

Check warning on line 664 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L663-L664

Added lines #L663 - L664 were not covered by tests
}

for (uint256 i = 0; i < array1.length; i++) {
if (keccak256(bytes(array1[i])) != keccak256(bytes(array2[i]))) {
return false;

Check warning on line 669 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L667-L669

Added lines #L667 - L669 were not covered by tests
}
}

return true;

Check warning on line 673 in contracts/evm/contracts/xcall/CallService.sol

View check run for this annotation

Codecov / codecov/patch

contracts/evm/contracts/xcall/CallService.sol#L673

Added line #L673 was not covered by tests
}

function verifySuccess(uint256 _sn) external view returns (bool) {
return successfulResponses[_sn];
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/evm/library/utils/RLPDecodeStruct.sol
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,6 @@ library RLPDecodeStruct {
bytes memory _rlp
) internal pure returns (Types.CSMessageResult memory) {
RLPDecode.RLPItem[] memory ls = _rlp.toRlpItem().toList();
return Types.CSMessageResult(ls[0].toUint(), int(ls[1].toInt()));
return Types.CSMessageResult(ls[0].toUint(), ls[1].toInt(), ls[2].toBytes());
}
}
3 changes: 2 additions & 1 deletion contracts/evm/library/utils/RLPEncodeStruct.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ library RLPEncodeStruct {
) internal pure returns (bytes memory) {
bytes memory _rlp = abi.encodePacked(
_bs.sn.encodeUint(),
_bs.code.encodeInt()
_bs.code.encodeInt(),
_bs.message.encodeBytes()
);
return _rlp.encodeList();
}
Expand Down
1 change: 1 addition & 0 deletions contracts/evm/library/utils/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ library Types {
struct CSMessageResult {
uint256 sn;
int code;
bytes message;
}

struct PendingResponse {
Expand Down
Loading
Loading