Skip to content
This repository has been archived by the owner on Sep 14, 2023. It is now read-only.

RPC Calls vs. state_calls #228

Open
harrysolovay opened this issue Sep 16, 2022 · 10 comments
Open

RPC Calls vs. state_calls #228

harrysolovay opened this issue Sep 16, 2022 · 10 comments

Comments

@harrysolovay
Copy link
Contributor

@statictype brings up a great point in #218 –– it is likely that many current RPC calls should (at least eventually) occur through state_call. How can we account for this in Capi?

@athei
Copy link
Member

athei commented Sep 19, 2022

What you want to do is use state_call whenever possible and only fall back to a custom RPC where no runtime API exists (storage access would be one example). Many of the RPCs are just wrappers around a runtime API and are redundant. I want to remove them. Eventually we will expose the runtime APIs in metadata but right now you need to hard code the type bindings as you need to do for RPCs. So this doesn't worsen the current situation.

You should not expose the distinction between a runtime API accessed via state_call or via a custom RPC to your users. It is a completely useless distinction. Calling something a "RPC" is a way too low level statement. Just call everything a "node api" and use either a custom RPC or state_call (which is also a RPC) in the background. This way you can slowly migrate over without breaking your API.

You can discover runtime APIs by grepping for decl_runtime_apis! in the substrate code base. All of those are callable via state_call by passing their name as the first argument and SCALE encoding their parameters as a single struct. Wrapper RPCs for them have usually the same name. Those are then redundant. Don't use them.

@harrysolovay
Copy link
Contributor Author

Thank you for this description.

Eventually we will expose the runtime APIs in metadata

This is fascinating to us (cc @tjjfvi, @niklasad1). Any more info on the plan around exposing RPC io types would be greatly appreciated.

@niklasad1
Copy link
Member

niklasad1 commented Sep 20, 2022

@harrysolovay

I don't think generating the RPC types from rpc_methods/discover will work for the runtime RPC APIs (state_call) instead you need the runtime API definition part of the metadata to generate this.

Not sure how polkadot.js handles this but I think it's hardcoded/done manually

@athei
Copy link
Member

athei commented Sep 20, 2022

It has nothing to do with RPCs. You would change the decl_runtime_apis macro to emit the information to metadata.

@niklasad1
Copy link
Member

niklasad1 commented Sep 20, 2022

In this case it does because the idea was to generate the RPC types from the rpc call "discover" i.e, for the jsonrpc library to support the OpenRpc specification such that it's possible to generate a JS client from that.

Because "discover/rpc methods" would only list state_call and the params would just be just Bytes. Thus, my point is that is not possible to generate these runtime RPC APIs without having it in the metadata.

@athei
Copy link
Member

athei commented Sep 20, 2022

I assume there will still be RPC calls except state_call. Those are the cases which don't touch the runtime. Having this discover functionality is still useful for those cases. It is clear that we need both (discover + runtime API in metadata).

@statictype
Copy link

let's take for example the contracts_call RPC that has just been removed

before the change you would use Capi like this:

  const x = C.rpcCall(rococo, "contracts_call", [
    {
      origin,
      dest,
      value,
      gasLimit,
      storageDepositLimit,
      inputData,
    },
  ]);
  const y = await x.run();

i think now it should be used like this. mind that param order is now important:

  const x = C.api(rococo, "contracts_call", [
      origin,
      dest,
      value,
      gasLimit,
      storageDepositLimit,
      inputData,
  ]);
  const y = await x.run();

users shouldn't care how the functionality is exposed. my suggestion is to expose all RPCs and state calls under the same namespace (let's say "api" but other name might work better).

@statictype
Copy link

statictype commented Oct 4, 2022

Type signatures for the contracts runtime calls. Based on the type docs - just for inspiration, didn't really try them out

  type StorageDeposit =
    | { type: "Charge"; value: Balance }
    | { type: "Refund"; value: Balance };

  type ReturnFlags = {
    revert: boolean;
  };

  type ExecReturnValue = {
    flags: ReturnFlags;
    data: string;
  };

  type InstantiateReturnValue = {
    result: ExecReturnValue;
    account_id: AccountId;  // the AccountId of the new contract
  };

  type ContractExecResult = {
    gasRequired: u64;
    gasConsumed: u64;
    storageDeposit: StorageDeposit;
    debug_message: string;
    result: ExecReturnValue | DispatchError;
  };

  type ContractInstantiateResult = {
    gasRequired: u64;
    gasConsumed: u64;
    storageDeposit: StorageDeposit;
    debug_message: string;
    result: InstantiateReturnValue | DispatchError;
  };

  type CodeSource =
    | { type: "Existing"; value: string } // existing on-chain code hash
    | { type: "Upload"; value: Uint8Array }; // new contract wasm code

  function call(
    origin: AccountId,  // caller account
    dest: AccountId,   // contract account
    value: Balance,
    gasLimit: u64,
    storageDepositLimit: Balance | undefined,
    inputData: Uint8Array
  ): ContractExecResult;

  function instantiate(
    origin: AccountId,   // caller account
    value: Balance,
    gasLimit: u64,
    storageDepositLimit: Balance | undefined,
    code: CodeSource,
    data: Uint8Array,
    salt: Uint8Array
  ): ContractInstantiateResult;

@harrysolovay
Copy link
Contributor Author

This is incredibly helpful. Thank you @statictype!

@tjjfvi
Copy link
Contributor

tjjfvi commented Oct 26, 2022

Generating API types for this is blocked on them getting included in the metadata (paritytech/substrate#11648). This is no different from the RPC typing, though, so I believe we can go ahead with using state_calls.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants