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