---
# System prepended metadata

title: Rings

---

# 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)
- 