Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

THIS PAGE IS WORK IN PROGRESS, PLEASE DO NOT COMMENT ON IT UNTIL I REMOVE THIS BANNER

Summary:
The purpose of ListenForDataAtName API is to provide API to RChain data pointed to by Rholang names of the deployed and proposed contracts that are finalized.

This is a developer-level API that does not impact the state of the blockchain and thus we should complicate our approach by trying to build in some payment tooling. Instead, I propose we simplify the solution to just the rnode updates needed to deliver the data.

The purpose of this page is to highlight how developers would like to get data from RChain and use it in their app. There is currently a gRPC API that developers can use called listenForDataAtName that most agree is close to what developers want. With this page, I hope to capture the developer requirements as well as the proposed design to deliver this feature.

...

  1. Client deploys rholang to a validator node. This is a signed message, and the signature represents the `DeployID`
  2. Send this data to something that is listening for these updates

Specifically, I am leaving off any discussion of additional servers related to aggregating and distributing results from listenToDataAtName and focussing only on the API that rnode will expose to allow developers to listenForDataAtName.  It does not preclude someone from building additional infrastructure to do this, but I feel it is out of scope for this team to deliver that. Second, there was a discussion of who would "pay" for the execution of listenForDataAtName.  This is a developer-level API that does not impact the state of the blockchain and thus we should complicate our approach by trying to build in some payment tooling. Instead, I propose we simplify the solution to just the rnode updates needed to deliver the data.

Changes to rnode/rspace

For the most part, the following three proposals from Dom, Artur and Chris follow a similar pattern.

Dom's Proposal

  1. Client figures out the unforgeable name that they are interests in. (More on that below)
  2. Client requests to get a report from an observer node on all updates to names, matches, and continuations and filters the results to only those names for which it is interested.

What unforgeable name?

One of the challenges in getting updates from RChain is that on-chain all Rholang names are represented as an unforgeable name using the output of a hash. This unforgeable name is determined algorithmically such that other validators derive the same hash and can confirm that the merkle root representing the state of RSpace is valid.  But the actual unforgeable names, (other than those in the top level new), cannot be known until the Rholang is actually executed. This presents a challenge to any code that desires to watch certain unforgeable names to see when they have been updated.

Currently, most code that desires to listen for data is only interested in listening to names that are at the top level of the Rholang code, and thus the unforgeable names can be calculated using the algorithm used by the validators. This means a client can deploy Rholang, then call a method to get all updates for these names that can be calculated.  For names that are nested deeper in the code, there are currently no simple mechanisms for easily determining the unforgeable names.

The approach we are proposing here is to instrument the deployed Rholang to write unforgeable names that need to be listened on to the DeployID channel.

Code Block
languagescala
titleSample with instrumented code
new _nameToListenOn, deployId(`rho:deploy:id`) in {
  _nameToListenOn!(0) |
         
  contract MyContract(@"hello", @name) = {
    for (@value <- _nameToListenOn) {
          // Do something with _nameToListenOn |
    } |
    
  // send the interesting channels down an easily accessible channel thx to deployId
  deployId!(("NAME_TO_LISTEN_ON", *_nameToListenOn))
} |
 

Changes to rnode/rspace

Assumptions:

  • we are able to pick a data scraping solution that will be good enough to attach a data aggregation solution (e.g. kafka, elastic search, etc)
  • this data scraping solution does not need to be "always on-line" as it can rely on an observer node
  • we are able to propagate information of processed and finalized blocks (as viewed by a node)
  • we are able to propagate information on deployid - block mapping

...

It could be viewed as continuing work on listenForDataAtName with the difference of not having any special entities in the system to allow data extraction.

In the end it's all deploys and deployid we already have.

Artur's proposal (from discord)

Let's say you're deploying a contract, and want to know some of its internal channels for future auditability:

Code Block
languagescala
titleSample code exposing names
linenumberstrue
new MyContract, rs(`rho:registry:insertSigned:secp256k1`), uriOut, rl(`rho:registry:lookup`) in {
  
  new _callCount, _log, deployId(`rho:deploy:id`) in {
  
      _callCount!(0) |
       
      contract _log(discard) = { Nil } |
  
      contract MyContract(@"hello", @name) = {
        _log!(("Starting a greeting for ", name)) |
        for (@count <- _callCount) {
          _callCount!(count + 1) |
        }
        // perform a proper greeting
        // ...
      }
    } |
    
    // send the interesting channels down an easily accessible channel thx to deployId
    deployId!(("LOG", *_log)) |
    deployId!(("CALL_COUNT", *_callCount)) 
  } |
  

  rs!(
    "04c71f6c7b87edf4bec14f16f715ee49c6fea918549abdf06c734d384b60ba922990317cc4bf68da8c85b455a65595cf7007f1e54bfd6be26ffee53d1ea6d7406b".hexToBytes(),
    (9223372036854775807, bundle+{*MyContract}),
    "3045022100aa2bbdd706e157efb6df78156f1520c6422ff651728ccff69d5bffbf901767eb0220799a0451c72c284b1da128f0e4031125dbed9ac8b9de6ce5b0e4d35562ade877".hexToBytes(),
    *uriOut
  )
}

...

Code Block
languagescala
titleshow-deploy
linenumberstrue
//rnode show-deploy X
//should print JSON of the follwoing structure:
{
"deployId": "X",
"nameUpdates": {
    "`rho:deploy:id:X`" : [["put", "(\"LOG\", \"`rho:unforgable:HASH_FOR_LOG`\")"], ["put", "(\"CALL_COUNT\", \"`rho:unforgable:HASH_FOR_CALL_COUNT`\")"]]
   ... //including: the initial send of '0' to _callCount
  }
}

Pros:

  • Can listen to any name that is instrumented in the deploy

Cons:

  • Requires instrumenting code that is deployed to output the unforgeable names that you plan to listen on

Chris's proposal

Chris's proposal is a slight variation on Artur's proposal in that you don't instrument the original deployed code in any way. Instead, you just call a method the dumps the known names. Such as:

Code Block
languagescala
titledump_map
dump_map(deployid) = returns something like =>
{
   "nameMap": [
   { "rhoterm":"foo","unforgeable":"bf12fe78ab84cd143412fe78ab84cd14", "line":4, "column":22 },
   { "rhoterm":"bar","unforgeable":"ac84cd143412fe78abf12f2fe8a4cdcd", "line":8, "column":18 }
  ]
}

Pros:

  • Nothing special needs to be done when deploying code to later use listenForDataAtName

Cons:

...