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

fix: cluster connection audit #424

Merged
merged 9 commits into from
Dec 13, 2024
89 changes: 63 additions & 26 deletions contracts/evm/contracts/adapters/ClusterConnection.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity >=0.8.0;
pragma abicoder v2;

import {console2 } from "forge-std/Test.sol";
import {console2} from "forge-std/Test.sol";

import "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
import "@xcall/utils/Types.sol";
Expand All @@ -12,7 +12,6 @@ import "@iconfoundation/xcall-solidity-library/utils/RLPEncode.sol";
import "@iconfoundation/xcall-solidity-library/utils/RLPEncode.sol";

contract ClusterConnection is Initializable, IConnection {

using RLPEncode for bytes;
using RLPEncode for string;
using RLPEncode for uint256;
Expand Down Expand Up @@ -51,12 +50,18 @@ contract ClusterConnection is Initializable, IConnection {
return validators;
}

function updateValidators(bytes[] memory _validators, uint8 _threshold) external onlyAdmin {
function updateValidators(
bytes[] memory _validators,
uint8 _threshold
) external onlyAdmin {
delete validators;
for (uint i = 0; i < _validators.length; i++) {
address validators_address = publicKeyToAddress(_validators[i]);
if(!isValidator(validators_address) && validators_address != address(0)) {
validators.push(validators_address);
if (
!isValidator(validators_address) &&
validators_address != address(0)
) {
validators.push(validators_address);
}
}
require(validators.length >= _threshold, "Not enough validators");
Expand Down Expand Up @@ -141,42 +146,65 @@ contract ClusterConnection is Initializable, IConnection {
string memory srcNetwork,
uint256 _connSn,
bytes calldata _msg,
string memory dstNetwork,
gcranju marked this conversation as resolved.
Show resolved Hide resolved
bytes[] calldata _signedMessages
) public onlyRelayer {
require(_signedMessages.length >= validatorsThreshold, "Not enough signatures passed");
bytes32 messageHash = getMessageHash(srcNetwork, _connSn, _msg);
require(
_signedMessages.length >= validatorsThreshold,
"Not enough signatures passed"
);
bytes32 messageHash = getMessageHash(
srcNetwork,
_connSn,
_msg,
dstNetwork
);
uint signerCount = 0;
address[] memory collectedSigners = new address[](_signedMessages.length);

address[] memory collectedSigners = new address[](
_signedMessages.length
);

for (uint i = 0; i < _signedMessages.length; i++) {
address signer = recoverSigner(messageHash, _signedMessages[i]);
require(signer != address(0), "Invalid signature");
if (!isValidatorProcessed(collectedSigners, signer) && existsInValidators(signer)){
if (
!isValidatorProcessed(collectedSigners, signer) &&
existsInValidators(signer)
) {
collectedSigners[signerCount] = signer;
signerCount++;
}
}
require(signerCount >= validatorsThreshold,"Not enough valid signatures passed");
recvMessage(srcNetwork,_connSn,_msg);
require(
signerCount >= validatorsThreshold,
"Not enough valid signatures passed"
);
recvMessage(srcNetwork, _connSn, _msg);
}

function existsInValidators(address signer) internal view returns (bool) {
for (uint i = 0; i < validators.length; i++){
for (uint i = 0; i < validators.length; i++) {
if (validators[i] == signer) return true;
}
return false;
}

function isValidatorProcessed(address[] memory processedSigners, address signer) public pure returns (bool) {
function isValidatorProcessed(
address[] memory processedSigners,
address signer
) public pure returns (bool) {
for (uint i = 0; i < processedSigners.length; i++) {
if (processedSigners[i] == signer) {
return true;
}
}
return false;
}
}

function recoverSigner(bytes32 messageHash, bytes memory signature) public pure returns (address) {
function recoverSigner(
bytes32 messageHash,
bytes memory signature
) public pure returns (address) {
require(signature.length == 65, "Invalid signature length");
bytes32 r;
bytes32 s;
Expand Down Expand Up @@ -240,7 +268,7 @@ contract ClusterConnection is Initializable, IConnection {
adminAddress = _address;
}

/**
/**
@notice Set the address of the relayer.
@param _address The address of the relayer.
*/
Expand Down Expand Up @@ -268,24 +296,34 @@ contract ClusterConnection is Initializable, IConnection {
@notice Set the required signature count for verification.
@param _count The desired count.
*/
function setRequiredValidatorCount(uint8 _count) external onlyAdmin() {
function setRequiredValidatorCount(uint8 _count) external onlyAdmin {
validatorsThreshold = _count;
}

function getRequiredValidatorCount() external view returns (uint8) {
return validatorsThreshold;
}

function getMessageHash(string memory srcNetwork, uint256 _connSn, bytes calldata _msg) internal pure returns (bytes32) {
bytes memory rlp = abi.encodePacked(
srcNetwork.encodeString(),
_connSn.encodeUint(),
_msg.encodeBytes()
).encodeList();
function getMessageHash(
string memory srcNetwork,
uint256 _connSn,
bytes calldata _msg,
string memory dstNetwork
) internal pure returns (bytes32) {
bytes memory rlp = abi
.encodePacked(
srcNetwork.encodeString(),
_connSn.encodeUint(),
_msg.encodeBytes(),
srcNetwork.encodeString()
sherpalden marked this conversation as resolved.
Show resolved Hide resolved
)
.encodeList();
return keccak256(rlp);
}

function publicKeyToAddress(bytes memory publicKey) internal pure returns (address addr) {
function publicKeyToAddress(
bytes memory publicKey
) internal pure returns (address addr) {
require(publicKey.length == 65, "Invalid public key length");

bytes32 hash;
Expand All @@ -298,5 +336,4 @@ contract ClusterConnection is Initializable, IConnection {

addr = address(uint160(uint256(hash)));
}

}
Loading
Loading