I wanna create OCW that will send a http request to the API and get the response and use this response in runtime code to call extrinsic with this data. This OCW should triggers only when I want to call it, not every block.
So, my question is What is the best way to create it? And what is the best architecture decision for this task, should I create another pallet for OCW or I can just write some functionality in already existing pallet and mark this code as #offchain_worker
(pseudo) for example for future use?
Thanks!
-
Design considerations: forum.polkadot.network/t/…– Bruno ♦Commented Feb 22 at 5:50
-
Examples: github.com/paritytech/substrate/pull/14280– Bruno ♦Commented Feb 22 at 5:50
-
Specifically logic, as Kian mentioned, can go here: github.com/paritytech/substrate/blob/…– Bruno ♦Commented Feb 22 at 5:51
1 Answer
There are 3 levels of answer to this question. As OCW being a commonly misunderstood topic, it is a very good question.
Simple Answer
First, a crude and objectively inefficient answer. You can use the onchain storage that the pallet already gives to you, to trigger the offchain worker. So, an extrinsic would set a storage value, and only when this storage is set the offchain worker would run.
(the following is a pseudo-code, mostly compatibel with FRAME)
// provide ways to set this via extrinsics, as you prefer
#[pallet::storage]
pub type RunWorker = StorageValue<()>;
#[pallet::hooks]
impl Hooks for Pallet {
fn offchain_worker() -> {
if !RunWorker::get() { return }
// rest
}
}
This method is only reasonable when you want to have some kind of onchain proof (eg. the existence of RunWorker
) that offchain workers should have been run. You can then use this to build some kind of an accountability around some nodes (eg. validators) to actually run the offchain workers.
If this is not required, this is mostly a misuse of onchain storage and I won't advice it.
Offchain Workers are off chain..
Which means, in principle, nodes are free to run it whenever they want. The substrate-cli already allows you to configure this to some extent. But it is worth emphasizing that this is an OFF CHAIN operation. It has no impact on the main execution of the chain. It CANNOT alter the state. A block author can decide to not run the offchain worker and it is totally acceptable.
The question would then be, are the execution of these offchain workers important? do all nodes have to run them? How are you going to impose this on thousands of permissionless sovereign node operators? This is where my previous answer might be helpful.
But, if not, the offchain_worker
is merely a runtime api that is executed by the node software. You can build further offchain machinery that, for example, allow a node to listen for normal HTTP requests, and upon receiving them, they execute the offchain workers on the next block.
This has not been done to the best of my knowledge, but if it is really want you want, we can discuss an implementation for it.
Does It Have to be a WASM OCW?
Given the above complexities, it is worth asking yourself, does this operation have to be done as a part of a WASM OCW blob that is part of the runtime? can it not just be a PJS-API (combined with any other web/http framework that you wish) script that lives elsewhere, and is executed whenever you want?
-
Oh, thanks a lot for this detailed answer. My main goal is to make a HTTP request to the API and use response inside my runtime code to create extrinsic call. So, the flow of this OCW execution is: 1. User call the extrinsic. 2. OCW make a HTTP request and get response. 3. Extrinsic is send to the blockchain for execution. Therefore I want to call it only when user triggers some extrinsic. Actually, I have an idea that I can trigger some event when user send me request and after that OCW starts to execute its code. But if we have faster solution for this I would use it. Commented Feb 22 at 12:52
-
Have you explored then doing this purely using JS/TS libraries? Commented Feb 22 at 13:28
-
I'll have this JS/TS functionality on the FE just to get approve from user of the response. But I want to get the last updated info directly from the blockchain. Blockchain should be the source of truth. Commented Feb 22 at 14:33
-
Hi there. Just want to know if you have maybe some ideas what is the best way to solve this? As I understand, it's difficult to query runtime events and search for the event that I need, because it's overload the runtime and block size. So, I decided try to use onchain storage (but it's also not the best way). I wanna write to the storage some value when user call extrinsic and after use this value in OCW to make an HTTP request and in this way I should clean up the storage sometimes. But extrinsics may be called by user anytime, so I can clean some info that haven't processed. @ kianenigma Commented Mar 16 at 14:58