16 #include "scale/scale.hpp" 21 using offchain::OffchainWorker;
28 std::shared_ptr<const runtime::MemoryProvider> memory_provider,
29 std::shared_ptr<offchain::OffchainStorage> offchain_storage,
30 std::shared_ptr<offchain::OffchainWorkerPool> ocw_pool)
32 memory_provider_(
std::move(memory_provider)),
33 offchain_storage_(
std::move(offchain_storage)),
34 ocw_pool_(
std::move(ocw_pool)),
35 log_(log::
createLogger(
"OffchainExtension",
"offchain_extension")) {
43 if (not worker_opt.has_value()) {
44 throw std::runtime_error(
45 "Method was called not in offchain worker context");
47 return worker_opt.value();
52 bool isValidator = worker->isValidator();
53 return isValidator ? 1 : 0;
63 auto data_buffer = memory.loadN(data_ptr, data_size);
64 auto xt_res = scale::decode<primitives::Extrinsic>(data_buffer);
65 if (xt_res.has_error()) {
66 throw std::runtime_error(
"Invalid encoded data for transaction arg");
68 auto &xt = xt_res.value();
70 auto result = worker->submitTransaction(std::move(xt));
72 return memory.storeBuffer(scale::encode(result).value());
79 auto result = worker->networkState();
81 return memory.storeBuffer(scale::encode(result).value());
86 auto result = worker->timestamp();
93 worker->sleepUntil(deadline);
99 auto result = worker->timestamp();
100 return memory.storeBuffer(scale::encode(result).value());
110 storage_type = StorageType::Persistent;
111 }
else if (kind == 2) {
112 storage_type = StorageType::Local;
113 }
else if (kind == 0) {
116 storage_type = StorageType::Persistent;
118 throw std::invalid_argument(
119 "Method was called with unknown kind of storage");
123 auto key_buffer = memory.loadN(key_ptr, key_size);
125 auto value_buffer = memory.loadN(value_ptr, value_size);
127 worker->localStorageSet(storage_type, key_buffer, value_buffer);
137 storage_type = StorageType::Persistent;
138 }
else if (kind == 2) {
139 storage_type = StorageType::Local;
140 }
else if (kind == 0) {
143 storage_type = StorageType::Persistent;
145 throw std::invalid_argument(
146 "Method was called with unknown kind of storage");
150 auto key_buffer = memory.loadN(key_ptr, key_size);
152 worker->localStorageClear(storage_type, key_buffer);
166 storage_type = StorageType::Persistent;
167 }
else if (kind == 2) {
168 storage_type = StorageType::Local;
169 }
else if (kind == 0) {
172 storage_type = StorageType::Persistent;
174 throw std::invalid_argument(
175 "Method was called with unknown kind of storage");
179 auto key_buffer = memory.loadN(key_ptr, key_size);
181 auto expected_encoded = memory.loadN(expected_ptr, expected_size);
183 scale::decode<std::optional<common::Buffer>>(expected_encoded);
184 if (expected_res.has_error()) {
185 throw std::runtime_error(
"Invalid encoded data for expected arg");
187 auto &expected_as_buffer{expected_res.value()};
188 std::optional<common::BufferView> expected_as_view;
189 if (expected_as_buffer) {
190 expected_as_view.emplace(expected_as_buffer.value());
193 auto value_buffer = memory.loadN(value_ptr, value_size);
195 auto result = worker->localStorageCompareAndSet(
196 storage_type, key_buffer, expected_as_view, value_buffer);
208 storage_type = StorageType::Persistent;
209 }
else if (kind == 2) {
210 storage_type = StorageType::Local;
211 }
else if (kind == 0) {
214 storage_type = StorageType::Persistent;
216 throw std::invalid_argument(
217 "Method was called with unknown kind of storage");
221 auto key_buffer = memory.loadN(key_ptr, key_size);
223 auto result = worker->localStorageGet(storage_type, key_buffer);
225 auto option = result ? std::make_optional(result.value()) : std::nullopt;
227 return memory.storeBuffer(scale::encode(option).value());
239 auto method_buffer = memory.loadN(method_ptr, method_size);
242 auto uri_buffer = memory.loadN(uri_ptr, uri_size);
243 auto uri = uri_buffer.toString();
247 auto meta_buffer = memory.loadN(meta_ptr, meta_size);
250 if (method_buffer.toString() ==
"Get") {
251 method = HttpMethod::Get;
252 }
else if (method_buffer.toString() ==
"Post") {
253 method = HttpMethod::Post;
257 "ext_offchain_http_request_start_version_1( {}, {}, {} ) failed: " 258 "Reason: unknown method",
259 method_buffer.toString(),
261 meta_buffer.toString());
264 auto result = worker->httpRequestStart(method, uri, meta_buffer);
266 if (result.isSuccess()) {
268 log_, result.value(), method_buffer.toString(), uri, meta_buffer);
272 "ext_offchain_http_request_start_version_1( {}, {}, {} ) failed " 274 method_buffer.toString(),
276 meta_buffer.toString());
279 return memory.storeBuffer(scale::encode(result).value());
292 auto name_buffer = memory.loadN(name_ptr, name_size);
293 auto name = name_buffer.toString();
296 auto value_buffer = memory.loadN(value_ptr, value_size);
297 auto value = value_buffer.toString();
299 auto result = worker->httpRequestAddHeader(request_id, name, value);
301 if (result.isSuccess()) {
307 "ext_offchain_http_request_add_header_version_1( {}, {}, {} ) failed " 314 return memory.storeBuffer(scale::encode(result).value());
327 auto chunk_buffer = memory.loadN(chunk_ptr, chunk_size);
330 auto deadline_buffer = memory.loadN(deadline_ptr, deadline_size);
332 scale::decode<std::optional<Timestamp>>(deadline_buffer);
333 if (deadline_res.has_error()) {
334 throw std::runtime_error(
"Invalid encoded data for deadline arg");
336 auto &deadline = deadline_res.value();
339 worker->httpRequestWriteBody(request_id, chunk_buffer, deadline);
341 return memory.storeBuffer(scale::encode(result).value());
352 auto ids_buffer = memory.loadN(ids_ptr, ids_size);
353 auto ids_res = scale::decode<std::vector<RequestId>>(ids_buffer);
354 if (ids_res.has_error()) {
355 throw std::runtime_error(
"Invalid encoded data for IDs arg");
357 auto &ids = ids_res.value();
360 auto deadline_buffer = memory.loadN(deadline_ptr, deadline_size);
362 scale::decode<std::optional<Timestamp>>(deadline_buffer);
363 if (deadline_res.has_error()) {
364 throw std::runtime_error(
"Invalid encoded data for deadline arg");
366 auto &deadline = deadline_res.value();
368 auto result = worker->httpResponseWait(ids, deadline);
370 return memory.storeBuffer(scale::encode(result).value());
380 auto result = worker->httpResponseHeaders(request_id);
383 log_, fmt::format(
"<{} headers>", result.size()), request_id);
385 return memory.storeBuffer(scale::encode(result).value());
399 auto deadline_buffer = memory.loadN(deadline_ptr, deadline_size);
401 scale::decode<std::optional<Timestamp>>(deadline_buffer);
402 if (deadline_res.has_error()) {
403 throw std::runtime_error(
"Invalid encoded data for deadline arg");
405 auto &deadline = deadline_res.value();
408 buffer.
resize(dst_buffer.size);
410 auto result = worker->httpResponseReadBody(request_id, buffer, deadline);
412 if (result.isSuccess()) {
413 memory.storeBuffer(dst_buffer.ptr, buffer);
416 return memory.storeBuffer(scale::encode(result).value());
425 auto nodes_buffer = memory.loadN(nodes_ptr, nodes_size);
426 auto nodes_res = scale::decode<std::vector<common::Buffer>>(nodes_buffer);
427 if (nodes_res.has_error()) {
428 throw std::runtime_error(
"Invalid encoded data for nodes arg");
430 const auto &nodes_as_buffers = nodes_res.value();
432 std::vector<libp2p::peer::PeerId> nodes;
433 for (
auto buff : nodes_as_buffers) {
434 auto peer_id_res = libp2p::peer::PeerId::fromBytes(buff);
435 if (peer_id_res.has_error()) {
436 throw std::runtime_error(
"Invalid encoded data for nodes arg");
438 auto &peer_id = peer_id_res.value();
439 nodes.emplace_back(std::move(peer_id));
442 worker->setAuthorizedNodes(std::move(nodes), authorized_only == 1);
454 auto key_buffer = memory.loadN(key_ptr, key_size);
456 auto value_buffer = memory.loadN(value_ptr, value_size);
459 if (result.has_error()) {
460 SL_WARN(
log_,
"Can't set value in storage: {}", result.error().message());
473 auto key_buffer = memory.loadN(key_ptr, key_size);
476 if (result.has_error()) {
478 log_,
"Can't clear value in storage: {}", result.error().message());
Class represents arbitrary (including empty) byte buffer.
void ext_offchain_index_clear_version_1(runtime::WasmSpan key)
Remove a key and its associated value from the offchain database.
runtime::WasmSpan ext_offchain_local_storage_get_version_1(runtime::WasmI32 kind, runtime::WasmSpan key)
Gets a value from the local storage.
runtime::WasmSpan ext_offchain_http_response_read_body_version_1(runtime::WasmI32 request_id, runtime::WasmSpan buffer, runtime::WasmSpan deadline)
Reads a chunk of body response to the given buffer. Returns the number of bytes written or an error i...
std::shared_ptr< offchain::OffchainWorker > getWorker()
runtime::WasmU64 ext_offchain_timestamp_version_1()
Returns current timestamp.
SLBuffer & resize(size_t size)
runtime::WasmSpan ext_offchain_http_response_headers_version_1(runtime::WasmI32 request_id)
Read all HTTP response headers. Returns an array of key/value pairs. Response headers must be read be...
#define SL_TRACE_FUNC_CALL(logger, ret,...)
runtime::WasmPointer ext_offchain_random_seed_version_1()
Generates a random seed. This is a truly random non deterministic seed generated by the host environm...
runtime::WasmSpan ext_offchain_http_response_wait_version_1(runtime::WasmSpan ids, runtime::WasmSpan deadline)
Returns an array of request statuses (the length is the same as IDs). Note that if deadline is not pr...
const OffchainExtensionConfig & config_
runtime::WasmI32 ext_offchain_local_storage_compare_and_set_version_1(runtime::WasmI32 kind, runtime::WasmSpan key, runtime::WasmSpan expected, runtime::WasmSpan value)
Sets a new value in the local storage if the condition matches the current value. ...
runtime::WasmSpan ext_offchain_http_request_start_version_1(runtime::WasmSpan method, runtime::WasmSpan uri, runtime::WasmSpan meta)
Initiates a HTTP request given by the HTTP method and the URL. Returns the id of a newly started requ...
runtime::WasmSpan ext_offchain_network_state_version_1()
Returns the SCALE encoded, opaque information about the local node's network state.
OffchainExtension(const OffchainExtensionConfig &config, std::shared_ptr< const runtime::MemoryProvider > memory_provider, std::shared_ptr< offchain::OffchainStorage > offchain_storage, std::shared_ptr< offchain::OffchainWorkerPool > ocw_pool)
void ext_offchain_set_authorized_nodes_version_1(runtime::WasmSpan nodes, runtime::WasmI32 authorized_only)
Set the authorized nodes which are allowed to connect to the local node. This function is offered by ...
uint64_t WasmSpan
combination of pointer and size, where less significant part represents wasm pointer, and most significant represents size
runtime::WasmI32 ext_offchain_is_validator_version_1()
Check whether the local node is a potential validator. Even if this function returns 1...
void ext_offchain_local_storage_set_version_1(runtime::WasmI32 kind, runtime::WasmSpan key, runtime::WasmSpan value)
Sets a value in the local storage. This storage is not part of the consensus, it's only accessible by...
runtime::WasmSpan ext_offchain_http_request_write_body_version_1(runtime::WasmI32 request_id, runtime::WasmSpan chunk, runtime::WasmSpan deadline)
Writes a chunk of the request body. Returns a non-zero value in case the deadline is reached or the c...
runtime::WasmSpan ext_offchain_http_request_add_header_version_1(runtime::WasmI32 request_id, runtime::WasmSpan name, runtime::WasmSpan value)
Append header to the request. Returns an error if the request identifier is invalid, http_response_wait has already been called on the specified request identifier, the deadline is reached or an I/O error has happened (e.g. the remote has closed the connection)
void ext_offchain_index_set_version_1(runtime::WasmSpan key, runtime::WasmSpan value)
Write a key value pair to the offchain database in a buffered fashion.
uint32_t WasmPointer
type of wasm memory is 32 bit integer
void ext_offchain_sleep_until_version_1(runtime::WasmU64 deadline)
Pause the execution until deadline is reached.
std::shared_ptr< const runtime::MemoryProvider > memory_provider_
uint64_t Timestamp
Timestamp is milliseconds since UNIX Epoch.
void ext_offchain_local_storage_clear_version_1(runtime::WasmI32 kind, runtime::WasmSpan key)
Remove a value from the local storage.
runtime::WasmSpan ext_offchain_submit_transaction_version_1(runtime::WasmSpan data)
Given a SCALE encoded extrinsic, this function submits the extrinsic to the Host's transaction pool...
std::shared_ptr< offchain::OffchainWorkerPool > ocw_pool_
Logger createLogger(const std::string &tag)
std::shared_ptr< offchain::OffchainStorage > offchain_storage_