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:
Other native processes are reached indirectly through these. For instance,
Design Considerations
Describe the issues which need to be addressed or resolved before attempting to devise a complete design.
@"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.Work for this specification is captured in:
A resolver takes a string and returns a process. Examples of resolvers include
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.
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 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.
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
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.
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.
Max File Size - Not going to implement controls as yet.
Error Conditions:
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:
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.
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.
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.
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.
Could include software or hardware, Operating systems and platforms, User Personas, Changes in functionality.
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:
This section should provide a high level overview of how the functionality and responsibilities of the the system were partitioned and then assigned to subsystems or components. The main purpose here is to gain a general understanding of how and why the system was decomposed, and how the individual parts work together to provide the desired functionality. If there are diagrams, models, flowcharts, or documented scenarios. This applies only to the scope of the document, not the entire system.