diff --git a/CMakeLists.txt b/CMakeLists.txt
index e66d15cec..73062d3c6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,6 +68,7 @@ option(GCC_ANALYZER "GCC10 static code analyses" OFF)
option(PAY_ETH "support for direct Eth-Payment" OFF)
option(USE_SCRYPT "integrate scrypt into the build in order to allow decrypt_key for scrypt encoded keys." ON)
option(USE_CURL "if true the curl transport will be built (with a dependency to libcurl)" ON)
+option(USE_WINHTTP "if true the winhttp transport will be built (with a dependency to winhttp)" OFF)
option(DEV_NO_INTRN_PTR "(*dev option*) if true the client will NOT include a void pointer (named internal) for use by devs)" ON)
option(LEDGER_NANO "include support for nano ledger" OFF)
option(ESP_IDF "include support for ESP-IDF microcontroller framework" OFF)
@@ -117,6 +118,10 @@ elseif(ETH_NANO)
set(IN3_VERIFIER eth_nano)
endif()
+if (ETH_NANO)
+ set(WASM_MODULES ${WASM_MODULES} eth)
+endif()
+
if(IN3API)
ADD_DEFINITIONS(-DETH_API)
set(IN3_API ${IN3_API} eth_api)
@@ -134,6 +139,8 @@ endif()
if(IPFS)
ADD_DEFINITIONS(-DIPFS)
set(IN3_VERIFIER ${IN3_VERIFIER} ipfs)
+ set(WASM_MODULES ${WASM_MODULES} ipfs)
+
if(IN3API)
set(IN3_API ${IN3_API} ipfs_api)
endif()
@@ -142,6 +149,7 @@ endif()
if(BTC)
ADD_DEFINITIONS(-DBTC)
set(IN3_VERIFIER ${IN3_VERIFIER} btc)
+ set(WASM_MODULES ${WASM_MODULES} btc)
if(IN3API)
set(IN3_API ${IN3_API} btc_api)
endif()
@@ -211,6 +219,7 @@ IF (WASM)
set(IN3_LIB false)
set(CMD false)
set(USE_CURL false)
+ set(USE_WINHTTP false)
ADD_DEFINITIONS(-DWASM)
add_subdirectory(wasm/src)
ENDIF (WASM)
diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt
index e8c04520e..b408dff81 100644
--- a/c/CMakeLists.txt
+++ b/c/CMakeLists.txt
@@ -54,6 +54,9 @@ IF (TRANSPORTS)
if (CURL_BLOCKING)
ADD_DEFINITIONS(-DCURL_BLOCKING)
endif (CURL_BLOCKING)
+ elseif(USE_WINHTTP)
+ ADD_DEFINITIONS(-DUSE_WINHTTP)
+ set(IN3_TRANSPORT ${IN3_TRANSPORT} transport_winhttp)
else ()
set(IN3_TRANSPORT ${IN3_TRANSPORT} transport_http)
endif (USE_CURL)
diff --git a/c/ci.yml b/c/ci.yml
index 0614842be..bed7c3ef3 100644
--- a/c/ci.yml
+++ b/c/ci.yml
@@ -54,7 +54,7 @@ win_mingw:
- .conanbuild
- .only_full
variables:
- CONAN_OPTS: "-DLIBCURL_LINKTYPE=static -DJAVA=false"
+ CONAN_OPTS: "-DUSE_CURL=false -DUSE_WINHTTP=true -DJAVA=false"
BUILD: "win_build"
win_jni:
diff --git a/c/include/in3/client.h b/c/include/in3/client.h
index d415ad01d..418b107d6 100644
--- a/c/include/in3/client.h
+++ b/c/include/in3/client.h
@@ -53,17 +53,17 @@
#define IN3_PROTO_VER "2.1.0" /**< the protocol version used when sending requests from the this client */
-#define CHAIN_ID_MULTICHAIN 0x0 /**< chain_id working with all known chains */
-#define CHAIN_ID_MAINNET 0x01 /**< chain_id for mainnet */
-#define CHAIN_ID_KOVAN 0x2a /**< chain_id for kovan */
-#define CHAIN_ID_TOBALABA 0x44d /**< chain_id for tobalaba */
-#define CHAIN_ID_GOERLI 0x5 /**< chain_id for goerlii */
-#define CHAIN_ID_EVAN 0x4b1 /**< chain_id for evan */
-#define CHAIN_ID_EWC 0xf6 /**< chain_id for ewc */
-#define CHAIN_ID_IPFS 0x7d0 /**< chain_id for ipfs */
-#define CHAIN_ID_BTC 0x99 /**< chain_id for btc */
-#define CHAIN_ID_LOCAL 0xFFFF /**< chain_id for local chain */
-#define DEF_REPL_LATEST_BLK 6 /**< default replace_latest_block */
+#define CHAIN_ID_MULTICHAIN 0x0 /**< chain_id working with all known chains */
+#define CHAIN_ID_MAINNET 0x01 /**< chain_id for mainnet */
+#define CHAIN_ID_KOVAN 0x2a /**< chain_id for kovan */
+#define CHAIN_ID_TOBALABA 0x44d /**< chain_id for tobalaba */
+#define CHAIN_ID_GOERLI 0x5 /**< chain_id for goerlii */
+#define CHAIN_ID_EVAN 0x4b1 /**< chain_id for evan */
+#define CHAIN_ID_EWC 0xf6 /**< chain_id for ewc */
+#define CHAIN_ID_IPFS 0x7d0 /**< chain_id for ipfs */
+#define CHAIN_ID_BTC 0x99 /**< chain_id for btc */
+#define CHAIN_ID_LOCAL 0x11 /**< chain_id for local chain */
+#define DEF_REPL_LATEST_BLK 6 /**< default replace_latest_block */
/**
* type for a chain_id.
diff --git a/c/include/in3/colors.h b/c/include/in3/colors.h
index cd47a3661..c9c9e7016 100644
--- a/c/include/in3/colors.h
+++ b/c/include/in3/colors.h
@@ -33,7 +33,7 @@
*******************************************************************************/
/*Term colors*/
-
+#pragma GCC diagnostic ignored "-Wformat-zero-length"
#ifdef LOG_USE_COLOR
#define COLORT_RESET "\033[0m"
#define COLORT_BOLD "\033[1m"
diff --git a/c/include/in3/context.h b/c/include/in3/context.h
index b73f40687..25f8c13a0 100644
--- a/c/include/in3/context.h
+++ b/c/include/in3/context.h
@@ -86,7 +86,7 @@ typedef struct in3_response {
* */
typedef struct in3_ctx {
uint_fast8_t signers_length; /**< number or addresses */
- uint_fast16_t len; /**< the number of requests */
+ uint16_t len; /**< the number of requests */
uint_fast16_t attempt; /**< the number of attempts */
ctx_type_t type; /**< the type of the request */
in3_ret_t verification_state; /**< state of the verification */
diff --git a/c/include/in3/in3_winhttp.h b/c/include/in3/in3_winhttp.h
new file mode 100644
index 000000000..037996e71
--- /dev/null
+++ b/c/include/in3/in3_winhttp.h
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * This file is part of the Incubed project.
+ * Sources: https://github.com/slockit/in3-c
+ *
+ * Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC
+ *
+ *
+ * COMMERCIAL LICENSE USAGE
+ *
+ * Licensees holding a valid commercial license may use this file in accordance
+ * with the commercial license agreement provided with the Software or, alternatively,
+ * in accordance with the terms contained in a written agreement between you and
+ * slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further
+ * information please contact slock.it at in3@slock.it.
+ *
+ * Alternatively, this file may be used under the AGPL license as follows:
+ *
+ * AGPL LICENSE USAGE
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Affero General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * [Permissions of this strong copyleft license are conditioned on making available
+ * complete source code of licensed works and modifications, which include larger
+ * works using a licensed work, under the same license. Copyright and license notices
+ * must be preserved. Contributors provide an express grant of patent rights.]
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ *******************************************************************************/
+
+// @PUBLIC_HEADER
+/** @file
+ * transport-handler using simple http.
+ */
+
+#ifndef in3_winhttp_h__
+#define in3_winhttp_h__
+
+#include "client.h"
+in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx);
+
+/**
+ * registers http as a default transport.
+ */
+in3_ret_t in3_register_winhttp(in3_t* c);
+
+#endif // in3_http_h__
diff --git a/c/src/cmd/in3/main.c b/c/src/cmd/in3/main.c
index 7f5a9b72b..3d71df5ae 100644
--- a/c/src/cmd/in3/main.c
+++ b/c/src/cmd/in3/main.c
@@ -48,6 +48,8 @@
#include "../../third-party/crypto/secp256k1.h"
#ifdef USE_CURL
#include "../../transport/curl/in3_curl.h"
+#elif USE_WINHTTP
+#include "../../transport/winhttp/in3_winhttp.h"
#else
#include "../../transport/http/in3_http.h"
#endif
@@ -617,6 +619,8 @@ static in3_ret_t debug_transport(void* plugin_data, in3_plugin_act_t action, voi
}
#ifdef USE_CURL
in3_ret_t r = send_curl(NULL, action, plugin_ctx);
+#elif USE_WINHTTP
+ in3_ret_t r = send_winhttp(NULL, action, plugin_ctx);
#else
in3_ret_t r = send_http(NULL, action, plugin_ctx);
#endif
@@ -639,6 +643,8 @@ static in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void
in3_request_t* req = plugin_ctx;
#ifdef USE_CURL
in3_ret_t r = send_curl(NULL, action, plugin_ctx);
+#elif USE_WINHTTP
+ in3_ret_t r = send_winhttp(NULL, action, plugin_ctx);
#else
in3_ret_t r = send_http(NULL, action, plugin_ctx);
#endif
@@ -722,11 +728,8 @@ int main(int argc, char* argv[]) {
bool to_eth = false;
plugin_register(c, PLGN_ACT_TRANSPORT, debug_transport, NULL, true);
-#ifdef __MINGW32__
- c->flags |= FLAGS_HTTP;
-#endif
-#ifndef USE_CURL
- c->flags |= FLAGS_HTTP;
+#ifndef USE_WINHTTP
+ c->request_count = 1;
#endif
// handle clear cache opt before initializing cache
for (i = 1; i < argc; i++)
@@ -1044,6 +1047,8 @@ int main(int argc, char* argv[]) {
r.payload = "";
#ifdef USE_CURL
send_curl(NULL, PLGN_ACT_TRANSPORT_SEND, &r);
+#elif USE_WINHTTP
+ send_winhttp(NULL, PLGN_ACT_TRANSPORT_SEND, &r);
#else
send_http(NULL, PLGN_ACT_TRANSPORT_SEND, &r);
#endif
diff --git a/c/src/core/client/context.h b/c/src/core/client/context.h
index 2e3cf9083..ab6a8aa42 100644
--- a/c/src/core/client/context.h
+++ b/c/src/core/client/context.h
@@ -86,7 +86,7 @@ typedef struct in3_response {
* */
typedef struct in3_ctx {
uint_fast8_t signers_length; /**< number or addresses */
- uint_fast16_t len; /**< the number of requests */
+ uint16_t len; /**< the number of requests */
uint_fast16_t attempt; /**< the number of attempts */
ctx_type_t type; /**< the type of the request */
in3_ret_t verification_state; /**< state of the verification */
diff --git a/c/src/core/client/execute.c b/c/src/core/client/execute.c
index 17afd109d..25b462714 100644
--- a/c/src/core/client/execute.c
+++ b/c/src/core/client/execute.c
@@ -995,7 +995,7 @@ in3_ret_t in3_ctx_execute(in3_ctx_t* ctx) {
if (ctx->error) return (ctx->verification_state && ctx->verification_state != IN3_WAITING) ? ctx->verification_state : IN3_EUNKNOWN;
// is it a valid request?
- if (!ctx->request_context || !d_get(ctx->requests[0], K_METHOD)) return ctx_set_error(ctx, "No Method defined", IN3_ECONFIG);
+ if (!ctx->request_context || d_type(d_get(ctx->requests[0], K_METHOD)) != T_STRING) return ctx_set_error(ctx, "No Method defined", IN3_ECONFIG);
// if there is response we are done.
if (ctx->response_context && ctx->verification_state == IN3_OK) return IN3_OK;
diff --git a/c/src/core/util/colors.h b/c/src/core/util/colors.h
index cd47a3661..c9c9e7016 100644
--- a/c/src/core/util/colors.h
+++ b/c/src/core/util/colors.h
@@ -33,7 +33,7 @@
*******************************************************************************/
/*Term colors*/
-
+#pragma GCC diagnostic ignored "-Wformat-zero-length"
#ifdef LOG_USE_COLOR
#define COLORT_RESET "\033[0m"
#define COLORT_BOLD "\033[1m"
diff --git a/c/src/transport/CMakeLists.txt b/c/src/transport/CMakeLists.txt
index 99164f5f1..95918428a 100644
--- a/c/src/transport/CMakeLists.txt
+++ b/c/src/transport/CMakeLists.txt
@@ -34,6 +34,8 @@
IF (USE_CURL)
add_subdirectory(curl)
+elseif(USE_WINHTTP)
+ add_subdirectory(winhttp)
else ()
add_subdirectory(http)
ENDIF ()
diff --git a/c/src/transport/winhttp/CMakeLists.txt b/c/src/transport/winhttp/CMakeLists.txt
new file mode 100644
index 000000000..8ed15497b
--- /dev/null
+++ b/c/src/transport/winhttp/CMakeLists.txt
@@ -0,0 +1,47 @@
+###############################################################################
+# This file is part of the Incubed project.
+# Sources: https://github.com/slockit/in3-c
+#
+# Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC
+#
+#
+# COMMERCIAL LICENSE USAGE
+#
+# Licensees holding a valid commercial license may use this file in accordance
+# with the commercial license agreement provided with the Software or, alternatively,
+# in accordance with the terms contained in a written agreement between you and
+# slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further
+# information please contact slock.it at in3@slock.it.
+#
+# Alternatively, this file may be used under the AGPL license as follows:
+#
+# AGPL LICENSE USAGE
+#
+# This program is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+# [Permissions of this strong copyleft license are conditioned on making available
+# complete source code of licensed works and modifications, which include larger
+# works using a licensed work, under the same license. Copyright and license notices
+# must be preserved. Contributors provide an express grant of patent rights.]
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see .
+###############################################################################
+
+# add lib
+add_static_library(
+ NAME transport_winhttp
+
+ SOURCES
+ in3_winhttp.c
+
+ DEPENDS
+ core
+ winhttp
+)
+
+
diff --git a/c/src/transport/winhttp/in3_winhttp.c b/c/src/transport/winhttp/in3_winhttp.c
new file mode 100644
index 000000000..9a932b1eb
--- /dev/null
+++ b/c/src/transport/winhttp/in3_winhttp.c
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * This file is part of the Incubed project.
+ * Sources: https://github.com/slockit/in3-c
+ *
+ * Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC
+ *
+ *
+ * COMMERCIAL LICENSE USAGE
+ *
+ * Licensees holding a valid commercial license may use this file in accordance
+ * with the commercial license agreement provided with the Software or, alternatively,
+ * in accordance with the terms contained in a written agreement between you and
+ * slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further
+ * information please contact slock.it at in3@slock.it.
+ *
+ * Alternatively, this file may be used under the AGPL license as follows:
+ *
+ * AGPL LICENSE USAGE
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Affero General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * [Permissions of this strong copyleft license are conditioned on making available
+ * complete source code of licensed works and modifications, which include larger
+ * works using a licensed work, under the same license. Copyright and license notices
+ * must be preserved. Contributors provide an express grant of patent rights.]
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ *******************************************************************************/
+
+#include "in3_winhttp.h"
+#include "../../core/client/client.h"
+#include "../../core/client/plugin.h"
+#include "../../core/client/version.h"
+#include "../../core/util/mem.h"
+#include "../../core/util/utils.h"
+#include /* printf, sprintf */
+#include /* exit, atoi, malloc, free */
+#include /* memcpy, memset */
+#include
+#include /* read, write, close */
+#include
+#include
+
+static inline wchar_t* convert_wstr(const char* src, void* dst) {
+ MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, (int) MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0));
+ return dst;
+}
+#define to_wstr(c) convert_wstr(c, alloca(MultiByteToWideChar(CP_UTF8, 0, c, -1, NULL, 0) * sizeof(wchar_t) + 1))
+
+in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) {
+ UNUSED_VAR(plugin_data);
+ in3_request_t* req = plugin_ctx;
+ if (action != PLGN_ACT_TRANSPORT_SEND) return IN3_ENOTSUP;
+ for (unsigned int n = 0; n < req->urls_len; n++) {
+ uint32_t start = current_ms();
+ sb_t* sb = &req->ctx->raw_response[n].data;
+ HINTERNET hSession = WinHttpOpen(to_wstr("in3 winhttp " IN3_VERSION),
+ WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS, 0);
+ if (!hSession) {
+ in3_ctx_add_response(req->ctx, n, true, "could not create the session", -1, 0);
+ continue;
+ }
+
+ URL_COMPONENTS url_components;
+ wchar_t hostname[128];
+ wchar_t url_path[4096];
+ wchar_t* url = to_wstr(req->urls[n]);
+ memset(&url_components, 0, sizeof(URL_COMPONENTS));
+ url_components.dwStructSize = sizeof(URL_COMPONENTS);
+ url_components.lpszHostName = hostname;
+ url_components.dwHostNameLength = 128;
+ url_components.lpszUrlPath = url_path;
+ url_components.dwUrlPathLength = 1024;
+
+ WinHttpCrackUrl(url, 0, 0, &url_components);
+
+ HINTERNET connect = WinHttpConnect(hSession, url_components.lpszHostName, url_components.nPort, 0);
+ if (!connect) {
+ in3_ctx_add_response(req->ctx, n, true, "could not connect to ", -1, 0);
+ sb_add_chars(sb, req->urls[n]);
+ sb_add_chars(sb, "Error code : ");
+ sb_add_int(sb, GetLastError());
+ WinHttpCloseHandle(hSession);
+ continue;
+ }
+ bool https = strstr(req->urls[n], "https") == req->urls[n];
+ HINTERNET request = WinHttpOpenRequest(connect, to_wstr("POST"),
+ url_components.lpszUrlPath, NULL, WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES, https ? WINHTTP_FLAG_SECURE : 0);
+ if (!request) {
+ in3_ctx_add_response(req->ctx, n, true, "could not open the request to ", -1, 0);
+ sb_add_chars(sb, req->urls[n]);
+ sb_add_chars(sb, "Error code : ");
+ sb_add_int(sb, GetLastError());
+ WinHttpCloseHandle(connect);
+ WinHttpCloseHandle(hSession);
+ continue;
+ }
+ int plen = strlen(req->payload);
+ bool success = plen
+ ? WinHttpSendRequest(
+ request,
+ to_wstr("Accept: application/json\r\nContent-Type: application/json\r\ncharsets: utf-8\r\n"),
+ (DWORD) -1,
+ (LPVOID) req->payload,
+ (DWORD) plen, (DWORD) plen, 0)
+ : WinHttpSendRequest(
+ request,
+ WINHTTP_NO_ADDITIONAL_HEADERS,
+ 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
+
+ if (success) {
+ WinHttpReceiveResponse(request, NULL);
+ DWORD dwSize = 0;
+ DWORD dwDownloaded = 0;
+ LPSTR pszOutBuffer = NULL;
+
+ do {
+ // Check for available data.
+ dwSize = 0;
+ if (!WinHttpQueryDataAvailable(request, &dwSize)) {
+ sb->len = 0;
+ in3_ctx_add_response(req->ctx, n, true, "could not read the data from ", -1, 0);
+ sb_add_chars(sb, req->urls[n]);
+ sb_add_chars(sb, "Error code : ");
+ sb_add_int(sb, GetLastError());
+ break;
+ }
+
+ // No more available data.
+ if (!dwSize)
+ break;
+
+ // Allocate space for the buffer.
+ pszOutBuffer = _calloc(dwSize + 1, 1);
+
+ if (!WinHttpReadData(request, (LPVOID) pszOutBuffer,
+ dwSize, &dwDownloaded)) {
+ sb->len = 0;
+ in3_ctx_add_response(req->ctx, n, true, "could not read the data from ", -1, 0);
+ sb_add_chars(sb, req->urls[n]);
+ sb_add_chars(sb, "Error code : ");
+ sb_add_int(sb, GetLastError());
+ _free(pszOutBuffer);
+ break;
+ }
+ else
+ sb_add_range(sb, pszOutBuffer, 0, dwSize);
+
+ // Free the memory allocated to the buffer.
+ _free(pszOutBuffer);
+
+ // This condition should never be reached since WinHttpQueryDataAvailable
+ // reported that there are bits to read.
+ if (!dwDownloaded)
+ break;
+
+ } while (dwSize > 0);
+
+ if (req->ctx->raw_response[n].state == IN3_WAITING) {
+ req->ctx->raw_response[n].state = IN3_OK;
+ req->ctx->raw_response[n].time = current_ms() - start;
+ }
+ }
+ else {
+ in3_ctx_add_response(req->ctx, n, true, "could not open send the request to ", -1, 0);
+ sb_add_chars(sb, req->urls[n]);
+ sb_add_chars(sb, "Error code : ");
+ sb_add_int(sb, GetLastError());
+ }
+ WinHttpCloseHandle(request);
+ WinHttpCloseHandle(connect);
+ WinHttpCloseHandle(hSession);
+ }
+ return IN3_OK;
+}
+
+in3_ret_t in3_register_winhttp(in3_t* c) {
+ return plugin_register(c, PLGN_ACT_TRANSPORT, send_winhttp, NULL, true);
+}
diff --git a/c/src/transport/winhttp/in3_winhttp.h b/c/src/transport/winhttp/in3_winhttp.h
new file mode 100644
index 000000000..ce5eb3133
--- /dev/null
+++ b/c/src/transport/winhttp/in3_winhttp.h
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * This file is part of the Incubed project.
+ * Sources: https://github.com/slockit/in3-c
+ *
+ * Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC
+ *
+ *
+ * COMMERCIAL LICENSE USAGE
+ *
+ * Licensees holding a valid commercial license may use this file in accordance
+ * with the commercial license agreement provided with the Software or, alternatively,
+ * in accordance with the terms contained in a written agreement between you and
+ * slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further
+ * information please contact slock.it at in3@slock.it.
+ *
+ * Alternatively, this file may be used under the AGPL license as follows:
+ *
+ * AGPL LICENSE USAGE
+ *
+ * This program is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Affero General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ * [Permissions of this strong copyleft license are conditioned on making available
+ * complete source code of licensed works and modifications, which include larger
+ * works using a licensed work, under the same license. Copyright and license notices
+ * must be preserved. Contributors provide an express grant of patent rights.]
+ * You should have received a copy of the GNU Affero General Public License along
+ * with this program. If not, see .
+ *******************************************************************************/
+
+// @PUBLIC_HEADER
+/** @file
+ * transport-handler using simple http.
+ */
+
+#ifndef in3_winhttp_h__
+#define in3_winhttp_h__
+
+#include "../../core/client/client.h"
+in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx);
+
+/**
+ * registers http as a default transport.
+ */
+in3_ret_t in3_register_winhttp(in3_t* c);
+
+#endif // in3_http_h__
diff --git a/c/src/verifier/eth1/basic/eth_getLog.c b/c/src/verifier/eth1/basic/eth_getLog.c
index 28a2ebd0c..43e38d475 100644
--- a/c/src/verifier/eth1/basic/eth_getLog.c
+++ b/c/src/verifier/eth1/basic/eth_getLog.c
@@ -222,6 +222,10 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs) {
for (d_iterator_t it = d_iter(d_get(vc->proof, K_LOG_PROOF)); it.left; d_iter_next(&it)) {
sprintf(xtmp, "0x%" PRIx64, d_get_longk(it.token, K_NUMBER));
+ if (strlen(xtmp) % 2) {
+ memmove(xtmp + 3, xtmp + 2, strlen(xtmp) - 1);
+ xtmp[2] = '0';
+ }
// verify that block number matches key
if (key(xtmp) != it.token->key)
return vc_err(vc, "block number mismatch");
diff --git a/c/src/verifier/in3_init.c b/c/src/verifier/in3_init.c
index 54b5e6aeb..f7bcc60eb 100644
--- a/c/src/verifier/in3_init.c
+++ b/c/src/verifier/in3_init.c
@@ -3,8 +3,13 @@
#include "../core/client/plugin.h"
#include "../pay/eth/pay_eth.h"
#include "../pay/zksync/zksync.h"
+#ifdef USE_CURL
#include "../transport/curl/in3_curl.h"
+#elif USE_WINHTTP
+#include "../transport/winhttp/in3_winhttp.h"
+#else
#include "../transport/http/in3_http.h"
+#endif
#include "../verifier/btc/btc.h"
#include "../verifier/eth1/basic/eth_basic.h"
#include "../verifier/eth1/full/eth_full.h"
@@ -43,6 +48,8 @@ static void init_transport() {
#ifdef TRANSPORTS
#ifdef USE_CURL
in3_register_default(in3_register_curl);
+#elif USE_WINHTTP
+ in3_register_default(in3_register_winhttp);
#else
in3_register_default(in3_register_http);
#endif /* USE_CURL */
diff --git a/python/.gitignore b/python/.gitignore
index 12a40a162..e9d56494c 100644
--- a/python/.gitignore
+++ b/python/.gitignore
@@ -10,3 +10,4 @@ MANIFEST
.DS_Store
.coverage
report.xml
+examples/smart_meter_write.py
diff --git a/python/in3/eth/model.py b/python/in3/eth/model.py
index 83481dfb6..97e6f4060 100644
--- a/python/in3/eth/model.py
+++ b/python/in3/eth/model.py
@@ -191,6 +191,15 @@ def __init__(self, blockHash: hex, blockNumber: int, cumulativeGasUsed: int, Fro
self.to = to
self.contractAddress = contractAddress
+ def to_dict(self, int_to_hex: bool = False) -> dict:
+ base_dict = super(TransactionReceipt, self).to_dict()
+ logs = [log.to_dict() for log in base_dict['logs']]
+ base_dict['logs'] = logs
+ return base_dict
+
+ def __str__(self):
+ return str(self.to_dict())
+
class Account(DataTransferObject):
"""
diff --git a/python/in3/transport.py b/python/in3/transport.py
index 7396acb57..88adbc67d 100644
--- a/python/in3/transport.py
+++ b/python/in3/transport.py
@@ -32,10 +32,7 @@ def https_transport(in3_request: In3Request, in3_response: In3Response):
if not response.status == 200:
raise TransportException('Request failed with status: {}'.format(str(response.status)))
msg = response.read()
- if 'error' in str(msg, 'utf8'):
- in3_response.failure(i, msg)
- else:
- in3_response.success(i, msg)
+ in3_response.success(i, msg)
except Exception as err:
in3_response.failure(i, str(err).encode('utf8'))
return 0
diff --git a/python/pylama.ini b/python/pylama.ini
index 27ceff578..b58ac4d5f 100644
--- a/python/pylama.ini
+++ b/python/pylama.ini
@@ -1,4 +1,4 @@
[pylama]
format = pylint
-skip = */.tox/*,*/.env/*
+skip = */.tox/*,*/.env/*,examples/smart*
ignore = E501,W0611,C901
\ No newline at end of file
diff --git a/scripts/build.sh b/scripts/build.sh
index 9c64f8caa..0795e4c04 100755
--- a/scripts/build.sh
+++ b/scripts/build.sh
@@ -46,6 +46,7 @@ if [ "$CONTAINER" = "--help" ]; then
echo " - clang9"
echo " - clang50"
echo " - gcc10"
+ echo " - gcc8-x86"
echo " - gcc8"
echo " - gcc8-armv7"
echo " - gcc8-armv7hf"
@@ -77,7 +78,7 @@ elif [ "$CONTAINER" = "win" ]; then
CONTAINER=docker.slock.it/build-images/cmake:gcc7-mingw
echo $CONTAINER > build/container.txt
docker run --rm -v $RD:$RD $CONTAINER \
- /bin/bash -c "cd $RD/build; cmake -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=false -DLEDGER_NANO=true -DUSE_CURL=true -DLIBCURL_LINKTYPE=static .. && make -j8"
+ /bin/bash -c "cd $RD/build; cmake -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=false -DLEDGER_NANO=false -DUSE_CURL=false -DUSE_WINHTTP=true .. && make -j8"
elif [ "$CONTAINER" = "cortexm3" ]; then
CONTAINER=docker.io/zephyrprojectrtos/zephyr-build:v0.12
echo $CONTAINER > build/container.txt
diff --git a/wasm/docs/2_examples.md b/wasm/docs/2_examples.md
index abb6469fd..1f377b71f 100644
--- a/wasm/docs/2_examples.md
+++ b/wasm/docs/2_examples.md
@@ -67,6 +67,64 @@ async function showLatestBlock() {
showLatestBlock().catch(console.error)
```
+### register_pugin
+
+source : [in3-c/wasm/examples/register_pugin.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/register_pugin.ts)
+
+register a custom plugin
+
+
+```js
+/// register a custom plugin
+
+import { IN3, RPCRequest } from 'in3-wasm'
+import * as crypto from 'crypto'
+
+class Sha256Plugin {
+
+ // this function will register for handling rpc-methods
+ // only if we return something other then `undefined`, it will be taken as the result of the rpc.
+ // if we don't return, the request will be forwarded to the incubed nodes
+ handleRPC(c: IN3, request: RPCRequest): any {
+ if (request.method === 'sha256') {
+ // assert params
+ if (request.params.length != 1 || typeof (request.params[0]) != 'string')
+ throw new Error('Only one parameter with as string is expected!')
+
+ // create hash
+ const hash = crypto.createHash('sha256').update(Buffer.from(request.params[0], 'utf8')).digest()
+
+ // return the result
+ return '0x' + hash.toString('hex')
+ }
+ }
+
+}
+
+
+
+async function registerPlugin() {
+ // create new incubed instance
+ const client = new IN3({
+ chainId: 'goerli'
+ })
+
+ // register the plugin
+ client.registerPlugin(new Sha256Plugin())
+
+ // exeucte a rpc-call
+ const result = await client.sendRPC("sha256", ["testdata"])
+
+ console.log(" sha256: ", result)
+
+ // clean up
+ client.free()
+
+}
+
+registerPlugin().catch(console.error)
+```
+
### use_web3
source : [in3-c/wasm/examples/use_web3.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/use_web3.ts)
diff --git a/wasm/examples/README.md b/wasm/examples/README.md
index 17801ae71..d71ea1d66 100644
--- a/wasm/examples/README.md
+++ b/wasm/examples/README.md
@@ -7,6 +7,9 @@
- [get_block_api](./get_block_api.ts)
read block with API
+- [register_pugin](./register_pugin.ts)
+ register a custom plugin
+
- [use_web3](./use_web3.ts)
use incubed as Web3Provider in web3js
diff --git a/wasm/examples/get_block_rpc.js b/wasm/examples/get_block_rpc.js
index 59805adf6..40cc4464a 100644
--- a/wasm/examples/get_block_rpc.js
+++ b/wasm/examples/get_block_rpc.js
@@ -10,13 +10,10 @@ async function showLatestBlock() {
chainId: 0x5 // use goerli
})
- // send raw RPC-Request
- const lastBlockResponse = await c.send({ method: 'eth_getBlockByNumber', params: ['latest', false] })
+ // send raw RPC-Request (this would throw if the response contains an error)
+ const lastBlockResponse = await c.sendRPC('eth_getBlockByNumber', ['latest', false])
- if (lastBlockResponse.error)
- console.error("Error getting the latest block : ", lastBlockResponse.error)
- else
- console.log("latest Block: ", JSON.stringify(lastBlockResponse.result, null, 2))
+ console.log("latest Block: ", JSON.stringify(lastBlockResponse, null, 2))
// clean up
c.free()
diff --git a/wasm/examples/register_pugin.ts b/wasm/examples/register_pugin.ts
new file mode 100644
index 000000000..4af0e9b30
--- /dev/null
+++ b/wasm/examples/register_pugin.ts
@@ -0,0 +1,46 @@
+/// register a custom plugin
+
+import { IN3, RPCRequest } from 'in3-wasm'
+import * as crypto from 'crypto'
+
+class Sha256Plugin {
+
+ // this function will register for handling rpc-methods
+ // only if we return something other then `undefined`, it will be taken as the result of the rpc.
+ // if we don't return, the request will be forwarded to the incubed nodes
+ handleRPC(c: IN3, request: RPCRequest): any {
+ if (request.method === 'sha256') {
+ // assert params
+ if (request.params.length != 1 || typeof (request.params[0]) != 'string')
+ throw new Error('Only one parameter with as string is expected!')
+
+ // create hash
+ const hash = crypto.createHash('sha256').update(Buffer.from(request.params[0], 'utf8')).digest()
+
+ // return the result
+ return '0x' + hash.toString('hex')
+ }
+ }
+
+}
+
+
+
+async function registerPlugin() {
+ // create new incubed instance
+ const client = new IN3()
+
+ // register the plugin
+ client.registerPlugin(new Sha256Plugin())
+
+ // exeucte a rpc-call
+ const result = await client.sendRPC("sha256", ["testdata"])
+
+ console.log(" sha256: ", result)
+
+ // clean up
+ client.free()
+
+}
+
+registerPlugin().catch(console.error)
\ No newline at end of file
diff --git a/wasm/src/CMakeLists.txt b/wasm/src/CMakeLists.txt
index a54fa4ee1..9518f71ae 100644
--- a/wasm/src/CMakeLists.txt
+++ b/wasm/src/CMakeLists.txt
@@ -63,11 +63,12 @@ add_executable(in3w wasm.c)
target_link_libraries(in3w init)
set_target_properties(in3w PROPERTIES LINK_FLAGS "${EMC_PROPS}")
+
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/bin/in3.js
- DEPENDS in3w in3.js in3_eth_api.js in3_btc_api.js in3_ipfs_api.js in3_util.js in3.d.ts
+ DEPENDS in3w in3.js modules/eth.js modules/btc.js modules/ipfs.js in3_util.js in3.d.ts modules/btc.d.ts modules/ipfs.d.ts modules/eth.d.ts
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin/
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_js.sh ${CMAKE_CURRENT_SOURCE_DIR} ${ASMJS}
+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build_js.sh ${CMAKE_CURRENT_SOURCE_DIR} ${ASMJS} ${WASM_MODULES}
)
add_custom_target(in3_wasm ALL DEPENDS ${CMAKE_BINARY_DIR}/bin/in3.js)
diff --git a/wasm/src/build_js.sh b/wasm/src/build_js.sh
index 020d03c00..846f2e0c3 100755
--- a/wasm/src/build_js.sh
+++ b/wasm/src/build_js.sh
@@ -1,4 +1,8 @@
#!/bin/bash
+function replace_var {
+ echo "REPLACE $1 with $2"
+ sed -i "s/$(echo $1 | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo $2 | sed -e 's/[\/&]/\\&/g')/g" $3
+}
TARGET_JS="in3.js"
@@ -10,9 +14,27 @@ cat in3w.js | sed "s/uncaughtException/ue/g" >> $TARGET_JS
# it should also overwrite the module.exports to use the wrapper-class.
cat "$1/in3.js" >> $TARGET_JS
cat "$1/in3_util.js" >> $TARGET_JS
-cat "$1/in3_eth_api.js" >> $TARGET_JS
-cat "$1/in3_ipfs_api.js" >> $TARGET_JS
-cat "$1/in3_btc_api.js" >> $TARGET_JS
+
+__CONFIG__=""
+typedefs=""
+__API__=""
+for m in $3 $4 $5 $6 $7 $8 $9
+do
+ cat "$1/modules/$m.js" >> $TARGET_JS
+ if test -f "$1/modules/$m.d.ts"; then
+ if grep -q "${m}_config" "$1/modules/$m.d.ts"; then
+ __CONFIG__="$__CONFIG__\n /** config for $m */\n $m?:${m}_config"
+ fi
+ conf=`grep API $1/modules/$m.d.ts | grep public | grep "$m:"`
+ [[ ! -z "$conf" ]] && __API__="$__API__\n /** $m API */\n $conf"
+ typedefs="$typedefs $1/modules/$m.d.ts"
+ fi
+done
+
+
+#cat "$1/in3_ipfs_api.js" >> $TARGET_JS
+#cat "$1/in3_btc_api.js" >> $TARGET_JS
+
# we return the default export
echo " return IN3; })();" >> $TARGET_JS
#echo "//# sourceMappingURL=index.js.map" >> $TARGET_JS
@@ -21,7 +43,13 @@ echo " return IN3; })();" >> $TARGET_JS
mkdir -p ../module
cp ../../LICENSE.AGPL "$1/package.json" $1/../README.md ../module/
cp in3.js ../module/index.js
-cp "$1/in3.d.ts" ../module/index.d.ts
+
+cat "$1/in3.d.ts" | awk -v "r=$__CONFIG__" '{gsub(/__CONFIG__/,r)}1' | awk -v "r=$__API__" '{gsub(/__API__/,r)}1' > ../module/index.d.ts
+for f in $typedefs; do
+ cat $f >> ../module/index.d.ts
+done
+
+
if [ -e in3w.wasm ]
then cp in3w.wasm ../module/
fi
diff --git a/wasm/src/in3.d.ts b/wasm/src/in3.d.ts
index 7b6489202..eda9ae8b0 100644
--- a/wasm/src/in3.d.ts
+++ b/wasm/src/in3.d.ts
@@ -37,6 +37,13 @@
* All properties are optional and will be verified when sending the next request.
*/
export declare interface IN3Config {
+ /**
+ * sets the transport-function.
+ *
+ * @param fn the function to fetch the response for the given url
+ */
+ transport?: (url: string, payload: string, timeout?: number) => Promise
+
/**
* if true the nodelist will be automaticly updated if the lastBlock is newer.
*
@@ -239,6 +246,8 @@ export declare interface IN3Config {
}
}
+
+ __CONFIG__
}
/**
* a configuration of a in3-server.
@@ -378,6 +387,34 @@ export declare interface RPCResponse {
result?: any
}
+/**
+ * a Incubed plugin.
+ *
+ * Depending on the methods this will register for those actions.
+ */
+interface IN3Plugin {
+ /**
+ * this is called when the client is cleaned up.
+ * @param client the client object
+ */
+ term?(client: IN3Generic)
+
+ /**
+ * returns address
+ * @param client
+ */
+ getAccount?(client: IN3Generic)
+
+ /**
+ * called for each request.
+ * If the plugin wants to handle the request, this function should return the value or a Promise for the value.
+ * If the plugin does not want to handle it, it should rreturn undefined.
+ * @param client the current client
+ * @param request the rpc-request
+ */
+ handleRPC?(client: IN3Generic, request: RPCRequest): undefined | Promise
+}
+
export default class IN3Generic {
/**
* IN3 config
@@ -432,7 +469,7 @@ export default class IN3Generic {
/**
- * changes the transport-function.
+ * changes the default transport-function.
*
* @param fn the function to fetch the response for the given url
*/
@@ -466,21 +503,18 @@ export default class IN3Generic {
*/
public eth: EthAPI
+ __API__
/**
- * ipfs API.
+ * collection of util-functions.
*/
- public ipfs: IpfsAPI
+ public util: Utils
/**
- * Bitcoin API.
+ * rregisters a plugin. The plugin may define methods which will be called by the client.
+ * @param plugin the plugin-object to register
*/
- public btc: BtcAPI
-
- /**
- * collection of util-functions.
- */
- public util: Utils
+ public registerPlugin(plugin: IN3Plugin): void
/**
* collection of util-functions.
@@ -585,212 +619,7 @@ export type Transaction = {
/** optional chain id */
chainId?: any
}
-export type TransactionReceipt = {
- /** 32 Bytes - hash of the block where this transaction was in. */
- blockHash: Hash
- /** block number where this transaction was in.*/
- blockNumber: BlockType
- /** 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.*/
- contractAddress: Address
- /** The total amount of gas used when this transaction was executed in the block. */
- cumulativeGasUsed: Quantity
- /** 20 Bytes - The address of the sender. */
- from: Address
- /** 20 Bytes - The address of the receiver. null when it’s a contract creation transaction.*/
- to: Address
- /** The amount of gas used by this specific transaction alone. */
- gasUsed: Quantity
- /** Array of log objects, which this transaction generated. */
- logs: Log[]
- /** 256 Bytes - A bloom filter of logs/events generated by contracts during transaction execution. Used to efficiently rule out transactions without expected logs.*/
- logsBloom: Data
- /** 32 Bytes - Merkle root of the state trie after the transaction has been executed (optional after Byzantium hard fork EIP609)*/
- root: Hash
- /** 0x0 indicates transaction failure , 0x1 indicates transaction success. Set for blocks mined after Byzantium hard fork EIP609, null before. */
- status: Quantity
- /** 32 Bytes - hash of the transaction. */
- transactionHash: Hash
- /** Integer of the transactions index position in the block. */
- transactionIndex: Quantity
-}
-export type TransactionDetail = {
- /** 32 Bytes - hash of the transaction. */
- hash: Hash
- /** the number of transactions made by the sender prior to this one.*/
- nonce: Quantity
- /** 32 Bytes - hash of the block where this transaction was in. null when its pending.*/
- blockHash: Hash
- /** block number where this transaction was in. null when its pending.*/
- blockNumber: BlockType
- /** integer of the transactions index position in the block. null when its pending.*/
- transactionIndex: Quantity
- /** 20 Bytes - address of the sender.*/
- from: Address
- /** 20 Bytes - address of the receiver. null when its a contract creation transaction. */
- to: Address
- /** value transferred in Wei.*/
- value: Quantity
- /** gas price provided by the sender in Wei.*/
- gasPrice: Quantity
- /** gas provided by the sender. */
- gas: Quantity
- /** the data send along with the transaction. */
- input: Data
- /** the standardised V field of the signature.*/
- v: Quantity
- /** the standardised V field of the signature (0 or 1).*/
- standardV: Quantity
- /** the R field of the signature.*/
- r: Quantity
- /** raw transaction data */
- raw: Data
- /** public key of the signer. */
- publicKey: Hash
- /** the chain id of the transaction, if any. */
- chainId: Quantity
- /** creates contract address */
- creates: Address
- /** (optional) conditional submission, Block number in block or timestamp in time or null. (parity-feature) */
- condition: any
- /** optional: the private key to use for signing */
- pk?: any
-}
-
-export type Block = {
- /** The block number. null when its pending block */
- number: Quantity
- /** hash of the block. null when its pending block */
- hash: Hash
- /** hash of the parent block */
- parentHash: Hash
- /** 8 bytes hash of the generated proof-of-work. null when its pending block. Missing in case of PoA. */
- nonce: Data
- /** SHA3 of the uncles data in the block */
- sha3Uncles: Data
- /** 256 Bytes - the bloom filter for the logs of the block. null when its pending block */
- logsBloom: Data
- /** 32 Bytes - the root of the transaction trie of the block */
- transactionsRoot: Data
- /** 32 Bytes - the root of the final state trie of the block */
- stateRoot: Data
- /** 32 Bytes - the root of the receipts trie of the block */
- receiptsRoot: Data
- /** 20 Bytes - the address of the author of the block (the beneficiary to whom the mining rewards were given)*/
- author: Address
- /** 20 Bytes - alias of ‘author’*/
- miner: Address
- /** integer of the difficulty for this block */
- difficulty: Quantity
- /** integer of the total difficulty of the chain until this block */
- totalDifficulty: Quantity
- /** the ‘extra data’ field of this block */
- extraData: Data
- /** integer the size of this block in bytes */
- size: Quantity
- /** the maximum gas allowed in this block */
- gasLimit: Quantity
- /** the total used gas by all transactions in this block */
- gasUsed: Quantity
- /** the unix timestamp for when the block was collated */
- timestamp: Quantity
- /** Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter */
- transactions: (Hash | Transaction)[]
- /** Array of uncle hashes */
- uncles: Hash[]
- /** PoA-Fields */
- sealFields: Data[]
-}
-export type Log = {
- /** true when the log was removed, due to a chain reorganization. false if its a valid log. */
- removed: boolean
- /** integer of the log index position in the block. null when its pending log. */
- logIndex: Quantity
- /** integer of the transactions index position log was created from. null when its pending log. */
- transactionIndex: Quantity
- /** Hash, 32 Bytes - hash of the transactions this log was created from. null when its pending log. */
- transactionHash: Hash
- /** Hash, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log. */
- blockHash: Hash,
- /** the block number where this log was in. null when its pending. null when its pending log. */
- blockNumber: Quantity
- /** 20 Bytes - address from which this log originated. */
- address: Address,
- /** contains the non-indexed arguments of the log. */
- data: Data
- /** - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.) */
- topics: Data[]
-}
-
-export type LogFilter = {
- /** Quantity or Tag - (optional) (default: latest) Integer block number, or 'latest' for the last mined block or 'pending', 'earliest' for not yet mined transactions. */
- fromBlock: BlockType
- /** Quantity or Tag - (optional) (default: latest) Integer block number, or 'latest' for the last mined block or 'pending', 'earliest' for not yet mined transactions.*/
- toBlock: BlockType
- /** (optional) 20 Bytes - Contract address or a list of addresses from which logs should originate.*/
- address: Address
- /** (optional) Array of 32 Bytes Data topics. Topics are order-dependent. It’s possible to pass in null to match any topic, or a subarray of multiple topics of which one should be matching. */
- topics: (string | string[])[]
- /** å(optional) The maximum number of entries to retrieve (latest first). */
- limit: Quantity
-}
-
-export type TxRequest = {
- /** contract */
- to?: Address
-
- /** address of the account to use */
- from?: Address
-
- /** the data to send */
- data?: Data
-
- /** the gas needed */
- gas?: number
-
- /** the gasPrice used */
- gasPrice?: number
-
- /** the nonce */
- nonce?: number
-
- /** the value in wei */
- value?: Quantity
-
- /** the ABI of the method to be used */
- method?: string
-
- /** the argument to pass to the method */
- args?: any[]
-
- /**raw private key in order to sign */
- pk?: Hash
-
- /** number of block to wait before confirming*/
- confirmations?: number
-
- /** number of seconds to wait for confirmations before giving up. Default: 10 */
- timeout?: number
-}
-export interface Web3Event {
- returnValues: {
- [name: string]: any
- },
- event: string,
- signature: string,
- logIndex: number
- transactionIndex: number,
- transactionHash: Hash,
- address: Address
- blockNumber: number
- blockHash: Hash,
- raw: {
- data: Hex
- topicx: Hash[]
- }
-
-
-}
export declare interface Signer {
/** optiional method which allows to change the transaction-data before sending it. This can be used for redirecting it through a multisig. */
@@ -806,282 +635,6 @@ export declare interface Signer {
sign: (data: Hex, account: Address, hashFirst?: boolean, ethV?: boolean) => Promise
}
-export interface EthAPI {
- client: IN3Generic;
- signer?: Signer;
- constructor(client: IN3Generic);
- /**
- * Returns the number of most recent block. (as number)
- */
- blockNumber(): Promise;
- /**
- * Returns the current price per gas in wei. (as number)
- */
- gasPrice(): Promise;
- /**
- * Executes a new message call immediately without creating a transaction on the block chain.
- */
- call(tx: Transaction, block?: BlockType): Promise;
- /**
- * Executes a function of a contract, by passing a [method-signature](https://github.com/ethereumjs/ethereumjs-abi/blob/master/README.md#simple-encoding-and-decoding) and the arguments, which will then be ABI-encoded and send as eth_call.
- */
- callFn(to: Address, method: string, ...args: any[]): Promise;
- /**
- * Returns the EIP155 chain ID used for transaction signing at the current best block. Null is returned if not available.
- */
- chainId(): Promise;
- /**
- * Makes a call or transaction, which won’t be added to the blockchain and returns the used gas, which can be used for estimating the used gas.
- */
- estimateGas(tx: Transaction): Promise;
- /**
- * Returns the balance of the account of given address in wei (as hex).
- */
- getBalance(address: Address, block?: BlockType): Promise;
- /**
- * Returns code at a given address.
- */
- getCode(address: Address, block?: BlockType): Promise;
- /**
- * Returns the value from a storage position at a given address.
- */
- getStorageAt(address: Address, pos: Quantity, block?: BlockType): Promise;
- /**
- * Returns information about a block by hash.
- */
- getBlockByHash(hash: Hash, includeTransactions?: boolean): Promise;
- /**
- * Returns information about a block by block number.
- */
- getBlockByNumber(block?: BlockType, includeTransactions?: boolean): Promise;
- /**
- * Returns the number of transactions in a block from a block matching the given block hash.
- */
- getBlockTransactionCountByHash(block: Hash): Promise;
- /**
- * Returns the number of transactions in a block from a block matching the given block number.
- */
- getBlockTransactionCountByNumber(block: Hash): Promise;
- /**
- * Polling method for a filter, which returns an array of logs which occurred since last poll.
- */
- getFilterChanges(id: Quantity): Promise;
- /**
- * Returns an array of all logs matching filter with given id.
- */
- getFilterLogs(id: Quantity): Promise;
- /**
- * Returns an array of all logs matching a given filter object.
- */
- getLogs(filter: LogFilter): Promise;
- /**
- * Returns information about a transaction by block hash and transaction index position.
- */
- getTransactionByBlockHashAndIndex(hash: Hash, pos: Quantity): Promise;
- /**
- * Returns information about a transaction by block number and transaction index position.
- */
- getTransactionByBlockNumberAndIndex(block: BlockType, pos: Quantity): Promise;
- /**
- * Returns the information about a transaction requested by transaction hash.
- */
- getTransactionByHash(hash: Hash): Promise;
- /**
- * Returns the number of transactions sent from an address. (as number)
- */
- getTransactionCount(address: Address, block?: BlockType): Promise;
- /**
- * Returns the receipt of a transaction by transaction hash.
- * Note That the receipt is available even for pending transactions.
- */
- getTransactionReceipt(hash: Hash): Promise;
- /**
- * Returns information about a uncle of a block by hash and uncle index position.
- * Note: An uncle doesn’t contain individual transactions.
- */
- getUncleByBlockHashAndIndex(hash: Hash, pos: Quantity): Promise;
- /**
- * Returns information about a uncle of a block number and uncle index position.
- * Note: An uncle doesn’t contain individual transactions.
- */
- getUncleByBlockNumberAndIndex(block: BlockType, pos: Quantity): Promise;
- /**
- * Returns the number of uncles in a block from a block matching the given block hash.
- */
- getUncleCountByBlockHash(hash: Hash): Promise;
- /**
- * Returns the number of uncles in a block from a block matching the given block hash.
- */
- getUncleCountByBlockNumber(block: BlockType): Promise;
- /**
- * Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.
- */
- newBlockFilter(): Promise;
- /**
- * Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.
- *
- * A note on specifying topic filters:
- * Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:
- *
- * [] “anything”
- * [A] “A in first position (and anything after)”
- * [null, B] “anything in first position AND B in second position (and anything after)”
- * [A, B] “A in first position AND B in second position (and anything after)”
- * [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)”
- */
- newFilter(filter: LogFilter): Promise;
- /**
- * Creates a filter in the node, to notify when new pending transactions arrive.
- *
- * To check if the state has changed, call eth_getFilterChanges.
- */
- newPendingTransactionFilter(): Promise;
- /**
- * Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with eth_getFilterChanges for a period of time.
- */
- uninstallFilter(id: Quantity): Promise;
- /**
- * Returns the current ethereum protocol version.
- */
- protocolVersion(): Promise;
- /**
- * Returns the current ethereum protocol version.
- */
- syncing(): Promise;
-
- /**
- * resolves a name as an ENS-Domain.
- * @param name the domain name
- * @param type the type (currently only addr is supported)
- * @param registry optionally the address of the registry (default is the mainnet ens registry)
- */
- resolveENS(name: string, type: Address, registry?: string): Promise;
-
- /**
- * Creates new message call transaction or a contract creation for signed transactions.
- */
- sendRawTransaction(data: Data): Promise;
- /**
- * signs any kind of message using the `\x19Ethereum Signed Message:\n`-prefix
- * @param account the address to sign the message with (if this is a 32-bytes hex-string it will be used as private key)
- * @param data the data to sign (Buffer, hexstring or utf8-string)
- */
- sign(account: Address, data: Data): Promise;
- /** sends a Transaction */
- sendTransaction(args: TxRequest): Promise;
-
-
-
- web3ContractAt(abi: ABI[], address?: Address, options?: {
- gasPrice?: string | number | bigint,
- gas?: string | number | bigint,
- from?: Address,
- data?: Hex
- }): {
- options: {
- address: Address,
- jsonInterface: ABI[],
- gasPrice?: string | number | bigint,
- gas?: string | number | bigint,
- from?: Address,
- data?: Hex,
- transactionConfirmationBlocks: number,
- transactionPollingTimeout: number
- },
- methods: {
- [methodName: string]: (...args: any) => {
- call: (options?: {
- gasPrice?: string | number | bigint,
- gas?: string | number | bigint,
- from?: Address,
- }) => Promise,
- send: (options?: {
- gasPrice?: string | number | bigint,
- gas?: string | number | bigint,
- from?: Address,
- value?: number | string | bigint
- }) => Promise,
- estimateGas: (options?: {
- value?: string | number | bigint,
- gas?: string | number | bigint,
- from?: Address,
- }) => Promise,
- encodeABI: () => Hex
- }
- },
-
- once: (eventName: string, options: {}, handler: (error?: Error, evData?: Web3Event) => void) => void,
-
- events: {
- [eventName: string]: (options?: {
- fromBlock?: number,
- topics?: any[],
- filter?: { [indexedName: string]: any }
- }) => {
- on: (ev: 'data' | 'error', handler: (ev: Web3Event | Error) => void) => any
- once: (ev: 'data', handler: (ev: Web3Event) => void) => any
- off: (ev: string, handler: (ev: any) => void) => any
- }
- },
-
- getPastEvents(evName: string, options?: {
- fromBlock?: number,
- topics?: any[],
- filter?: { [indexedName: string]: any }
- }): Promise
-
- }
-
- contractAt(abi: ABI[], address?: Address): {
- [methodName: string]: any;
- _address: Address;
- _eventHashes: any;
- events: {
- [event: string]: {
- getLogs: (options: {
- limit?: number;
- fromBlock?: BlockType;
- toBlock?: BlockType;
- topics?: any[];
- filter?: {
- [key: string]: any;
- };
- }) => Promise<{
- [key: string]: any;
- event: string;
- log: Log;
- }[]>;
- };
- all: {
- getLogs: (options: {
- limit?: number;
- fromBlock?: BlockType;
- toBlock?: BlockType;
- topics?: any[];
- filter?: {
- [key: string]: any;
- };
- }) => Promise<{
- [key: string]: any;
- event: string;
- log: Log;
- }[]>;
- };
- decode: any;
- };
- _abi: ABI[];
- _in3: IN3Generic;
- };
- decodeEventData(log: Log, d: ABI): any;
- hashMessage(data: Data): Hex;
-}
export declare class SimpleSigner implements Signer {
accounts: {
[ac: string]: BufferType;
@@ -1200,193 +753,4 @@ export declare interface Utils {
private2address(pk: Hex | BufferType): Address
}
-/**
- * API for storing and retrieving IPFS-data.
- */
-export declare interface IpfsAPI {
- /**
- * retrieves the content for a hash from IPFS.
- * @param multihash the IPFS-hash to fetch
- *
- */
- get(multihash: string): Promise
- /**
- * stores the data on ipfs and returns the IPFS-Hash.
- * @param content puts a IPFS content
- */
- put(content: BufferType): Promise
-}
-
-/**
- * a Input of a Bitcoin Transaction
- */
-export declare interface BtcTransactionInput {
- /** the transaction id */
- txid: Hash
-
- /** the index of the transactionoutput */
- vout: number
-
- /** the script */
- scriptSig: {
- /** the asm data */
- asm: Data
-
- /** the raw hex data */
- hex: Data
- }
-
- /** The script sequence number */
- sequence: number
-
- /** hex-encoded witness data (if any) */
- txinwitness: Data[]
-}
-/**
- * a Input of a Bitcoin Transaction
- */
-export declare interface BtcTransactionOutput {
- /** the value in BTC */
- value: number
-
- /** the index */
- n: number
-
- /** the index of the transactionoutput */
- vout: number
-
- /** the script */
- scriptPubKey: {
- /** the asm data */
- asm: Data
-
- /** the raw hex data */
- hex: Data
-
- /** the required sigs */
- reqSigs: number
-
- /** The type, eg 'pubkeyhash' */
- type: string
-
- /** list of addresses */
- addresses: Address[]
- }
-}
-
-/**
- * a BitCoin Transaction.
- */
-export declare interface BtcTransaction {
- /** true if this transaction is part of the longest chain */
- in_active_chain: boolean
-
- /** the hex representation of raw data*/
- hex: Data
-
- /** The requested transaction id. */
- txid: Hash
-
- /** The transaction hash (differs from txid for witness transactions) */
- hash: Hash
-
- /** The serialized transaction size */
- size: number
-
- /** The virtual transaction size (differs from size for witness transactions) */
- vsize: number
- /** The transaction’s weight (between vsize4-3 and vsize4) */
- weight: number
-
- /** The version */
- version: number
-
- /** The locktime */
- locktime: number
-
- /** the block hash of the block containing this transaction. */
- blockhash: Hash
-
- /** The confirmations. */
- confirmations: number
-
- /** The transaction time in seconds since epoch (Jan 1 1970 GMT) */
- time: number
-
- /** The block time in seconds since epoch (Jan 1 1970 GMT) */
- blocktime: number
-
- /** the transaction inputs */
- vin: BtcTransactionInput[]
-
- /** the transaction outputs */
- vout: BtcTransactionOutput[]
-
-}
-/** a Block header */
-export interface BTCBlockHeader {
- /** the hash of the blockheader */
- hash: string,
- /** number of confirmations or blocks mined on top of the containing block*/
- confirmations: number,
- /** block number */
- height: number,
- /** used version */
- version: number,
- /** version as hex */
- versionHex: string,
- /** merkle root of the trie of all transactions in the block */
- merkleroot: string,
- /** unix timestamp in seconds since 1970 */
- time: string,
- /** unix timestamp in seconds since 1970 */
- mediantime: string,
- /** nonce-field of the block */
- nonce: number,
- /** bits (target) for the block as hex*/
- bits: string,
- /** difficulty of the block */
- difficulty: number,
- /** total amount of work since genesis */
- chainwork: string,
- /** number of transactions in the block */
- nTx: number,
- /** hash of the parent blockheader */
- previousblockhash: string,
- /** hash of the next blockheader */
- nextblockhash: string
-}
-
-/** a full Block including the transactions */
-export interface BTCBlock extends BTCBlockHeader {
- /** the transactions */
- tx: T[]
-}
-
-
-/**
- * API for handling BitCoin data
- */
-export declare interface BtcAPI {
- /** retrieves the transaction and returns the data as json. */
- getTransaction(txid: Hash): Promise
-
- /** retrieves the serialized transaction (bytes) */
- getTransactionBytes(txid: Hash): Promise
-
- /** retrieves the blockheader and returns the data as json. */
- getBlockHeader(blockHash: Hash): Promise
-
- /** retrieves the serialized blockheader (bytes) */
- getBlockHeaderBytes(blockHash: Hash): Promise
-
- /** retrieves the block including all tx data as json. */
- getBlockWithTxData(blockHash: Hash): Promise>
-
- /** retrieves the block including all tx ids as json. */
- getBlockWithTxIds(blockHash: Hash): Promise>
-
- /** retrieves the serialized block (bytes) including all transactions */
- getBlockBytes(blockHash: Hash): Promise
-}
diff --git a/wasm/src/in3.js b/wasm/src/in3.js
index db4395780..017f4aa4e 100644
--- a/wasm/src/in3.js
+++ b/wasm/src/in3.js
@@ -123,11 +123,15 @@ function getVersion() {
}
// keep track of all created client instances
-const clients = {}
+const clients = in3w.clients = {}
+in3w.promises = {}
+in3w.promiseCount = 0;
+in3w.extensions = []
// create a flag indicating when the wasm was succesfully loaded.
let _in3_listeners = []
in3w.onRuntimeInitialized = _ => {
+ in3w.ccall('wasm_init', 'void', [], []);
const o = _in3_listeners
_in3_listeners = undefined
o.forEach(_ => _(true))
@@ -157,6 +161,7 @@ class IN3 {
if (chainId === 'ewc') chainId = '0xf6'
this.ptr = in3w.ccall('in3_create', 'number', ['number'], [parseInt(chainId) || 0]);
clients['' + this.ptr] = this
+ this.plugins.forEach(_ => this.registerPlugin(_))
}
// here we are creating the instance lazy, when the first function is called.
@@ -165,9 +170,8 @@ class IN3 {
this.config = config ? { ...def, ...config } : def
this.needsSetConfig = !!config
this.ptr = 0;
- this.eth = new EthAPI(this)
- this.ipfs = new IpfsAPI(this)
- this.btc = new BtcAPI(this)
+ in3w.extensions.forEach(_ => _(this))
+ this.plugins = []
}
/**
@@ -181,6 +185,10 @@ class IN3 {
}
this.needsSetConfig = !this.ptr
if (this.ptr) {
+ if (this.config.transport) {
+ this.transport = this.config.transport
+ delete this.config.transport
+ }
const r = in3w.ccall('in3_config', 'number', ['number', 'string'], [this.ptr, JSON.stringify(this.config)]);
if (r) {
const ex = new Error(UTF8ToString(r))
@@ -204,6 +212,25 @@ class IN3 {
return p
}
+ registerPlugin(plgn) {
+ let action = 0
+ if (plgn.term) action |= 0x2
+ if (plgn.getAccount) action |= 0x20
+ if (plgn.handleRPC) action |= 0x100
+ if (plgn.verifyRPC) action |= 0x200
+ if (plgn.cacheGet) action |= 0x800
+ if (plgn.cacheSet) action |= 0x400
+ if (plgn.cacheClear) action |= 0x1000
+ let index = this.plugins.indexOf(plgn)
+ if (index == -1) {
+ index = this.plugins.length
+ this.plugins.push(plgn)
+ }
+
+ if (this.ptr)
+ in3w.ccall('wasm_register_plugin', 'number', ['number', 'number', 'number'], [this.ptr, action, index]);
+ }
+
/**
* sends a request and returns the response.
@@ -232,7 +259,14 @@ class IN3 {
// main async loop
// we repeat it until we have a result
while (this.ptr && !this.delayFree) {
- const state = JSON.parse(call_string('ctx_execute', r).replace(/\n/g, ' > '))
+ const js = call_string('ctx_execute', r).replace(/\n/g, ' > ')
+ let state;
+ try {
+ state = JSON.parse(js)
+ }
+ catch (x) {
+ throw new Error("Invalid json:", js)
+ }
switch (state.status) {
case 'error':
throw new Error(state.error || 'Unknown error')
@@ -262,7 +296,10 @@ class IN3 {
case 'rpc':
if (req.wait) await new Promise(r => setTimeout(r, req.wait))
- await getNextResponse(responses, req)
+ if (req.urls[0].startsWith("promise://"))
+ await resolvePromises(req.ctx, req.urls[0])
+ else
+ await getNextResponse(responses, req)
}
}
@@ -283,7 +320,7 @@ class IN3 {
}
- async sendRPC(method, params) {
+ async sendRPC(method, params = []) {
const res = await this.sendRequest({ method, params })
if (res.error) throw new Error(res.error.message || res.error)
return res.result
@@ -295,13 +332,25 @@ class IN3 {
if (this.pending)
this.delayFree = true
else if (this.ptr) {
- delete clients['' + this.ptr]
in3w.ccall('in3_dispose', 'void', ['number'], [this.ptr])
+ delete clients['' + this.ptr]
this.ptr = 0
}
}
}
+async function resolvePromises(ctx, url) {
+ const pid = url.substr(10)
+ const p = in3w.promises[pid]
+ if (!p)
+ setResponse(ctx, JSON.stringify({ error: { message: 'could not find the requested proomise' } }), 0, false)
+ else {
+ delete in3w.promises[pid]
+ return p
+ .then(r => setResponse(ctx, JSON.stringify({ result: r }), 0, false))
+ .catch(e => setResponse(ctx, JSON.stringify({ error: { message: e.message || e } }), 0, false))
+ }
+}
function cleanUpResponses(responses, ptr) {
Object.keys(responses).forEach(ctx => responses[ctx].cleanUp(ptr))
@@ -316,7 +365,8 @@ function url_queue(req) {
let counter = 0
const promises = [], responses = []
if (req.in3.config.debug) console.log("send req (" + req.ctx + ") to " + req.urls.join() + ' : ', JSON.stringify(req.payload, null, 2))
- req.urls.forEach((url, i) => in3w.transport(url, JSON.stringify(req.payload), req.timeout || 30000).then(
+ const transport = req.in3.transport || in3w.transport
+ req.urls.forEach((url, i) => transport(url, JSON.stringify(req.payload), req.timeout || 30000).then(
response => { responses.push({ i, url, response }); trigger() },
error => { responses.push({ i, url, error }); trigger() }
))
@@ -444,4 +494,5 @@ function setResponse(ctx, msg, i, isError) {
function check_ready() {
if (_in3_listeners) throw new Error('The Incubed wasm runtime is not initialized yet! Please use onInit() to execute it when ready.')
-}
\ No newline at end of file
+}
+
diff --git a/wasm/src/in3_util.js b/wasm/src/in3_util.js
index d0f3d33dd..df15bff91 100644
--- a/wasm/src/in3_util.js
+++ b/wasm/src/in3_util.js
@@ -408,20 +408,19 @@ function padEnd(val, minLength, fill = ' ') {
}
function soliditySha3(...args) {
-
- const abiCoder = new AbiCoder()
- return toHex(keccak(abiCoder.encode(args.map(_ => {
+ return toHex(keccak('0x' + toHex(abiEncode('_(' + args.map(_ => {
switch (typeof (_)) {
case 'number':
+ case 'bigint':
return _ < 0 ? 'int256' : 'uint256'
case 'string':
return _.substr(0, 2) === '0x' ? 'bytes' : 'string'
case 'boolean':
return 'bool'
default:
- return BN.isBN(_) ? 'uint256' : 'bytes'
+ return 'bytes'
}
- }), args.map(encodeEtheresBN))))
+ }).join() + ')', args)).substr(10)))
}
function createSignatureHash(def) {
diff --git a/wasm/src/modules/btc.d.ts b/wasm/src/modules/btc.d.ts
new file mode 100644
index 000000000..3b4ff3265
--- /dev/null
+++ b/wasm/src/modules/btc.d.ts
@@ -0,0 +1,194 @@
+
+/**
+ * a Input of a Bitcoin Transaction
+ */
+export declare interface BtcTransactionInput {
+ /** the transaction id */
+ txid: Hash
+
+ /** the index of the transactionoutput */
+ vout: number
+
+ /** the script */
+ scriptSig: {
+ /** the asm data */
+ asm: Data
+
+ /** the raw hex data */
+ hex: Data
+ }
+
+ /** The script sequence number */
+ sequence: number
+
+ /** hex-encoded witness data (if any) */
+ txinwitness: Data[]
+}
+/**
+ * a Input of a Bitcoin Transaction
+ */
+export declare interface BtcTransactionOutput {
+ /** the value in BTC */
+ value: number
+
+ /** the index */
+ n: number
+
+ /** the index of the transactionoutput */
+ vout: number
+
+ /** the script */
+ scriptPubKey: {
+ /** the asm data */
+ asm: Data
+
+ /** the raw hex data */
+ hex: Data
+
+ /** the required sigs */
+ reqSigs: number
+
+ /** The type, eg 'pubkeyhash' */
+ type: string
+
+ /** list of addresses */
+ addresses: Address[]
+ }
+}
+
+/**
+ * a BitCoin Transaction.
+ */
+export declare interface BtcTransaction {
+ /** true if this transaction is part of the longest chain */
+ in_active_chain: boolean
+
+ /** the hex representation of raw data*/
+ hex: Data
+
+ /** The requested transaction id. */
+ txid: Hash
+
+ /** The transaction hash (differs from txid for witness transactions) */
+ hash: Hash
+
+ /** The serialized transaction size */
+ size: number
+
+ /** The virtual transaction size (differs from size for witness transactions) */
+ vsize: number
+
+ /** The transaction’s weight (between vsize4-3 and vsize4) */
+ weight: number
+
+ /** The version */
+ version: number
+
+ /** The locktime */
+ locktime: number
+
+ /** the block hash of the block containing this transaction. */
+ blockhash: Hash
+
+ /** The confirmations. */
+ confirmations: number
+
+ /** The transaction time in seconds since epoch (Jan 1 1970 GMT) */
+ time: number
+
+ /** The block time in seconds since epoch (Jan 1 1970 GMT) */
+ blocktime: number
+
+ /** the transaction inputs */
+ vin: BtcTransactionInput[]
+
+ /** the transaction outputs */
+ vout: BtcTransactionOutput[]
+
+}
+/** a Block header */
+export interface BTCBlockHeader {
+ /** the hash of the blockheader */
+ hash: string,
+ /** number of confirmations or blocks mined on top of the containing block*/
+ confirmations: number,
+ /** block number */
+ height: number,
+ /** used version */
+ version: number,
+ /** version as hex */
+ versionHex: string,
+ /** merkle root of the trie of all transactions in the block */
+ merkleroot: string,
+ /** unix timestamp in seconds since 1970 */
+ time: string,
+ /** unix timestamp in seconds since 1970 */
+ mediantime: string,
+ /** nonce-field of the block */
+ nonce: number,
+ /** bits (target) for the block as hex*/
+ bits: string,
+ /** difficulty of the block */
+ difficulty: number,
+ /** total amount of work since genesis */
+ chainwork: string,
+ /** number of transactions in the block */
+ nTx: number,
+ /** hash of the parent blockheader */
+ previousblockhash: string,
+ /** hash of the next blockheader */
+ nextblockhash: string
+}
+
+/** a full Block including the transactions */
+export interface BTCBlock extends BTCBlockHeader {
+ /** the transactions */
+ tx: T[]
+}
+
+
+/**
+ * API for handling BitCoin data
+ */
+export declare interface BtcAPI {
+ /** retrieves the transaction and returns the data as json. */
+ getTransaction(txid: Hash): Promise
+
+ /** retrieves the serialized transaction (bytes) */
+ getTransactionBytes(txid: Hash): Promise
+
+ /** retrieves the blockheader and returns the data as json. */
+ getBlockHeader(blockHash: Hash): Promise
+
+ /** retrieves the serialized blockheader (bytes) */
+ getBlockHeaderBytes(blockHash: Hash): Promise
+
+ /** retrieves the block including all tx data as json. */
+ getBlockWithTxData(blockHash: Hash): Promise>
+
+ /** retrieves the block including all tx ids as json. */
+ getBlockWithTxIds(blockHash: Hash): Promise>
+
+ /** retrieves the serialized block (bytes) including all transactions */
+ getBlockBytes(blockHash: Hash): Promise
+}
+
+/**
+ * bitcoin configuration.
+ */
+export declare interface btc_config {
+ /**
+ * max number of DAPs (Difficulty Adjustment Periods) allowed when accepting new targets.
+ */
+ maxDAP?: number
+
+ /**
+ * max increase (in percent) of the difference between targets when accepting new targets.
+ */
+ maxDiff?: number
+
+}
+
+/*
+public btc:BtcAPI
+ */
\ No newline at end of file
diff --git a/wasm/src/in3_btc_api.js b/wasm/src/modules/btc.js
similarity index 97%
rename from wasm/src/in3_btc_api.js
rename to wasm/src/modules/btc.js
index 3c330ad9c..d66ae0ec0 100644
--- a/wasm/src/in3_btc_api.js
+++ b/wasm/src/modules/btc.js
@@ -1,3 +1,5 @@
+in3w.extensions.push(c => c.btc = new BtcAPI(c))
+
class BtcAPI {
constructor(client) {
this.client = client
diff --git a/wasm/src/modules/eth.d.ts b/wasm/src/modules/eth.d.ts
new file mode 100644
index 000000000..e63fdb48d
--- /dev/null
+++ b/wasm/src/modules/eth.d.ts
@@ -0,0 +1,485 @@
+export type TransactionReceipt = {
+ /** 32 Bytes - hash of the block where this transaction was in. */
+ blockHash: Hash
+ /** block number where this transaction was in.*/
+ blockNumber: BlockType
+ /** 20 Bytes - The contract address created, if the transaction was a contract creation, otherwise null.*/
+ contractAddress: Address
+ /** The total amount of gas used when this transaction was executed in the block. */
+ cumulativeGasUsed: Quantity
+ /** 20 Bytes - The address of the sender. */
+ from: Address
+ /** 20 Bytes - The address of the receiver. null when it’s a contract creation transaction.*/
+ to: Address
+ /** The amount of gas used by this specific transaction alone. */
+ gasUsed: Quantity
+ /** Array of log objects, which this transaction generated. */
+ logs: Log[]
+ /** 256 Bytes - A bloom filter of logs/events generated by contracts during transaction execution. Used to efficiently rule out transactions without expected logs.*/
+ logsBloom: Data
+ /** 32 Bytes - Merkle root of the state trie after the transaction has been executed (optional after Byzantium hard fork EIP609)*/
+ root: Hash
+ /** 0x0 indicates transaction failure , 0x1 indicates transaction success. Set for blocks mined after Byzantium hard fork EIP609, null before. */
+ status: Quantity
+ /** 32 Bytes - hash of the transaction. */
+ transactionHash: Hash
+ /** Integer of the transactions index position in the block. */
+ transactionIndex: Quantity
+}
+export type TransactionDetail = {
+ /** 32 Bytes - hash of the transaction. */
+ hash: Hash
+ /** the number of transactions made by the sender prior to this one.*/
+ nonce: Quantity
+ /** 32 Bytes - hash of the block where this transaction was in. null when its pending.*/
+ blockHash: Hash
+ /** block number where this transaction was in. null when its pending.*/
+ blockNumber: BlockType
+ /** integer of the transactions index position in the block. null when its pending.*/
+ transactionIndex: Quantity
+ /** 20 Bytes - address of the sender.*/
+ from: Address
+ /** 20 Bytes - address of the receiver. null when its a contract creation transaction. */
+ to: Address
+ /** value transferred in Wei.*/
+ value: Quantity
+ /** gas price provided by the sender in Wei.*/
+ gasPrice: Quantity
+ /** gas provided by the sender. */
+ gas: Quantity
+ /** the data send along with the transaction. */
+ input: Data
+ /** the standardised V field of the signature.*/
+ v: Quantity
+ /** the standardised V field of the signature (0 or 1).*/
+ standardV: Quantity
+ /** the R field of the signature.*/
+ r: Quantity
+ /** raw transaction data */
+ raw: Data
+ /** public key of the signer. */
+ publicKey: Hash
+ /** the chain id of the transaction, if any. */
+ chainId: Quantity
+ /** creates contract address */
+ creates: Address
+ /** (optional) conditional submission, Block number in block or timestamp in time or null. (parity-feature) */
+ condition: any
+ /** optional: the private key to use for signing */
+ pk?: any
+}
+
+export type Block = {
+ /** The block number. null when its pending block */
+ number: Quantity
+ /** hash of the block. null when its pending block */
+ hash: Hash
+ /** hash of the parent block */
+ parentHash: Hash
+ /** 8 bytes hash of the generated proof-of-work. null when its pending block. Missing in case of PoA. */
+ nonce: Data
+ /** SHA3 of the uncles data in the block */
+ sha3Uncles: Data
+ /** 256 Bytes - the bloom filter for the logs of the block. null when its pending block */
+ logsBloom: Data
+ /** 32 Bytes - the root of the transaction trie of the block */
+ transactionsRoot: Data
+ /** 32 Bytes - the root of the final state trie of the block */
+ stateRoot: Data
+ /** 32 Bytes - the root of the receipts trie of the block */
+ receiptsRoot: Data
+ /** 20 Bytes - the address of the author of the block (the beneficiary to whom the mining rewards were given)*/
+ author: Address
+ /** 20 Bytes - alias of ‘author’*/
+ miner: Address
+ /** integer of the difficulty for this block */
+ difficulty: Quantity
+ /** integer of the total difficulty of the chain until this block */
+ totalDifficulty: Quantity
+ /** the ‘extra data’ field of this block */
+ extraData: Data
+ /** integer the size of this block in bytes */
+ size: Quantity
+ /** the maximum gas allowed in this block */
+ gasLimit: Quantity
+ /** the total used gas by all transactions in this block */
+ gasUsed: Quantity
+ /** the unix timestamp for when the block was collated */
+ timestamp: Quantity
+ /** Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter */
+ transactions: (Hash | Transaction)[]
+ /** Array of uncle hashes */
+ uncles: Hash[]
+ /** PoA-Fields */
+ sealFields: Data[]
+}
+export type Log = {
+ /** true when the log was removed, due to a chain reorganization. false if its a valid log. */
+ removed: boolean
+ /** integer of the log index position in the block. null when its pending log. */
+ logIndex: Quantity
+ /** integer of the transactions index position log was created from. null when its pending log. */
+ transactionIndex: Quantity
+ /** Hash, 32 Bytes - hash of the transactions this log was created from. null when its pending log. */
+ transactionHash: Hash
+ /** Hash, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log. */
+ blockHash: Hash,
+ /** the block number where this log was in. null when its pending. null when its pending log. */
+ blockNumber: Quantity
+ /** 20 Bytes - address from which this log originated. */
+ address: Address,
+ /** contains the non-indexed arguments of the log. */
+ data: Data
+ /** - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.) */
+ topics: Data[]
+}
+
+export type LogFilter = {
+ /** Quantity or Tag - (optional) (default: latest) Integer block number, or 'latest' for the last mined block or 'pending', 'earliest' for not yet mined transactions. */
+ fromBlock: BlockType
+ /** Quantity or Tag - (optional) (default: latest) Integer block number, or 'latest' for the last mined block or 'pending', 'earliest' for not yet mined transactions.*/
+ toBlock: BlockType
+ /** (optional) 20 Bytes - Contract address or a list of addresses from which logs should originate.*/
+ address: Address
+ /** (optional) Array of 32 Bytes Data topics. Topics are order-dependent. It’s possible to pass in null to match any topic, or a subarray of multiple topics of which one should be matching. */
+ topics: (string | string[])[]
+ /** å(optional) The maximum number of entries to retrieve (latest first). */
+ limit: Quantity
+}
+
+export type TxRequest = {
+ /** contract */
+ to?: Address
+
+ /** address of the account to use */
+ from?: Address
+
+ /** the data to send */
+ data?: Data
+
+ /** the gas needed */
+ gas?: number
+
+ /** the gasPrice used */
+ gasPrice?: number
+
+ /** the nonce */
+ nonce?: number
+
+ /** the value in wei */
+ value?: Quantity
+
+ /** the ABI of the method to be used */
+ method?: string
+
+ /** the argument to pass to the method */
+ args?: any[]
+
+ /**raw private key in order to sign */
+ pk?: Hash
+
+ /** number of block to wait before confirming*/
+ confirmations?: number
+
+ /** number of seconds to wait for confirmations before giving up. Default: 10 */
+ timeout?: number
+}
+
+export interface Web3Event {
+ returnValues: {
+ [name: string]: any
+ },
+ event: string,
+ signature: string,
+ logIndex: number
+ transactionIndex: number,
+ transactionHash: Hash,
+ address: Address
+ blockNumber: number
+ blockHash: Hash,
+ raw: {
+ data: Hex
+ topicx: Hash[]
+ }
+
+
+}
+
+
+
+export interface EthAPI {
+ client: IN3Generic;
+ signer?: Signer;
+ constructor(client: IN3Generic);
+ /**
+ * Returns the number of most recent block. (as number)
+ */
+ blockNumber(): Promise;
+ /**
+ * Returns the current price per gas in wei. (as number)
+ */
+ gasPrice(): Promise;
+ /**
+ * Executes a new message call immediately without creating a transaction on the block chain.
+ */
+ call(tx: Transaction, block?: BlockType): Promise;
+ /**
+ * Executes a function of a contract, by passing a [method-signature](https://github.com/ethereumjs/ethereumjs-abi/blob/master/README.md#simple-encoding-and-decoding) and the arguments, which will then be ABI-encoded and send as eth_call.
+ */
+ callFn(to: Address, method: string, ...args: any[]): Promise;
+ /**
+ * Returns the EIP155 chain ID used for transaction signing at the current best block. Null is returned if not available.
+ */
+ chainId(): Promise;
+ /**
+ * Makes a call or transaction, which won’t be added to the blockchain and returns the used gas, which can be used for estimating the used gas.
+ */
+ estimateGas(tx: Transaction): Promise;
+ /**
+ * Returns the balance of the account of given address in wei (as hex).
+ */
+ getBalance(address: Address, block?: BlockType): Promise;
+ /**
+ * Returns code at a given address.
+ */
+ getCode(address: Address, block?: BlockType): Promise;
+ /**
+ * Returns the value from a storage position at a given address.
+ */
+ getStorageAt(address: Address, pos: Quantity, block?: BlockType): Promise;
+ /**
+ * Returns information about a block by hash.
+ */
+ getBlockByHash(hash: Hash, includeTransactions?: boolean): Promise;
+ /**
+ * Returns information about a block by block number.
+ */
+ getBlockByNumber(block?: BlockType, includeTransactions?: boolean): Promise;
+ /**
+ * Returns the number of transactions in a block from a block matching the given block hash.
+ */
+ getBlockTransactionCountByHash(block: Hash): Promise;
+ /**
+ * Returns the number of transactions in a block from a block matching the given block number.
+ */
+ getBlockTransactionCountByNumber(block: Hash): Promise;
+ /**
+ * Polling method for a filter, which returns an array of logs which occurred since last poll.
+ */
+ getFilterChanges(id: Quantity): Promise;
+ /**
+ * Returns an array of all logs matching filter with given id.
+ */
+ getFilterLogs(id: Quantity): Promise;
+ /**
+ * Returns an array of all logs matching a given filter object.
+ */
+ getLogs(filter: LogFilter): Promise;
+ /**
+ * Returns information about a transaction by block hash and transaction index position.
+ */
+ getTransactionByBlockHashAndIndex(hash: Hash, pos: Quantity): Promise;
+ /**
+ * Returns information about a transaction by block number and transaction index position.
+ */
+ getTransactionByBlockNumberAndIndex(block: BlockType, pos: Quantity): Promise;
+ /**
+ * Returns the information about a transaction requested by transaction hash.
+ */
+ getTransactionByHash(hash: Hash): Promise;
+ /**
+ * Returns the number of transactions sent from an address. (as number)
+ */
+ getTransactionCount(address: Address, block?: BlockType): Promise;
+ /**
+ * Returns the receipt of a transaction by transaction hash.
+ * Note That the receipt is available even for pending transactions.
+ */
+ getTransactionReceipt(hash: Hash): Promise;
+ /**
+ * Returns information about a uncle of a block by hash and uncle index position.
+ * Note: An uncle doesn’t contain individual transactions.
+ */
+ getUncleByBlockHashAndIndex(hash: Hash, pos: Quantity): Promise;
+ /**
+ * Returns information about a uncle of a block number and uncle index position.
+ * Note: An uncle doesn’t contain individual transactions.
+ */
+ getUncleByBlockNumberAndIndex(block: BlockType, pos: Quantity): Promise;
+ /**
+ * Returns the number of uncles in a block from a block matching the given block hash.
+ */
+ getUncleCountByBlockHash(hash: Hash): Promise;
+ /**
+ * Returns the number of uncles in a block from a block matching the given block hash.
+ */
+ getUncleCountByBlockNumber(block: BlockType): Promise;
+ /**
+ * Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.
+ */
+ newBlockFilter(): Promise;
+ /**
+ * Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.
+ *
+ * A note on specifying topic filters:
+ * Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters:
+ *
+ * [] “anything”
+ * [A] “A in first position (and anything after)”
+ * [null, B] “anything in first position AND B in second position (and anything after)”
+ * [A, B] “A in first position AND B in second position (and anything after)”
+ * [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)”
+ */
+ newFilter(filter: LogFilter): Promise;
+ /**
+ * Creates a filter in the node, to notify when new pending transactions arrive.
+ *
+ * To check if the state has changed, call eth_getFilterChanges.
+ */
+ newPendingTransactionFilter(): Promise;
+ /**
+ * Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with eth_getFilterChanges for a period of time.
+ */
+ uninstallFilter(id: Quantity): Promise;
+ /**
+ * Returns the current ethereum protocol version.
+ */
+ protocolVersion(): Promise;
+ /**
+ * Returns the current ethereum protocol version.
+ */
+ syncing(): Promise;
+
+ /**
+ * resolves a name as an ENS-Domain.
+ * @param name the domain name
+ * @param type the type (currently only addr is supported)
+ * @param registry optionally the address of the registry (default is the mainnet ens registry)
+ */
+ resolveENS(name: string, type: Address, registry?: string): Promise;
+
+ /**
+ * Creates new message call transaction or a contract creation for signed transactions.
+ */
+ sendRawTransaction(data: Data): Promise;
+ /**
+ * signs any kind of message using the `\x19Ethereum Signed Message:\n`-prefix
+ * @param account the address to sign the message with (if this is a 32-bytes hex-string it will be used as private key)
+ * @param data the data to sign (Buffer, hexstring or utf8-string)
+ */
+ sign(account: Address, data: Data): Promise;
+ /** sends a Transaction */
+ sendTransaction(args: TxRequest): Promise;
+
+
+
+ web3ContractAt(abi: ABI[], address?: Address, options?: {
+ gasPrice?: string | number | bigint,
+ gas?: string | number | bigint,
+ from?: Address,
+ data?: Hex
+ }): {
+ options: {
+ address: Address,
+ jsonInterface: ABI[],
+ gasPrice?: string | number | bigint,
+ gas?: string | number | bigint,
+ from?: Address,
+ data?: Hex,
+ transactionConfirmationBlocks: number,
+ transactionPollingTimeout: number
+ },
+ methods: {
+ [methodName: string]: (...args: any) => {
+ call: (options?: {
+ gasPrice?: string | number | bigint,
+ gas?: string | number | bigint,
+ from?: Address,
+ }) => Promise,
+ send: (options?: {
+ gasPrice?: string | number | bigint,
+ gas?: string | number | bigint,
+ from?: Address,
+ value?: number | string | bigint
+ }) => Promise,
+ estimateGas: (options?: {
+ value?: string | number | bigint,
+ gas?: string | number | bigint,
+ from?: Address,
+ }) => Promise,
+ encodeABI: () => Hex
+ }
+ },
+
+ once: (eventName: string, options: {}, handler: (error?: Error, evData?: Web3Event) => void) => void,
+
+ events: {
+ [eventName: string]: (options?: {
+ fromBlock?: number,
+ topics?: any[],
+ filter?: { [indexedName: string]: any }
+ }) => {
+ on: (ev: 'data' | 'error', handler: (ev: Web3Event | Error) => void) => any
+ once: (ev: 'data', handler: (ev: Web3Event) => void) => any
+ off: (ev: string, handler: (ev: any) => void) => any
+ }
+ },
+
+ getPastEvents(evName: string, options?: {
+ fromBlock?: number,
+ topics?: any[],
+ filter?: { [indexedName: string]: any }
+ }): Promise
+
+ }
+
+ contractAt(abi: ABI[], address?: Address): {
+ [methodName: string]: any;
+ _address: Address;
+ _eventHashes: any;
+ events: {
+ [event: string]: {
+ getLogs: (options: {
+ limit?: number;
+ fromBlock?: BlockType;
+ toBlock?: BlockType;
+ topics?: any[];
+ filter?: {
+ [key: string]: any;
+ };
+ }) => Promise<{
+ [key: string]: any;
+ event: string;
+ log: Log;
+ }[]>;
+ };
+ all: {
+ getLogs: (options: {
+ limit?: number;
+ fromBlock?: BlockType;
+ toBlock?: BlockType;
+ topics?: any[];
+ filter?: {
+ [key: string]: any;
+ };
+ }) => Promise<{
+ [key: string]: any;
+ event: string;
+ log: Log;
+ }[]>;
+ };
+ decode: any;
+ };
+ _abi: ABI[];
+ _in3: IN3Generic;
+ };
+ decodeEventData(log: Log, d: ABI): any;
+ hashMessage(data: Data): Hex;
+}
\ No newline at end of file
diff --git a/wasm/src/in3_eth_api.js b/wasm/src/modules/eth.js
similarity index 99%
rename from wasm/src/in3_eth_api.js
rename to wasm/src/modules/eth.js
index 5a07d2a93..19b0e42b9 100644
--- a/wasm/src/in3_eth_api.js
+++ b/wasm/src/modules/eth.js
@@ -1,3 +1,5 @@
+in3w.extensions.push(c => c.eth = new EthAPI(c))
+
class EthAPI {
constructor(client) { this.client = client }
@@ -443,9 +445,6 @@ class EthAPI {
}
-
-
-
contractAt(abi, address) {
const api = this, ob = { _address: address, _eventHashes: {}, events: {}, _abi: abi, _in3: this.client }
for (const def of abi.filter(_ => _.type == 'function')) {
diff --git a/wasm/src/modules/ipfs.d.ts b/wasm/src/modules/ipfs.d.ts
new file mode 100644
index 000000000..a1c0e1f38
--- /dev/null
+++ b/wasm/src/modules/ipfs.d.ts
@@ -0,0 +1,20 @@
+
+/**
+ * API for storing and retrieving IPFS-data.
+ */
+export declare interface IpfsAPI {
+ /**
+ * retrieves the content for a hash from IPFS.
+ * @param multihash the IPFS-hash to fetch
+ *
+ */
+ get(multihash: string): Promise
+ /**
+ * stores the data on ipfs and returns the IPFS-Hash.
+ * @param content puts a IPFS content
+ */
+ put(content: BufferType): Promise
+}
+/*
+public ipfs:IpfsAPI
+ */
\ No newline at end of file
diff --git a/wasm/src/in3_ipfs_api.js b/wasm/src/modules/ipfs.js
similarity index 94%
rename from wasm/src/in3_ipfs_api.js
rename to wasm/src/modules/ipfs.js
index f9f807285..526d3a219 100644
--- a/wasm/src/in3_ipfs_api.js
+++ b/wasm/src/modules/ipfs.js
@@ -1,3 +1,5 @@
+in3w.extensions.push(c => c.ipfs = new IpfsAPI(c))
+
class IpfsAPI {
constructor(client) {
this.client = client
diff --git a/wasm/src/modules/zksync.d.ts b/wasm/src/modules/zksync.d.ts
new file mode 100644
index 000000000..4e79ed2ed
--- /dev/null
+++ b/wasm/src/modules/zksync.d.ts
@@ -0,0 +1,28 @@
+
+/**
+ * API for zksync.
+ */
+export declare interface ZksyncAPI {
+}
+
+
+/**
+ * zksync configuration.
+ */
+export declare interface zksync_config {
+ /**
+ * max number of DAPs (Difficulty Adjustment Periods) allowed when accepting new targets.
+ */
+ maxDAP?: number
+
+ /**
+ * max increase (in percent) of the difference between targets when accepting new targets.
+ */
+ maxDiff?: number
+
+}
+
+
+/*
+public zksync:ZksyncAPI
+ */
\ No newline at end of file
diff --git a/wasm/src/modules/zksync.js b/wasm/src/modules/zksync.js
new file mode 100644
index 000000000..8e5af02ce
--- /dev/null
+++ b/wasm/src/modules/zksync.js
@@ -0,0 +1,8 @@
+in3w.extensions.push(c => c.zksync = new ZksyncAPI(c))
+
+class ZksyncAPI {
+ constructor(client) {
+ this.client = client
+ }
+
+}
\ No newline at end of file
diff --git a/wasm/src/wasm.c b/wasm/src/wasm.c
index 8e4e97947..e89923be8 100644
--- a/wasm/src/wasm.c
+++ b/wasm/src/wasm.c
@@ -32,10 +32,10 @@
* with this program. If not, see .
*******************************************************************************/
#include "../../c/src/core/client/cache.h"
-#include "../../c/src/core/client/client.h"
#include "../../c/src/core/client/context_internal.h"
#include "../../c/src/core/client/keys.h"
#include "../../c/src/core/client/nodelist.h"
+#include "../../c/src/core/client/plugin.h"
#include "../../c/src/core/client/version.h"
#include "../../c/src/core/util/mem.h"
#include "../../c/src/third-party/crypto/ecdsa.h"
@@ -95,6 +95,7 @@ EM_JS(void, in3_cache_set, (const char* key, char* val), {
Module.in3_cache.set(UTF8ToString(key),UTF8ToString(val));
})
+
char* EMSCRIPTEN_KEEPALIVE in3_version() {
return IN3_VERSION;
}
@@ -114,6 +115,82 @@ void storage_set_item(void* cptr, const char* key, bytes_t* content) {
in3_cache_set(key, buffer);
}
+EM_JS(int, plgn_exec_term, (in3_t * c, int index), {
+ var client = Module.clients[c];
+ var plgn = client && client.plugins[index];
+ if (!plgn) return -4;
+ return plgn.term(client) || 0;
+})
+
+EM_JS(int, plgn_exec_rpc_handle, (in3_t * c, in3_ctx_t* ctx, char* req, int index), {
+ var client = Module.clients[c];
+ var plgn = client && client.plugins[index];
+ if (!plgn) return -4;
+ try {
+ var json = JSON.parse(UTF8ToString(req));
+ var val = plgn.handleRPC(client, json);
+ if (typeof(val) == "undefined") return -17;
+ if (!val.then) val = Promise.resolve(val);
+ var id = ++in3w.promiseCount;
+ in3w.promises["" + id] = val;
+ json.in3 = {rpc : "promise://" + id};
+ in3w.ccall("wasm_set_request_ctx", "void", [ "number", "string" ], [ ctx, JSON.stringify(json) ]);
+ } catch (x) {
+ setResponse(ctx, JSON.stringify({error : {message : x.message || x}}), 0, false)
+ }
+ return 0;
+})
+
+/**
+ * the main plgn-function which is called for each js-plugin,
+ * delegating it depending on the action.
+ */
+in3_ret_t wasm_plgn(void* data, in3_plugin_act_t action, void* ctx) {
+ // we use the custom data pointer of the plugin as index within the clients plugin array
+ int index = (int) data;
+
+ switch (action) {
+ case PLGN_ACT_INIT: return IN3_OK;
+ case PLGN_ACT_TERM: return plgn_exec_term(ctx, index);
+ case PLGN_ACT_RPC_HANDLE: {
+ // extract the request as string, so we can pass it to js
+ in3_rpc_handle_ctx_t* rc = ctx;
+ str_range_t sr = d_to_json(rc->request);
+ char* req = alloca(sr.len + 1);
+ memcpy(req, sr.data, sr.len);
+ req[sr.len] = 0;
+ return plgn_exec_rpc_handle(rc->ctx->client, rc->ctx, req, index);
+ }
+ default: break;
+ }
+ return IN3_ENOTSUP;
+}
+
+void EMSCRIPTEN_KEEPALIVE wasm_register_plugin(in3_t* c, in3_plugin_act_t action, int index) {
+ // the index is used as the custom void* or data for the plugin.
+ // This way we can cast it backward in order doing the call to js to find the plugin
+ // if a js-plugin needs custom data, the it should do this in js withihn its own plugin object
+ in3_plugin_register(NULL, c, action, wasm_plgn, (void*) index, false);
+}
+
+/**
+ * repareses the request for the context with a new input.
+ */
+void EMSCRIPTEN_KEEPALIVE wasm_set_request_ctx(in3_ctx_t* ctx, char* req) {
+ if (!ctx->request_context) return;
+ char* src = ctx->request_context->c; // we keep the old pointer since this may be an internal request where this needs to be freed.
+ json_free(ctx->request_context); // throw away the old pares context
+ char* r = _strdupn(req, -1); // need to copy, because req is on the stack and the pointers of the tokens need to point to valid memory
+ ctx->request_context = parse_json(r); // parse the new
+ ctx->requests[0] = ctx->request_context->result; //since we don't support bulks in custom rpc, requests must be allocated with len=1
+ ctx->request_context->c = src; // set the old pointer, so the memory management will clean it correctly
+ in3_cache_add_ptr(&ctx->cache, r)->props = CACHE_PROP_MUST_FREE; // but add the copy to be cleaned when freeing ctx to avoid memory leaks.
+}
+
+/**
+ * main execute function which generates a json representing the status and all required data to be handled in js.
+ * The resulting string needs to be freed by the caller!
+ */
char* EMSCRIPTEN_KEEPALIVE ctx_execute(in3_ctx_t* ctx) {
in3_ctx_t* p = ctx;
in3_request_t* req = NULL;
@@ -179,6 +256,9 @@ char* EMSCRIPTEN_KEEPALIVE ctx_execute(in3_ctx_t* ctx) {
void EMSCRIPTEN_KEEPALIVE ifree(void* ptr) {
_free(ptr);
}
+void EMSCRIPTEN_KEEPALIVE wasm_init() {
+ in3_init();
+}
void* EMSCRIPTEN_KEEPALIVE imalloc(size_t size) {
return _malloc(size);
}
@@ -197,6 +277,7 @@ void EMSCRIPTEN_KEEPALIVE in3_blacklist(in3_t* in3, char* url) {
}
void EMSCRIPTEN_KEEPALIVE ctx_set_response(in3_ctx_t* ctx, int i, int is_error, char* msg) {
+ if (!ctx->raw_response) ctx->raw_response = _calloc(sizeof(in3_response_t), i + 1);
ctx->raw_response[i].time = now() - ctx->raw_response[i].time;
ctx->raw_response[i].state = is_error ? IN3_ERPC : IN3_OK;
if (ctx->type == CT_SIGN && !is_error) {
diff --git a/wasm/test/testEthApi.js b/wasm/test/testEthApi.js
index af69210a9..81b30a9dc 100644
--- a/wasm/test/testEthApi.js
+++ b/wasm/test/testEthApi.js
@@ -89,6 +89,28 @@ describe('EthAPI-Tests', () => {
})
+ it('plugin._handlRPC', async () => {
+ const c = createClient();
+ c.registerPlugin({
+ handleRPC(client, req) {
+ if (req.method === 'rpc_test')
+ return "test"
+ if (req.method === 'rpc_error')
+ throw new Error('RPCERROR')
+ if (req.method === 'rpc_error2')
+ return Promise.reject(new Error('RPCERROR2'))
+
+ }
+ })
+
+ assert.equal('test', await c.sendRPC('rpc_test'))
+ assert.equal(true, await c.sendRPC('test2').catch(() => true))
+ assert.equal('RPCERROR', await c.sendRPC('rpc_error').catch(x => x.message))
+ assert.equal('RPCERROR2', await c.sendRPC('rpc_error2').catch(x => x.message))
+
+ })
+
+
it('eth.sign()', async () => {
const pk = '0x889dbed9450f7a4b68e0732ccb7cd016dab158e6946d16158f2736fda1143ca6'
const msg = '0x9fa034abf05bd334e60d92da257eb3d66dd3767bba9a1d7a7575533eb0977465'