Skip to content
Ishinka edited this page Aug 10, 2022 · 3 revisions

This component contains known RPC sections and their methods that are available for Remote Calls to the node by default. Currently not all of them are implemented.

Also this component provides tools for defining such a section. These tools help to generate code for calling RPC methods or subscribing to them. This approach reduces the boilerplate code.

Known Sections and their Methods

The Rpc interface represents known sections. Each one of them contains proper RPC methods and subscriptions. Sections that are not included in this interface can be defined manually.

Define a Section

For all interfaces annotated with RpcInterface the processor will generate the appropriate implementation.

Example of a section:

@RpcInterface("chain")
public interface Chain {
    @RpcCall("getFinalizedHead")
    @Scale
    CompletableFuture<BlockHash> getFinalizedHead();

    @RpcSubscription(type = "newHead", subscribeMethod = "subscribeNewHead", unsubscribeMethod = "unsubscribeNewHead")
    CompletableFuture<Supplier<CompletableFuture<Boolean>>> subscribeNewHeads(BiConsumer<Exception, Header> callback);

    @RpcCall("getBlockHash")
    @Scale
    CompletableFuture<BlockHash> getBlockHash(long number);

    @RpcCall("getBlock")
    CompletableFuture<SignedBlock> getBlock(@Scale BlockHash hash);
}

Where:

  • RpcInterface indicates an RPC section and its value() is the name of the section;
  • RpcCall indicates the RPC method and its value() is the name of the method;
  • RpcSubscription indicates the RPC subscription:
    • type() is the type of the subscription;
    • subscribeMethod - the name of the method to subscribe;
    • unsubscribeMethod - the name of the method to unsubscribe.

Parameters of RPC methods or subscriptions including the return parameters are encoded/decoded to/from SCALE (if they are annotated properly) or encoded/decoded to/from RpcObject.

Create an Instance of a Section

RpcGeneratedSectionFactory allows to create an instance of a section. The RpcGeneratedSectionFactory.create method requires the class of the section and an instance of the ProviderInterface.

Example:

try (WsProvider wsProvider = WsProvider.builder()
        .setEndpoint("ws://127.0.0.1:9944")
        .build()) {
    wsProvider.connect().join();
    Chain chainSection = RpcGeneratedSectionFactory.create(Chain.class, wsProvider);
}

Rpc Objects

When a client communicates with the node, it encodes/decodes DTOs to/from RpcObjects. Proper encoders/decoders (RpcEncoder and RpcDecoder) must be put into RpcEncoderRegistry and RpcDecoderRegistry respectively.

Standard types have decoders/encoders which are already registered.

The RpcEncoder and RpcDecoder annotations generate proper encoders/decoders for the entities and put them into registries. Annotated entities will be (de-)serialized from/to JSON. The code generation processor will go through each field and find the appropriate encoder/decoder for it (by its type) in the registry or will consider the Scale annotation that represents the field as SCALE.

Example:

@RpcDecoder
@NoArgsConstructor
@Getter
@Setter
public class StorageChangeSet {
    @Scale
    private BlockHash block;
    private List<Pair<StorageKey, StorageData>> changes;
}

The RpcEncoder and RpcDecoder can also be implemented manually. The annotation AutoRegister makes possible to register an encoder/decoder in the registry and it to be resolvable by the types() specified.

Clone this wiki locally