[![github license](https://img.shields.io/badge/license-LGPLv3-blue.svg)](https://www.gnu.org/licenses/lgpl-3.0.en.html) -------------------------------------------------------------------------------- [中文版](./README_CN.md) ## Overview Rosetta-IO is a building block of Rosetta, providing IO service for Rosetta. Once the channel in Rosetta-IO is created, it is available to send/receive messages from other nodes. In Rosetta-IO, `NODE` identified by `NODE ID`, is a endpoint of a TCP connection. Each node has unique `(HOST, PORT)` tuple where `HOST` is a `IP ADDRESS` or `DOMAIN NAME` and `PORT` is a `TCP LISTENING PORT`. Rosetta-IO supports `MULTI DATA SOURCE`. It defines three roles, called `DATA ROLE`, `COMPUTATION ROLE` and `RESULT ROLE`. `DATA ROLE` denotes that inputing data/module from the node is legal. Nodes, owning `COMPUTATION ROLE`, can participate in `PRIVACY COMPUTATION`. The results of `PRIVACY COMPUTATION` can only be stored on nodes with `RESULT ROLE`. Each node can have one or more roles. Rosetta-IO establishes network topoloy according to the roles of nodes. Three subnetworks, namely `INPUT NETWORK`, `COMPUTATION NETWORK` and `OUTPUT NETWORK`, will be built. `INPUT NETWORK` consists of nodes owning `DATA ROLE` and/or `COMPUTATION ROLE`. All of the nodes in `COMPUTATION NETWORK` have `COMPUTATION ROLE`. Nodes with `COMPUTATION ROLE` and nodes with `RESULT_ROLE` establish `OUTPUT NETWORK` together. Rosetta-IO supports `MULTI TASKING`. The term `CHANNEL` refers to a task level handler. Every interface provided is based on a specific task. In Rosetta-IO, the connection between any two nodes is reused inter-task and there is only one connection between any two nodes. ## Compile & Install Follow the steps below to compile and install Rosetta-IO ```bash $ git clone --recurse https://github.com/LatticeX-Foundation/Rosetta-IO.git $ cd Rosetta-IO $ export install_path=~/.local/rosetta-io $ mkdir -p build && cd build $ cmake ../ -DCMAKE_INSTALL_PREFIX=${install_path} $ core_num=$(nproc) $ make -j${core_num} && make install ``` ### Example Here we give a example to demostrate how to use Rosetta-IO. Support three parties, called P0, P1 and P2, need to compare their config file on network topology. They may write the following program to finish this task.(check_config_json.cpp) ```cpp #include #include #include #include #include #include #include #include using namespace std; int main(int argc, char* argv[]) { if (argc != 3) { printf("argc != 3\n"); return -1; } const char* file_name = argv[1]; const char* node_id = argv[2]; string config_str = ""; char buf[1024]; FILE* fp = fopen(file_name, "r"); if (fp == nullptr) { printf("open file %s error", file_name); return -1; } while (fgets(buf, sizeof(buf), fp) != nullptr) { config_str += string(buf); } fclose(fp); printf("config:%s", config_str.c_str()); IChannel* channel = ::CreateInternalChannel("test", node_id, config_str.c_str(), nullptr); vector connected_nodes = ::decode_vector(channel->GetConnectedNodeIDs()); int config_str_size = config_str.size(); const char* data_id = "config str"; for (int i = 0; i < connected_nodes.size(); i++) { channel->Send(connected_nodes[i].c_str(), data_id, (const char*)&config_str_size, sizeof(int)); channel->Send(connected_nodes[i].c_str(), data_id, config_str.data(), config_str_size); printf("send data to %s\n", connected_nodes[i].c_str()); } for (int i = 0; i < connected_nodes.size(); i++) { int data_size = 0; channel->Recv(connected_nodes[i].c_str(), data_id, (char*)&data_size, sizeof(int)); string data(data_size, 0); channel->Recv(connected_nodes[i].c_str(), data_id, &data[0], data_size); printf("recv data from %s, size:%d\n", connected_nodes[i].c_str(), data_size); } ::DestroyInternalChannel(channel); return 0; } ``` P0 and P1 use the following config file, named p0p1.json. ```json { "NODE_INFO": [ { "NAME": "PartyA(P0)", "HOST": "127.0.0.1", "PORT": 11121, "NODE_ID": "P0" }, { "NAME": "PartyB(P1)", "HOST": "127.0.0.1", "PORT": 12144, "NODE_ID": "P1" }, { "NAME": "PartyC(P2)", "HOST": "127.0.0.1", "PORT": 13169, "NODE_ID": "P2" } ], "DATA_NODES": [ "P0", "P1", "P2" ], "COMPUTATION_NODES": { "P0": 0, "P1": 1, "P2": 2 }, "RESULT_NODES": [ "P0", "P1", "P2" ] } ``` P2 uses the follow config file, named p2.config. ```json { "NODE_INFO": [ { "NAME": "PartyA(P0)", "HOST": "127.0.0.1", "PORT": 11121, "NODE_ID": "P0" }, { "NAME": "PartyB(P1)", "HOST": "127.0.0.1", "PORT": 12144, "NODE_ID": "P1" }, { "NAME": "(P2)", "HOST": "127.0.0.1", "PORT": 13169, "NODE_ID": "P2" } ], "DATA_NODES": [ "P0", "P1", "P2" ], "COMPUTATION_NODES": { "P0": 0, "P1": 1, "P2": 2 }, "RESULT_NODES": [ "P0", "P1", "P2" ] } ``` The only difference between the two config files is that `NAME` of P2 in p0p1.json is `PartyC(P2)` while `NAME` of P2 in p2.json is `(P2)`. The three parties follow the steps below to install rosetta-io and generate program `check_config_json`. ```bash #install_path $ git clone --recurse https://github.com/LatticeX-Foundation/Rosetta-IO.git $ cd Rosetta-IO $ mkdir -p build $ cd build $ export install_path=~/.local/rosetta-io $ cmake ../ -DCMAKE_INSTALL_PREFIX=${install_path} $ core_num=$(nproc) $ make -j${core_num} && make install $ cd ../example $ g++ check_config_json.cpp -o check_config_json -I${install_path}/include -L${install_path}/lib -lio -Wl,-rpath=${install_path}/lib ``` Next, the three parties start their program respectively. Here is what P0 does. ```bash $ ./check_config_json p0p1.json P0 ``` Here is what P1 does. ```bash $ ./check_config_json p0p1.json P1 ``` Here is what P2 does. ```bash $ ./check_config_json p2.json P2 ``` The three parties get different results from their console terminals. Here is what P0 gets. ```bash send data to P1 send data to P2 recv data from P1, size:716 recv data from P2, size:710 ``` Here is what P1 gets. ```bash send data to P0 send data to P2 recv data from P0, size:716 recv data from P2, size:710 ``` Here is what P2 gets ```bash send data to P0 send data to P1 recv data from P0, size:716 recv data from P1, size:716 ``` ## Document List * [Rosetta-IO User API](./doc/API_DOC.md)