Skip to content

Commit

Permalink
Merge pull request #16 from delta-mpc/identity
Browse files Browse the repository at this point in the history
Identity
  • Loading branch information
mh739025250 authored Nov 1, 2022
2 parents 3c8ef27 + 1f9d8c0 commit 1a34024
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 53 deletions.
2 changes: 1 addition & 1 deletion contracts/HFLContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ contract HFLContract {
bytes32 task_id = keccak256(
abi.encode(block.number, msg.sender, dataSet, commitment, taskType)
);
IdentityContract.Node memory node = idContract.getNodeInfo(msg.sender);
IdentityContract.NodeInfo memory node = idContract.getNodeInfo(msg.sender);
createdTasks[task_id] = Task({
creatorUrl: node.url,
creator: msg.sender,
Expand Down
2 changes: 1 addition & 1 deletion contracts/HLR.sol
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ contract HLR {
bytes32 task_id = keccak256(
abi.encode(block.number, msg.sender, dataSet, commitment, taskType)
);
IdentityContract.Node memory node = idContract.getNodeInfo(msg.sender);
IdentityContract.NodeInfo memory node = idContract.getNodeInfo(msg.sender);
createdTasks[task_id] = Task({
creatorUrl: node.url,
creator: msg.sender,
Expand Down
126 changes: 75 additions & 51 deletions contracts/IdentityContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@
pragma solidity >=0.7.0 <0.9.0;

contract IdentityContract {
uint256 constant aliveTimeout = 120;

struct Node {
address addr;
string url;
string name;
uint256 timeout;
}

struct NodeInfo {
address addr;
string url;
string name;
}

address private onwer;
mapping(address => Node) nodes;
address[] addrs;
mapping(address => uint256) addrs;
mapping(uint256 => Node) nodes;
uint256 count;

// event for EVM logging
event OwnerSet(address indexed oldOwner, address indexed newOwner);
Expand All @@ -22,19 +32,14 @@ contract IdentityContract {
// triggered when node leaved
event NodeLeaved(address addr, string url, string name);

modifier nodeNotExists(address addr) {
require(
bytes(nodes[addr].name).length == 0 &&
bytes(nodes[addr].url).length == 0,
"node has already joined in"
);
modifier nodeExists(address addr) {
require(addrs[addr] > 0, "node does not exist");
_;
}

modifier nodeExists(address addr) {
modifier nodeAlive(address addr) {
require(
bytes(nodes[addr].name).length > 0 &&
bytes(nodes[addr].url).length > 0,
addrs[addr] > 0 && nodes[addrs[addr]].timeout >= block.timestamp,
"node has not joined in"
);
_;
Expand All @@ -45,69 +50,88 @@ contract IdentityContract {
emit OwnerSet(address(0), onwer);
}

function join(string calldata url, string calldata name)
public
nodeNotExists(msg.sender)
{
nodes[msg.sender] = Node({addr: msg.sender, url: url, name: name});
addrs.push(msg.sender);
function join(string calldata url, string calldata name) public {
uint256 timeout = block.timestamp + aliveTimeout;
if (addrs[msg.sender] > 0) {
uint256 id = addrs[msg.sender];
nodes[id] = Node({
addr: msg.sender,
url: url,
name: name,
timeout: timeout
});
} else {
count++;
addrs[msg.sender] = count;
nodes[count] = Node({
addr: msg.sender,
url: url,
name: name,
timeout: timeout
});
}
emit NodeJoined(msg.sender, url, name);
}

function updateUrl(string calldata url) public nodeExists(msg.sender) {
nodes[msg.sender].url = url;
emit NodeUpdated(msg.sender, url, nodes[msg.sender].name);
function updateUrl(string calldata url) public nodeAlive(msg.sender) {
nodes[addrs[msg.sender]].url = url;
emit NodeUpdated(msg.sender, url, nodes[addrs[msg.sender]].name);
}

function updateName(string calldata name) public nodeExists(msg.sender) {
nodes[msg.sender].name = name;
emit NodeUpdated(msg.sender, nodes[msg.sender].url, name);
function updateName(string calldata name) public nodeAlive(msg.sender) {
nodes[addrs[msg.sender]].name = name;
emit NodeUpdated(msg.sender, nodes[addrs[msg.sender]].url, name);
}

function leave() public nodeExists(msg.sender) {
string memory url = nodes[msg.sender].url;
string memory name = nodes[msg.sender].name;
delete nodes[msg.sender];
uint256 removeIndex;
for (uint256 i = 0; i < addrs.length; i++) {
if (addrs[i] == msg.sender) {
removeIndex = i;
break;
}
}
for (uint256 i = removeIndex; i < addrs.length - 1; i++) {
addrs[i] = addrs[i + 1];
}
addrs.pop();
string memory url = nodes[addrs[msg.sender]].url;
string memory name = nodes[addrs[msg.sender]].name;
addrs[msg.sender] = 0;
emit NodeLeaved(msg.sender, url, name);
}

function getNodeInfo(address addr)
public
view
nodeExists(addr)
returns (Node memory node)
nodeAlive(addr)
returns (NodeInfo memory node)
{
node = nodes[addr];
node = NodeInfo({
addr: nodes[addrs[addr]].addr,
url: nodes[addrs[addr]].url,
name: nodes[addrs[addr]].name
});
}

function getNodes(uint256 page, uint256 pageSize)
public
view
returns (Node[] memory, uint256)
returns (NodeInfo[] memory, uint256)
{
uint256 offset = (page - 1) * pageSize;
if (offset < addrs.length) {
uint256 size = addrs.length - offset > pageSize
? pageSize
: addrs.length - offset;
Node[] memory result = new Node[](size);
for (uint256 i = 0; i < size; i++) {
result[i] = nodes[addrs[i]];
uint256 size = 0;
uint256 aliveCount = 0;
uint256[] memory ids = new uint256[](pageSize);
for (uint256 i = 1; i <= count; i++) {
if (
nodes[i].timeout >= block.timestamp && addrs[nodes[i].addr] > 0
) {
aliveCount++;
if (aliveCount > offset && size < pageSize) {
ids[size] = addrs[nodes[i].addr];
size++;
}
}
return (result, addrs.length);
} else {
return (new Node[](0), addrs.length);
}

NodeInfo[] memory res = new NodeInfo[](size);
for (uint256 i = 0; i < size; i++) {
res[i] = NodeInfo({
addr: nodes[ids[i]].addr,
url: nodes[ids[i]].url,
name: nodes[ids[i]].name
});
}
return (res, aliveCount);
}
}
117 changes: 117 additions & 0 deletions test/test_identity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const identity = artifacts.require("IdentityContract");
const chaiAsPromised = require("chai-as-promised");
const chai = require("chai");

chai.use(chaiAsPromised);
const assert = chai.assert;

contract("Identity", (accounts) => {
const address1 = accounts[0];
const name1 = "node1";
const url1 = "http://127.0.0.1:6700";

const address2 = accounts[1];
const name2 = "node2";
const url2 = "http://127.0.0.1:6800";

it("join", async () => {
const identityInstance = await identity.deployed();
const res1 = await identityInstance.join(url1, name1, { from: address1 });
assert.strictEqual(res1.logs[0].args[0], address1);
assert.strictEqual(res1.logs[0].args[1], url1);
assert.strictEqual(res1.logs[0].args[2], name1);

const res2 = await identityInstance.join(url2, name2, { from: address2 });
assert.strictEqual(res2.logs[0].args[0], address2);
assert.strictEqual(res2.logs[0].args[1], url2);
assert.strictEqual(res2.logs[0].args[2], name2);
})

const newName1 = "node11";
const newUrl1 = "http://127.0.0.1:6701";
it("update name and url", async () => {
const identityInstance = await identity.deployed();
const res1 = await identityInstance.updateName(newName1, { from: address1 });
assert.strictEqual(res1.logs[0].args[0], address1);
assert.strictEqual(res1.logs[0].args[1], url1);
assert.strictEqual(res1.logs[0].args[2], newName1);

const res2 = await identityInstance.updateUrl(newUrl1, { from: address1 });
assert.strictEqual(res2.logs[0].args[0], address1);
assert.strictEqual(res2.logs[0].args[1], newUrl1);
assert.strictEqual(res2.logs[0].args[2], newName1);
})

it("get node info", async () => {
const identityInstance = await identity.deployed();
const node1 = await identityInstance.getNodeInfo.call(address1);
assert.strictEqual(node1.addr, address1);
assert.strictEqual(node1.url, newUrl1);
assert.strictEqual(node1.name, newName1);

const node2 = await identityInstance.getNodeInfo.call(address2);
assert.strictEqual(node2.addr, address2);
assert.strictEqual(node2.url, url2);
assert.strictEqual(node2.name, name2);
})

it("get nodes", async () => {
const identityInstance = await identity.deployed();
const res = await identityInstance.getNodes.call(1, 20);
const nodes = res[0];
const count = res[1];
assert.strictEqual(count.toNumber(), 2);
assert.lengthOf(nodes, 2);

assert.strictEqual(nodes[0].addr, address1);
assert.strictEqual(nodes[0].url, newUrl1);
assert.strictEqual(nodes[0].name, newName1);
assert.strictEqual(nodes[1].addr, address2);
assert.strictEqual(nodes[1].url, url2);
assert.strictEqual(nodes[1].name, name2);
})

it("join again", async () => {
const identityInstance = await identity.deployed();
const res1 = await identityInstance.join(newUrl1, newName1, { from: address1 });
assert.strictEqual(res1.logs[0].args[0], address1);
assert.strictEqual(res1.logs[0].args[1], newUrl1);
assert.strictEqual(res1.logs[0].args[2], newName1);

const res2 = await identityInstance.join(url2, name2, { from: address2 });
assert.strictEqual(res2.logs[0].args[0], address2);
assert.strictEqual(res2.logs[0].args[1], url2);
assert.strictEqual(res2.logs[0].args[2], name2);
})

it("leave node1", async () => {
const identityInstance = await identity.deployed();
const res = await identityInstance.leave({ from: address1 });
assert.strictEqual(res.logs[0].args[0], address1);
assert.strictEqual(res.logs[0].args[1], newUrl1);
assert.strictEqual(res.logs[0].args[2], newName1);
})

it("get node info after node1's leaving", async () => {
const identityInstance = await identity.deployed();
assert.isRejected(identityInstance.getNodeInfo.call(address1));

const node2 = await identityInstance.getNodeInfo.call(address2);
assert.strictEqual(node2.addr, address2);
assert.strictEqual(node2.url, url2);
assert.strictEqual(node2.name, name2);
})

it("get nodes after node1's leaving", async () => {
const identityInstance = await identity.deployed();
const res = await identityInstance.getNodes.call(1, 20);
const nodes = res[0];
const count = res[1];
assert.strictEqual(count.toNumber(), 1);
assert.lengthOf(nodes, 1);

assert.strictEqual(nodes[0].addr, address2);
assert.strictEqual(nodes[0].url, url2);
assert.strictEqual(nodes[0].name, name2);
})
})

0 comments on commit 1a34024

Please sign in to comment.