# Rings ## Abstract / Problem Statement ## Ring specification / pseudo code ```solidity contract RingLogs is CircularBufferUint { // update: store records, not Logs for single-writer-logs (see string) // /// Ring log checkpoint frequency uint256 const CHECKPOINT_FREQUENCY = 100; /// CID prefix bytes cidPrefix; /// Heads of the single-writer log nodes of the members. mapping(address /* member */ => bytes32 /* cid */) logNodeHeads; /// Head of log node associated with the "multi-writer consensus of the ring" bytes32 ringNodeHead; /// Store the CHECKPOINT_FREQUENCY most recent ring logs, /// and archive afterwards each checkpoint at said frequency. mapping(uint256 /* entry */ => bytes32) ringLogs; func } ``` ```solidity contract Ring is RingLogs { // Storage /// Engine owning the ring. address owner; /// The ring's majority numerator. uint256 const RING_MAJORITY_NUMERATOR = uint256(2); /// The ring's majority denominator. uint256 const RING_MAJORITY_DENOMINATOR = uint256(3); /// The ring's member count. uint256 memberCount; /// Sentinel pointer for marking start and end of the ring's members in the linked-list. const address SENTINEL_MEMBERS = address(0x1); /// Linked list of nodes. mapping(address => address) members; /// (Optional) public multiaddresses of members. mapping(address => string) publicMultiaddresses; /// (Optional) peerId // PeerId based (for now) on avatar public key; check pubkey -> address mapping(address => bytes32 /* PeerId */) peerIds; // Special Functions constructor() public { owner = msg.sender; } // External Functions function enter(address _member) external onlyOwner; function exit(address _member) external onlyOwner; function registerOutputs( Gate _gate, uint96[] _pins, bytes32[] _cid, bytes32[] _r, bytes32[] _s, uint8[] _v ) { // requires majority tallyVote(..); uint256[] tokenIds = scope.declareData(cid[], ConstantData); _gate.output(_pins, tokenIds); } // Private Functions /// Adds the given member to the linked list of members. function addMember(address _newNode) private {} } ``` ## Services built on Rings ### Replica-rings (Figure out how to) share the replica keys / service keys; the ring members hold the logs of other nodes available without being able to read them over a period of time ### Swarm / DHT and/or STUN/TURN-rings for nodes providing STUN/TURN services to connect edge devices behind NAT routers. Questions: - Swarm discovery services can aid Peer discovery? (even for public accessible nodes?) - should we aim to support one global DHT across IPFS and all Mosaic; or cluster per app? ## Think about next after break - compound actions / flush to ring contract - whats in the records - what s the definition the code: WASM, docker process, ... native; adopt existing framework - no measuring (gas consumption) - capture non-determinism in the ringWriter contract logic - (?) ring definition - (?) messages / transactions / actions (?) - messages, CBOR encoded can be passed to the application layer? ## Examples - chat example - group of chat participants have a ring - `message{txt:string}`` - find contacts by username/profile - contact tracing - which rings exist? - Map and reduce rings - API (JSONRPC) ring for client-server from webbrowser to - (?) push "Compound action" - (?) graphQL - replica-ring - the records of a replica ring contain the rings and their references to their records - as client, make http request (received in application http-server) ``` { method: "ReplicateRing", params: { ring: 0xabc..def, replica_ring: 0xabc..dee, replica_key: xhjadndf..ldkfjsldk, mtx: acd..aa2, // should register ring in replica-ring (and pay replica-ring) } } ``` - as client, make http request "FlushToRing" + Payload what do I do in response as a replica node: 1. verify Payload (done in application layer) ``` { method: `FlushToRing`, params: { avatar: 0xeed..223, ring: 0xec2..a11, // same as msg_domsep? mtx: acb..2fa, mtx_sig: rsv, logNodes: [ser_logNode12, ser_logNode11] } } } ``` some validations: 1. do I have the replica key for client-ring ? 1. ecrecover(mtx, mtx_sig) = avatar 1. ring.isMember(avatar) 1. deserialise $logNode_i$, and check connected-ancestry and well-connected - error response "log replication incomplete" 1. write message to next log(from app>mosaic), so that it will get passed to other nodes ``` message { application_domsep: msg_domsep: `GlobalAddressRing`, type: `FlushToRing`, status : `received`, // "hi! I will do it" payload: { avatar: 0xeed..223, ring: 0xec2..a11, // same as msg_domsep? mtx: acb..2fa, mtx_sig: rsv, logNodes: [ser_logNode12, ser_logNode11] } } ``` 1. execute payload (ie. relay metatx) ``` message { type: `` msg_hash: bababa..ba, status: relayed, // "Hi! I ve done it!" payload: { tx: ".." txfee: .. } } ``` - Mosaic should see updates of heads of logs flushed to rings; and be able to see registered replica-rings, and get back logs, and replay messages to application - Wallet - Contacts/chat - IPDR-ring, docker hub on Mosaic - git on rings - music/media - photos - Maps (traffic, updates to, non-mapped terrain) - Route finding - Pepo / Decrypt / Tolkin / other Ost projects ## Scribbles @ben - situation / edge case: PeerId forks their own log nodes; logNode2 and logNode2' hence, rings: you have had consensus on what is the head of the logs because `CompoundAction := {metatx; logNode}`; - PeerId is created with `opts.keyType = 'secp256k1'`, and derived from Avatar public key; Model: one avatar per epoch/session - (?) STUN/TURN hole-punching; who is this public IP address? establish a bridge over a bridge server; 1. QR scanning 2. over PeerIds? ## Scribbles @kevin ### Rings * New way to do computation, cf w/ smart contract * Orchestration done via a smart contract * Execution of contracts happens on Ethereum (GoEth) * I/O (reading/writing) happens over IPFS[1] * Mosaic Node(s) do computation * Append only -- only ever writing data * 2x static keys: Replica (service) key and read key * Each member has a single writer log / not shared * A thread = one or more single writer logs with shared read key, ... * Say 5 nodes, same input, write results * As an outsider what's the correct answer? * Ring = contract w/ one thread. * Each member has it's own single writer log. * Ring ---> logic for resolving collection decision / outcome. * Application rings * Rings that do different steps e.g. segmentation of data, what today's interaction graph looks like? For contact tracing app, incorporate today's positive self-attestations. [1] Textile -- project on top of IPFS, structured more usable data. Threads db. ## Questions / knowledge base / short answers - What are reasons of having redundancy in rings? - make data and computation more available - have either consensus or consistency or merge of repeated computations - reduce availability requirement of nodes (push computation out to edge devices) ## Landscape Mosaic is a "operating system" (despite objections to the use of this term) iExec, Ocean (and golem) are marketplaces matching compute resources; not intended to run applications ## random references - peerID https://github.com/libp2p/js-peer-id - libp2p NAT traversal https://docs.libp2p.io/concepts/nat/ - as a reminder JSONRPC 2.0 https://www.jsonrpc.org/specification - IPDR InterPlanetary Docker Registry https://github.com/miguelmota/ipdr - Kubernetes go-client for managing different processes https://github.com/kubernetes/client-go - [Sabotage-Tolerance Mechanisms for Volunteer Computing Systems](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.67.2962&rep=rep1&type=pdf) - HPX C++ standard library for parrallisation http://hpx.stellar-group.org/ https://github.com/STEllAR-GROUP/hpx https://www.youtube.com/watch?v=js-e8xAMd1s - HPX task based programming model in global address space http://stellar.cct.lsu.edu/pubs/pgas14.pdf - [Towards Massive Parallelism (aka Heterogeneous Devices/Accelerator/GPGPU) support in C++ with HPX](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0234r0.pdf) -