Node Powerbox


Introduction

Purpose:

Rholang's design requires that messages be sent on a channel.  The Powerbox's purpose is to create system channels and expose them to Rholang, so that the resources of the system are available to the Rholang contracts.  

The Powerbox is a piece of the RChain node that serves as an abstraction layer between the physical system resources on the node and the Rholang language.  It will create the system channels that Rholang contracts will send messages along.  It also delegates authority via Object Capabilities to system contracts and other components on the RChain Node.  When an RChain Node is started up, the powerbox is instantiated in Scala and contains sub-objects for Disk IO, Network, Console, etc.  It also acts as a client of the tuplespace,  by creating a process that sits and listens at a channel for 'method calls'.  

References:

Object Capability ("OCaps") Security Model:

The Powerbox Pattern:

Storage .02 Specification: (deprecated) RSpace 0.2 Specification (Not ready yet)

Rholang FFI: Rholang Foreign Function Interface - WIP

Definitions:

Channel - A key in the tuplespace

Scope

Features here are scoped to the Mercury release.  Detailed release vehicles will be described in tickets under "Traceability Matrix"  


Use Cases

  • The Casper system contract requires the ability to send messages across the network so that nodes can achieve consensus. 
  • The RChain core development team needs for the node system to accept a local configuration file as part of the system contracts.
  • The system contracts require access to cryptographic libraries on the system (Also requires Rholang FFI)
  • The Node Operator will want to know if the hardware configuration is insufficient to serve as a full validator due to system hardware requirements 


The powerbox is injected into system contracts, and the system contracts call the powerbox system.  The process listening on system expects a method name and some arguments, like system!("print", "Hello, World!", ack).  The process listening on system could be written in Rholang if we want; it's only doing message dispatch based on the method name.  One of the arguments is usually a return channel on which are passed channels where various native processes are listening.  Some of these native processes include:

  • A process that returns a channel for talking to the file process STDERR
  • A process that returns a channel for talking to a filesystem resolver 
  • A process that returns a channel for talking to an HTTP URL resolver
  • A process that returns a channel for talking to a TCP/IP resolver
  • A process that returns a channel for talking to a UDP resolver
  • A process that takes a binary jar process and the name of a class to load and returns a channel on which to talk to the class

Other native processes are reached indirectly through these.  For instance,

  • Resolvers take a string path and return a channel to communicate with a process representing the resulting content. 
    • For example, the filesystem resolver takes a path and returns a channel over which to talk to a file process.  The file process has methods like seek, read, write, etc, where read for example returns a "list of bytes" process.
    • The TCP/IP resolver takes an IP address and returns a channel over which to talk to a socket process.  The socket process has methods for sending & receiving data.

Design Considerations

Describe the issues which need to be addressed or resolved before attempting to devise a complete design.

  • This depends on the ability to support native processes in the tuplespace because all continuations are stored in the tuplespace, and this is how Rholang interacts with the system. 
  • To be an ocaps platform, it's imperative that we do not automatically grant access to the system channel to all contracts. Until we've figured out how to inject the system channel, @"system" is a public name on which we can access it, in much the same way that V8 exposes authority in the global namespace.  We don't have contracts on the blockchain right now, so this isn't a big problem.  In the future system will become a private name that gets injected into system contracts and contracts on the blockchain will not be able to cause side-effects directly.
  • In some fashion, the Node will need to be informed of how much of the base system resources it has access to. 
  • The private names have to be cryptographically secure.  This is to prevent anyone from attempting to guess the names.

Traceability Matrix

Work for this specification is captured in: 


Resolvers

A resolver takes a string and returns a process.  Examples of resolvers include

  • directories in a file system, where the string is a path and the returned process represents a file or directory
  • an HTTP client, where the string is a URL and the returned process is the content (the mime type determines what kind of content)
  • a TCP client, where the string is a port to bind to; the resulting process is a resolver where the string is the IP address and port to connect to, etc.

Resolvers may be synchronous or asynchronous; an asynchronous resolver must also take a return channel for the resulting process to be returned on.  Asynchronous resolvers may take an error channel as well.


System Process - (see above) - This is the system channel that is exposed to Rholang.  The System channel contract will be authored in Rholang as a method that ushers a request out of Rholang.

Synchronous Interface

Any synchronous code may be exposed as a process with methods.  Method invocations must not occur until the invocation is at the top level.  Method invocation is eager.  Methods must not block.  Invoking a method will unmarshal the arguments, invoke a method on the object, and marshal the result; the result will be marshaled and will effectively replace the original invocation expression in the term.

Asynchronous Interface

Asynchronous code must be exposed either as a method that schedules an asynchronous side effect and immediately returns Nil, or as a native process listening on a channel.  When the asynchronous operation is complete, the native callbacks may marshal any results and use a produce() call to send them back to Rholang code on some channel.

Dispatcher

The system needs to marshal the right continuations to the right process that can run the continuation.  The tuplespace will have a mechanism to 'label' continuations such that the continuations can be returned to the process that knows how to run them.  The dispatcher gets continuations from the tuplespace based on the label and either runs them, or returns them to the process that created them, so they can be run.  Henry Till Please confirm /clarify

Hardware Interface

Http Resolver, TCP/IP Resolver / UDP:

The resolver consumes a well formed url and returns back a channel on which requests can be sent to the http resource and responses can be received.   

  • If an error code is returned, the error is returned to the STDERR channel.

File Resolver:

The file resolver is something that is used by the RChain Dev team to prepare the node for exposing the local file system to System Contracts.  This will be an infrequent operation.  Additionally, if a Node Operator wishes to expose an application via a Jar file (Oracle) to Rholang, they can do so via the File Resolver.  

  1. Consumes a string which is a path to a directory /  location on the local system to be used by the file I/O channel.
  2. Nodes will need to allocate some amount of file system for use by the file I/O channel.
  3. Provides some information back on the amount of disk space available for use by the I/O channel?
  4. Binary JAR files -
    1. Will need an argument to include the class to expose to the FFI

Max File Size - Not going to implement controls as yet.

Error Conditions:

  • I/O Errors:
    • Unable to write - 
      • the file operation is rolled back, and that node won't be able to execute the system contract -and by extension any other contracts.
        • Node falls out of the validator set, does not lose stake.
      • Error sent to the STDERR channel
    • Unable to read -
      • The process retries 2X and then sends an error to the STDERR Channel
  • File type Errors: Binary executable files will not be supported.
    • Resolver returns an error to the STDERR channel.

Software & User Interface

The powerbox process will be injected into every Rholang system contract as its first argument.  The powerbox process will have some methods similar to the following:

  • fileSystem(): Directory (subclass of Resolver)
  • httpClient(): Resolver
  • stdout(): File
  • stdin(): File
  • stderr(): File
  • tcpClient(): Resolver
  • load(jar: File, className: String): Process
  • etc.

The load() method takes a File process and a class name and returns the corresponding marshaled class object.  Since there is no way for the loader to know whether the code is synchronous or asynchronous, the marshaled class object should expose both synchronous and asynchronous interfaces.  Given a Java method of the form

    ReturnType methodName(T1 arg1, T2 arg2, ..., Tn argn)

the FFI should expose a synchronous method of the same signature and a method methodNameAsync() that takes a return channel in the first position and the rest of the arguments afterwards.


System Overview

Tuplespace & Storage  Layer

Rholang channels are represented in the tuplespace by a key value in the database and are accessed by the Consume and Produce functions..  In essence, this is how Rholang channels are created physically on the system.  For system processes, a set of special channels will be created in the tuplespace for system processes.  

All interaction with other processes, whether they be Rholang processes or native code, happens through the tuplespace.  The VM / interpreter is the main client of the tuplespace: the interpretation of

    x!(Q)

is that the code of the process Q is stored at the key x, while the interpretation of

    for (y <- x) { P }

is that the continuation

    (y) => P

is stored at the key x, where P is Rholang code.

There are other clients, however.  In order to cause any side effects on the computer, it is necessary for the node to store continuations as well, but the continuations are usually compiled Scala code that unmarshals Rholang data into Scala data and processes it.  This Scala code can print to the console or send messages over the network, or write to a file, etc.  When the operation is complete, the Scala code can then marshal the result and send it on a channel.

Network/File System / Console

This component receives the request from the tuplespace, (optional: checks it against a set of criteria) and then fulfills the request.  If the request fails (optional: to meet criteria), a meaningful message is sent to the STDERR channel via the tuplespace.  

Interpreter Updates:

  • Kyle Butt: Need to implement support for native processes in the interpreter for the time being. There isn't any way to have system processes in the system.  Ambient Authority to print on a public name. 

Limitations

There is currently (2018-03-14) no way to declare methods, but we can expose methods on processes that represent class objects or instance objects.

Assumptions and Dependencies

Architectural Strategies

Describe any design decisions and/or strategies that affect the overall organization of the system and its higher-level structures. These strategies should provide insight into the key abstractions and mechanisms used in the system architecture. Describe the reasoning employed for each decision and/or strategy (possibly referring to previously stated design goals and principles) and how any design goals or priorities were balanced or traded-off. Such decisions might concern (but are not limited to) things like the following:

  • Use of a particular type of product (programming language, database, library, etc. ...)
  • Reuse of existing software components to implement various parts/features of the system
  • Future plans for extending or enhancing the software
  • User interface paradigms (or system input and output models)
  • Hardware and/or software interface paradigms
  • Error detection and recovery
  • Memory management policies
  • External databases and/or data storage management and persistence
  • Distributed data or control over a network
  • Generalized approaches to control
  • Concurrency and synchronization
  • Communication mechanisms
  • Management of other resources


System Architecture