From 0aac2ab099888258e452e777561c11d8ef35a432 Mon Sep 17 00:00:00 2001 From: Uladzislau Hubar Date: Wed, 24 Jan 2024 15:43:17 +0100 Subject: [PATCH] Renamed Sharding Table structs, added possibility to add Node to the Sharding Table using Binary Search for position search --- contracts/v1/ShardingTable.sol | 20 +-- ...Structs.sol => ShardingTableStructsV1.sol} | 2 +- contracts/v2/CommitManagerV1U1.sol | 2 +- contracts/v2/ShardingTable.sol | 141 +++++++++++------- contracts/v2/scoring/LinearSum.sol | 23 --- contracts/v2/storage/ShardingTableStorage.sol | 28 +++- ...Structs.sol => ShardingTableStructsV2.sol} | 3 +- 7 files changed, 125 insertions(+), 94 deletions(-) rename contracts/v1/structs/{ShardingTableStructs.sol => ShardingTableStructsV1.sol} (89%) rename contracts/v2/structs/{ShardingTableStructs.sol => ShardingTableStructsV2.sol} (83%) diff --git a/contracts/v1/ShardingTable.sol b/contracts/v1/ShardingTable.sol index 4d7f7936..38266024 100644 --- a/contracts/v1/ShardingTable.sol +++ b/contracts/v1/ShardingTable.sol @@ -9,7 +9,7 @@ import {ContractStatus} from "./abstract/ContractStatus.sol"; import {Initializable} from "./interface/Initializable.sol"; import {Named} from "./interface/Named.sol"; import {Versioned} from "./interface/Versioned.sol"; -import {ShardingTableStructs} from "./structs/ShardingTableStructs.sol"; +import {ShardingTableStructsV1} from "./structs/ShardingTableStructsV1.sol"; import {NULL} from "./constants/ShardingTableConstants.sol"; contract ShardingTable is Named, Versioned, ContractStatus, Initializable { @@ -43,11 +43,11 @@ contract ShardingTable is Named, Versioned, ContractStatus, Initializable { function getShardingTable( uint72 startingIdentityId, uint72 nodesNumber - ) external view returns (ShardingTableStructs.NodeInfo[] memory) { + ) external view returns (ShardingTableStructsV1.NodeInfo[] memory) { return _getShardingTable(startingIdentityId, nodesNumber); } - function getShardingTable() external view returns (ShardingTableStructs.NodeInfo[] memory) { + function getShardingTable() external view returns (ShardingTableStructsV1.NodeInfo[] memory) { ShardingTableStorage sts = shardingTableStorage; return _getShardingTable(sts.head(), sts.nodesCount()); } @@ -106,7 +106,7 @@ contract ShardingTable is Named, Versioned, ContractStatus, Initializable { ShardingTableStorage sts = shardingTableStorage; - ShardingTableStructs.Node memory nodeToRemove = sts.getNode(identityId); + ShardingTableStructsV1.Node memory nodeToRemove = sts.getNode(identityId); uint72 head = sts.head(); uint72 tail = sts.tail(); @@ -133,24 +133,24 @@ contract ShardingTable is Named, Versioned, ContractStatus, Initializable { function _getShardingTable( uint72 startingIdentityId, uint72 nodesNumber - ) internal view virtual returns (ShardingTableStructs.NodeInfo[] memory) { - ShardingTableStructs.NodeInfo[] memory nodesPage; + ) internal view virtual returns (ShardingTableStructsV1.NodeInfo[] memory) { + ShardingTableStructsV1.NodeInfo[] memory nodesPage; ShardingTableStorage sts = shardingTableStorage; if ((sts.nodesCount() == 0) || (nodesNumber == 0)) { return nodesPage; } - ShardingTableStructs.Node memory startingNode = sts.getNode(startingIdentityId); + ShardingTableStructsV1.Node memory startingNode = sts.getNode(startingIdentityId); require((startingIdentityId == NULL) || (startingNode.identityId != NULL), "Wrong starting Identity ID"); - nodesPage = new ShardingTableStructs.NodeInfo[](nodesNumber); + nodesPage = new ShardingTableStructsV1.NodeInfo[](nodesNumber); ProfileStorage ps = profileStorage; StakingStorage ss = stakingStorage; - nodesPage[0] = ShardingTableStructs.NodeInfo({ + nodesPage[0] = ShardingTableStructsV1.NodeInfo({ nodeId: ps.getNodeId(startingIdentityId), identityId: startingIdentityId, ask: ps.getAsk(startingNode.identityId), @@ -162,7 +162,7 @@ contract ShardingTable is Named, Versioned, ContractStatus, Initializable { while ((i < nodesNumber) && (nextIdentityId != NULL)) { nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; - nodesPage[i] = ShardingTableStructs.NodeInfo({ + nodesPage[i] = ShardingTableStructsV1.NodeInfo({ nodeId: ps.getNodeId(nextIdentityId), identityId: nextIdentityId, ask: ps.getAsk(nextIdentityId), diff --git a/contracts/v1/structs/ShardingTableStructs.sol b/contracts/v1/structs/ShardingTableStructsV1.sol similarity index 89% rename from contracts/v1/structs/ShardingTableStructs.sol rename to contracts/v1/structs/ShardingTableStructsV1.sol index 654efdb6..53259b79 100644 --- a/contracts/v1/structs/ShardingTableStructs.sol +++ b/contracts/v1/structs/ShardingTableStructsV1.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.16; -library ShardingTableStructs { +library ShardingTableStructsV1 { struct NodeInfo { bytes nodeId; uint72 identityId; diff --git a/contracts/v2/CommitManagerV1U1.sol b/contracts/v2/CommitManagerV1U1.sol index 58d926cb..ce49760c 100644 --- a/contracts/v2/CommitManagerV1U1.sol +++ b/contracts/v2/CommitManagerV1U1.sol @@ -20,7 +20,7 @@ import {GeneralErrors} from "../v1/errors/GeneralErrors.sol"; import {ServiceAgreementErrorsV1} from "../v1/errors/ServiceAgreementErrorsV1.sol"; import {ServiceAgreementErrorsV2} from "./errors/ServiceAgreementErrorsV2.sol"; import {ServiceAgreementStructsV2} from "./structs/ServiceAgreementStructsV2.sol"; -import {ShardingTableStructs} from "../v2/structs/ShardingTableStructs.sol"; +import {ShardingTableStructsV2} from "../v2/structs/ShardingTableStructsV2.sol"; import {CommitManagerErrorsV2} from "./errors/CommitManagerErrorsV2.sol"; contract CommitManagerV2 is Named, Versioned, ContractStatus, Initializable { diff --git a/contracts/v2/ShardingTable.sol b/contracts/v2/ShardingTable.sol index d3f58395..ec2d7e0a 100644 --- a/contracts/v2/ShardingTable.sol +++ b/contracts/v2/ShardingTable.sol @@ -9,7 +9,7 @@ import {ContractStatus} from "../v1/abstract/ContractStatus.sol"; import {Initializable} from "../v1/interface/Initializable.sol"; import {Named} from "../v1/interface/Named.sol"; import {Versioned} from "../v1/interface/Versioned.sol"; -import {ShardingTableStructs} from "./structs/ShardingTableStructs.sol"; +import {ShardingTableStructsV2} from "./structs/ShardingTableStructsV2.sol"; import {ShardingTableErrors} from "./errors/ShardingTableErrors.sol"; import {NULL} from "../v1/constants/ShardingTableConstants.sol"; @@ -45,25 +45,90 @@ contract ShardingTableV2 is Named, Versioned, ContractStatus, Initializable { function getShardingTable( uint72 startingIdentityId, uint72 nodesNumber - ) external view returns (ShardingTableStructs.NodeInfo[] memory) { + ) external view returns (ShardingTableStructsV2.NodeInfo[] memory) { return _getShardingTable(startingIdentityId, nodesNumber); } - function getShardingTable() external view returns (ShardingTableStructs.NodeInfo[] memory) { + function getShardingTable() external view returns (ShardingTableStructsV2.NodeInfo[] memory) { ShardingTableStorageV2 sts = shardingTableStorage; return _getShardingTable(sts.head(), sts.nodesCount()); } + function insertNode(uint72 identityId) external onlyContracts { + uint256 newNodeHashRingPosition = uint256(profileStorage.getNodeAddress(identityId, 1)); + (uint72 prevIdentityId, uint72 nextIdentityId) = _binarySearchForPosition(newNodeHashRingPosition); + + _insertNode(newNodeHashRingPosition, identityId, prevIdentityId, nextIdentityId); + } + function insertNode(uint72 identityId, uint72 prevIdentityId, uint72 nextIdentityId) external onlyContracts { - ProfileStorage ps = profileStorage; + _insertNode(uint256(profileStorage.getNodeAddress(identityId, 1)), identityId, prevIdentityId, nextIdentityId); + } + + function removeNode(uint72 identityId) external onlyContracts { + ShardingTableStorageV2 sts = shardingTableStorage; - uint256 newNodeHashRingPosition = uint256(ps.getNodeAddress(identityId, 1)); + ShardingTableStructsV2.Node memory nodeToRemove = sts.getNode(identityId); - require(newNodeHashRingPosition != 0, "Profile doesn't exist"); + sts.link(nodeToRemove.prevIdentityId, nodeToRemove.nextIdentityId); + + uint72 index = nodeToRemove.index; + uint72 nextIdentityId = nodeToRemove.nextIdentityId; + while (nextIdentityId != NULL) { + sts.decrementNodeIndex(nextIdentityId); + sts.setIdentityId(index, nextIdentityId); + unchecked { + index += 1; + } + nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; + } + + sts.deleteNodeObject(identityId); + sts.decrementNodesCount(); + + emit NodeRemoved(identityId, profileStorage.getNodeId(identityId)); + } + + function _binarySearchForPosition(uint256 hashRingPosition) internal virtual returns (uint72, uint72) { ShardingTableStorageV2 sts = shardingTableStorage; - ShardingTableStructs.Node memory prevNode = sts.getNode(prevIdentityId); + uint72 left = 0; + uint72 mid; + uint72 right = sts.nodesCount() - 1; + + uint72 prevIdentityId; + uint72 nextIdentityId; + while (left <= right) { + mid = (left + right) / 2; + ShardingTableStructsV2.Node memory currentNode = sts.getNodeByIndex(mid); + + if (currentNode.hashRingPosition < hashRingPosition) { + prevIdentityId = currentNode.identityId; + left = mid + 1; + } else if (currentNode.hashRingPosition > hashRingPosition) { + nextIdentityId = currentNode.identityId; + right = mid - 1; + } else { + prevIdentityId = currentNode.identityId; + nextIdentityId = currentNode.nextIdentityId; + break; + } + } + + return (prevIdentityId, nextIdentityId); + } + + function _insertNode( + uint256 newNodeHashRingPosition, + uint72 identityId, + uint72 prevIdentityId, + uint72 nextIdentityId + ) internal virtual { + ShardingTableStorageV2 sts = shardingTableStorage; + ProfileStorage ps = profileStorage; + + ShardingTableStructsV2.Node memory prevNode = sts.getNode(prevIdentityId); if (prevNode.hashRingPosition > newNodeHashRingPosition) { revert ShardingTableErrors.InvalidPreviousIdentityId( @@ -74,7 +139,7 @@ contract ShardingTableV2 is Named, Versioned, ContractStatus, Initializable { ); } - ShardingTableStructs.Node memory nextNode = sts.getNode(nextIdentityId); + ShardingTableStructsV2.Node memory nextNode = sts.getNode(nextIdentityId); if (nextNode.identityId != NULL && nextNode.hashRingPosition < newNodeHashRingPosition) { revert ShardingTableErrors.InvalidNextIdentityId( @@ -95,13 +160,8 @@ contract ShardingTableV2 is Named, Versioned, ContractStatus, Initializable { ); } - sts.createNodeObject( - uint256(ps.getNodeAddress(identityId, 1)), - nextNode.index, - identityId, - prevIdentityId, - nextIdentityId - ); + sts.createNodeObject(newNodeHashRingPosition, identityId, prevIdentityId, nextIdentityId, nextNode.index); + sts.setIdentityId(nextNode.index, identityId); sts.incrementNodesCount(); if (prevIdentityId == NULL) { @@ -114,8 +174,14 @@ contract ShardingTableV2 is Named, Versioned, ContractStatus, Initializable { sts.link(identityId, nextIdentityId); } + uint72 index = nextNode.index + 1; while (nextIdentityId != NULL) { sts.incrementNodeIndex(nextIdentityId); + sts.setIdentityId(index, nextIdentityId); + + unchecked { + index += 1; + } nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; } @@ -127,66 +193,39 @@ contract ShardingTableV2 is Named, Versioned, ContractStatus, Initializable { ); } - function removeNode(uint72 identityId) external onlyContracts { - ShardingTableStorageV2 sts = shardingTableStorage; - - ShardingTableStructs.Node memory nodeToRemove = sts.getNode(identityId); - - require(nodeToRemove.identityId != 0, "Profile doesn't exist"); - - sts.link(nodeToRemove.prevIdentityId, nodeToRemove.nextIdentityId); - - uint72 nextIdentityId = nodeToRemove.nextIdentityId; - while (nextIdentityId != NULL) { - sts.decrementNodeIndex(nextIdentityId); - nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; - } - - sts.deleteNodeObject(identityId); - sts.decrementNodesCount(); - - emit NodeRemoved(identityId, profileStorage.getNodeId(identityId)); - } - function _getShardingTable( uint72 startingIdentityId, uint72 nodesNumber - ) internal view virtual returns (ShardingTableStructs.NodeInfo[] memory) { - ShardingTableStructs.NodeInfo[] memory nodesPage; + ) internal view virtual returns (ShardingTableStructsV2.NodeInfo[] memory) { + ShardingTableStructsV2.NodeInfo[] memory nodesPage; ShardingTableStorageV2 sts = shardingTableStorage; if ((sts.nodesCount() == 0) || (nodesNumber == 0)) { return nodesPage; } - ShardingTableStructs.Node memory startingNode = sts.getNode(startingIdentityId); + ShardingTableStructsV2.Node memory startingNode = sts.getNode(startingIdentityId); require((startingIdentityId == NULL) || (startingNode.identityId != NULL), "Wrong starting Identity ID"); - nodesPage = new ShardingTableStructs.NodeInfo[](nodesNumber); + nodesPage = new ShardingTableStructsV2.NodeInfo[](nodesNumber); ProfileStorage ps = profileStorage; StakingStorage ss = stakingStorage; - nodesPage[0] = ShardingTableStructs.NodeInfo({ - nodeId: ps.getNodeId(startingIdentityId), - identityId: startingIdentityId, - ask: ps.getAsk(startingNode.identityId), - stake: ss.totalStakes(startingNode.identityId) - }); - uint72 nextIdentityId = startingIdentityId; - uint72 i = 1; + uint72 i; while ((i < nodesNumber) && (nextIdentityId != NULL)) { - nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; - - nodesPage[i] = ShardingTableStructs.NodeInfo({ + nodesPage[i] = ShardingTableStructsV2.NodeInfo({ + hashRingPosition: uint256(ps.getNodeAddress(nextIdentityId, 1)), nodeId: ps.getNodeId(nextIdentityId), identityId: nextIdentityId, ask: ps.getAsk(nextIdentityId), stake: ss.totalStakes(nextIdentityId) }); + nextIdentityId = sts.getNode(nextIdentityId).nextIdentityId; + unchecked { i += 1; } diff --git a/contracts/v2/scoring/LinearSum.sol b/contracts/v2/scoring/LinearSum.sol index b82ea6d1..ae041494 100644 --- a/contracts/v2/scoring/LinearSum.sol +++ b/contracts/v2/scoring/LinearSum.sol @@ -70,29 +70,6 @@ contract LinearSum is IScoreFunction, Indexable, Named, HubDependent, Initializa return uint256(nodeIdHash ^ keywordHash); } - function calculateClockwiseProximityOnHashRing( - uint8 hashFunctionId, - bytes calldata nodeId, - bytes calldata keyword - ) external view returns (uint256) { - HashingProxy hp = hashingProxy; - bytes32 nodeIdHash = hp.callHashFunction(hashFunctionId, nodeId); - bytes32 keywordHash = hp.callHashFunction(hashFunctionId, keyword); - - uint256 peerPositionOnHashRing = uint256(nodeIdHash); - uint256 keyPositionOnHashRing = uint256(keywordHash); - - uint256 clockwiseDistance; - if (peerPositionOnHashRing > keyPositionOnHashRing) { - uint256 distanceToEnd = HASH_RING_SIZE - peerPositionOnHashRing; - clockwiseDistance = distanceToEnd + keyPositionOnHashRing; - } else { - clockwiseDistance = keyPositionOnHashRing - peerPositionOnHashRing; - } - - return clockwiseDistance; - } - function calculateBidirectionalProximityOnHashRing( uint8 hashFunctionId, bytes calldata peerHash, diff --git a/contracts/v2/storage/ShardingTableStorage.sol b/contracts/v2/storage/ShardingTableStorage.sol index 809a4fca..6291cb38 100644 --- a/contracts/v2/storage/ShardingTableStorage.sol +++ b/contracts/v2/storage/ShardingTableStorage.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.16; import {HubDependent} from "../../v1/abstract/HubDependent.sol"; import {Named} from "../../v1/interface/Named.sol"; import {Versioned} from "../../v1/interface/Versioned.sol"; -import {ShardingTableStructs} from "../structs/ShardingTableStructs.sol"; +import {ShardingTableStructsV2} from "../structs/ShardingTableStructsV2.sol"; import {NULL} from "../../v1/constants/ShardingTableConstants.sol"; contract ShardingTableStorageV2 is Named, Versioned, HubDependent { @@ -16,7 +16,9 @@ contract ShardingTableStorageV2 is Named, Versioned, HubDependent { uint72 public nodesCount; // identityId => Node - mapping(uint72 => ShardingTableStructs.Node) internal nodes; + mapping(uint72 => ShardingTableStructsV2.Node) internal nodes; + // index => identityId + mapping(uint72 => uint72) internal identityIds; constructor(address hubAddress) HubDependent(hubAddress) { head = NULL; @@ -49,7 +51,7 @@ contract ShardingTableStorageV2 is Named, Versioned, HubDependent { uint72 nextIdentityId, uint72 index ) external onlyContracts { - nodes[identityId] = ShardingTableStructs.Node({ + nodes[identityId] = ShardingTableStructsV2.Node({ hashRingPosition: hashRingPosition, index: index, identityId: identityId, @@ -58,7 +60,7 @@ contract ShardingTableStorageV2 is Named, Versioned, HubDependent { }); } - function getNode(uint72 identityId) external view returns (ShardingTableStructs.Node memory) { + function getNode(uint72 identityId) external view returns (ShardingTableStructsV2.Node memory) { return nodes[identityId]; } @@ -86,13 +88,25 @@ contract ShardingTableStorageV2 is Named, Versioned, HubDependent { nodes[identityId].index -= 1; } + function getIdentityIdByIndex(uint72 index) external view returns (uint72) { + return identityIds[index]; + } + + function setIdentityId(uint72 index, uint72 identityId) external onlyContracts { + identityIds[index] = identityId; + } + + function getNodeByIndex(uint72 index) external view returns (ShardingTableStructsV2.Node memory) { + return nodes[identityIds[index]]; + } + function getMultipleNodes( uint72 firstIdentityId, uint16 nodesNumber - ) external view returns (ShardingTableStructs.Node[] memory) { - ShardingTableStructs.Node[] memory nodesPage = new ShardingTableStructs.Node[](nodesNumber); + ) external view returns (ShardingTableStructsV2.Node[] memory) { + ShardingTableStructsV2.Node[] memory nodesPage = new ShardingTableStructsV2.Node[](nodesNumber); - ShardingTableStructs.Node memory currentNode = nodes[firstIdentityId]; + ShardingTableStructsV2.Node memory currentNode = nodes[firstIdentityId]; for (uint256 i; i < nodesNumber; ) { nodesPage[i] = currentNode; currentNode = nodes[currentNode.nextIdentityId]; diff --git a/contracts/v2/structs/ShardingTableStructs.sol b/contracts/v2/structs/ShardingTableStructsV2.sol similarity index 83% rename from contracts/v2/structs/ShardingTableStructs.sol rename to contracts/v2/structs/ShardingTableStructsV2.sol index 20845946..7b8268b8 100644 --- a/contracts/v2/structs/ShardingTableStructs.sol +++ b/contracts/v2/structs/ShardingTableStructsV2.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.16; -library ShardingTableStructs { +library ShardingTableStructsV2 { struct NodeInfo { + uint256 hashRingPosition; bytes nodeId; uint72 identityId; uint96 ask;