/******************************************************************************* * This file is part of the Incubed project. * Sources: https://github.com/blockchainsllc/in3 * * 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 * this file defines the incubed configuration struct and it registration. * * * */ #ifndef CLIENT_H #define CLIENT_H #ifdef __cplusplus extern "C" { #endif #include "bytes.h" #include "data.h" #include "error.h" #include "mem.h" #include "stringbuilder.h" #include #include #include #define IN3_PROTO_VER "2.1.0" /**< the protocol version used when sending requests from the this client */ #define CHAIN_ID_MAINNET 0x01 /**< chain_id for mainnet */ #define CHAIN_ID_GOERLI 0x5 /**< chain_id for goerlii */ #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. */ typedef uint32_t chain_id_t; /** the type of the chain. * * for incubed a chain can be any distributed network or database with incubed support. * Depending on this chain-type the previously registered verifier will be chosen and used. */ typedef enum { CHAIN_ETH = 0, /**< Ethereum chain */ CHAIN_SUBSTRATE = 1, /**< substrate chain */ CHAIN_IPFS = 2, /**< ipfs verification */ CHAIN_BTC = 3, /**< Bitcoin chain */ CHAIN_EOS = 4, /**< EOS chain */ CHAIN_IOTA = 5, /**< IOTA chain */ CHAIN_GENERIC = 6, /**< other chains */ } in3_chain_type_t; /** the type of proof. * * Depending on the proof-type different levels of proof will be requested from the node. */ typedef enum { PROOF_NONE = 0, /**< No Verification */ PROOF_STANDARD = 1, /**< Standard Verification of the important properties */ PROOF_FULL = 2 /**< All field will be validated including uncles */ } in3_proof_t; /** * Node capabilities * @note Always access using getters/setters in nodelist.h */ typedef uint64_t in3_node_props_t; /** * a list of flags defining the behavior of the incubed client. They should be used as bitmask for the flags-property. */ typedef enum { FLAGS_KEEP_IN3 = 0x1, /**< the in3-section with the proof will also returned */ FLAGS_AUTO_UPDATE_LIST = 0x2, /**< the nodelist will be automatically updated if the last_block is newer */ FLAGS_INCLUDE_CODE = 0x4, /**< the code is included when sending eth_call-requests */ FLAGS_BINARY = 0x8, /**< the client will use binary format */ FLAGS_HTTP = 0x10, /**< the client will try to use http instead of https */ FLAGS_STATS = 0x20, /**< nodes will keep track of the stats (default=true) */ FLAGS_NODE_LIST_NO_SIG = 0x40, /**< nodelist update request will not automatically ask for signatures and proof */ FLAGS_BOOT_WEIGHTS = 0x80, /**< if true the client will initialize the first weights from the nodelist given by the nodelist.*/ FLAGS_ALLOW_EXPERIMENTAL = 0x100 /**< if true the client will support experimental features.*/ } in3_flags_type_t; /** represents a blockhash which was previously verified */ typedef struct in3_verified_hash { uint64_t block_number; /**< the number of the block */ bytes32_t hash; /**< the blockhash */ } in3_verified_hash_t; /** * Chain definition inside incubed. * * for incubed a chain can be any distributed network or database with incubed support. */ typedef struct in3_chain { uint8_t version; /**< version of the chain */ chain_id_t chain_id; /**< chain_id, which could be a free or based on the public ethereum networkId*/ in3_chain_type_t type; /**< chain-type */ in3_verified_hash_t* verified_hashes; /**< contains the list of already verified blockhashes */ } in3_chain_t; #define PLGN_ACT_LIFECYCLE (PLGN_ACT_INIT | PLGN_ACT_TERM) #define PLGN_ACT_TRANSPORT (PLGN_ACT_TRANSPORT_SEND | PLGN_ACT_TRANSPORT_RECEIVE | PLGN_ACT_TRANSPORT_CLEAN) #define PLGN_ACT_NODELIST (PLGN_ACT_NL_PICK | PLGN_ACT_NL_PICK_FOLLOWUP | PLGN_ACT_NL_BLACKLIST | PLGN_ACT_NL_FAILABLE | PLGN_ACT_NL_OFFLINE) #define PLGN_ACT_CACHE (PLGN_ACT_CACHE_SET | PLGN_ACT_CACHE_GET | PLGN_ACT_CACHE_CLEAR) #define PLGN_ACT_CONFIG (PLGN_ACT_CONFIG_SET | PLGN_ACT_CONFIG_GET) /** plugin action list */ typedef enum { PLGN_ACT_INIT = 0x1, /**< initialize plugin - use for allocating/setting-up internal resources . Plugins will be initialized before first used. The plgn_ctx will be the first request ctx in3_req_t */ PLGN_ACT_TERM = 0x2, /**< terminate plugin - use for releasing internal resources and cleanup. ( ctx: in3_t )*/ PLGN_ACT_TRANSPORT_SEND = 0x4, /**< sends out a request - the transport plugin will receive a request_t as plgn_ctx, it may set a cptr which will be passed back when fetching more responses. */ PLGN_ACT_TRANSPORT_RECEIVE = 0x8, /**< fetch next response - the transport plugin will receive a request_t as plgn_ctx, which contains a cptr if set previously*/ PLGN_ACT_TRANSPORT_CLEAN = 0x10, /**< free-up transport resources - the transport plugin will receive a request_t as plgn_ctx if the cptr was set.*/ PLGN_ACT_SIGN_ACCOUNT = 0x20, /**< returns the accounts or addresses of the signer */ PLGN_ACT_SIGN_PUBLICKEY = 0x40, /**< returns the public key for a given address ( ctx: in3_sign_public_key_ctx_t )*/ PLGN_ACT_SIGN_PREPARE = 0x80, /**< allows a wallet to manipulate the payload before signing - the plgn_ctx will be in3_sign_ctx_t. This way a tx can be send through a multisig */ PLGN_ACT_SIGN = 0x100, /**< signs the payload - the plgn_ctx will be in3_sign_ctx_t. */ PLGN_ACT_RPC_HANDLE = 0x200, /**< a plugin may respond to a rpc-request directly (without sending it to the node). */ PLGN_ACT_RPC_VERIFY = 0x400, /**< verifies the response. the plgn_ctx will be a in3_vctx_t holding all data */ PLGN_ACT_CACHE_SET = 0x800, /**< stores data to be reused later - the plgn_ctx will be a in3_cache_ctx_t containing the data */ PLGN_ACT_CACHE_GET = 0x1000, /**< reads data to be previously stored - the plgn_ctx will be a in3_cache_ctx_t containing the key. if the data was found the data-property needs to be set. */ PLGN_ACT_CACHE_CLEAR = 0x2000, /**< clears all stored data - plgn_ctx will be NULL */ PLGN_ACT_CONFIG_SET = 0x4000, /**< gets a config-token and reads data from it */ PLGN_ACT_CONFIG_GET = 0x8000, /**< gets a string-builder and adds all config to it. */ PLGN_ACT_PAY_PREPARE = 0x10000, /**< prepares a payment */ PLGN_ACT_PAY_FOLLOWUP = 0x20000, /**< called after a request to update stats. */ PLGN_ACT_PAY_HANDLE = 0x40000, /**< handles the payment */ PLGN_ACT_PAY_SIGN_REQ = 0x80000, /**< signs a request */ PLGN_ACT_LOG_ERROR = 0x100000, /**< report an error */ PLGN_ACT_NL_PICK = 0x200000, /**< picks the data nodes, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_PICK_FOLLOWUP = 0x400000, /**< called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_BLACKLIST = 0x800000, /**< blacklist a particular node in the nodelist, plgn_ctx will be a pointer to the node's address. */ PLGN_ACT_NL_FAILABLE = 0x1000000, /**< handle fail-able request, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_OFFLINE = 0x2000000, /**< mark a particular node in the nodelist as offline, plgn_ctx will be a pointer to in3_nl_offline_ctx_t. */ PLGN_ACT_CHAIN_CHANGE = 0x4000000, /**< chain id change event, called after setting new chain id */ PLGN_ACT_GET_DATA = 0x8000000, /**< get access to plugin data as a void ptr */ PLGN_ACT_ADD_PAYLOAD = 0x10000000, /**< add plugin specific metadata to payload, plgn_ctx will be a sb_t pointer, make sure to begin with a comma */ } in3_plugin_act_t; /** * plugin interface definition */ typedef struct in3_plugin in3_plugin_t; /** * plugin action handler * * Implementations of this function must strictly follow the below pattern for return values - * * IN3_OK - successfully handled specified action * * IN3_WAITING - handling specified action, but waiting for more information * * IN3_EIGNORE - could handle specified action, but chose to ignore it so maybe another handler could handle it * * Other errors - handled but failed */ typedef in3_ret_t (*in3_plugin_act_fn)(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx); typedef uint32_t in3_plugin_supp_acts_t; struct in3_plugin { in3_plugin_supp_acts_t acts; /**< bitmask of supported actions this plugin can handle */ void* data; /**< opaque pointer to plugin data */ in3_plugin_act_fn action_fn; /**< plugin action handler */ in3_plugin_t* next; /**< pointer to next plugin in list */ }; /** Incubed Configuration. * * This struct holds the configuration and also point to internal resources such as filters or chain configs. * */ typedef struct in3_t_ { uint8_t signature_count; /**< the number of signatures used to proof the blockhash. */ uint8_t replace_latest_block; /**< if specified, the blocknumber *latest* will be replaced by blockNumber- specified value */ uint_fast16_t flags; /**< a bit mask with flags defining the behavior of the incubed client. See the FLAG...-defines*/ uint16_t finality; /**< the number of signatures in percent required for the request*/ uint_fast16_t max_attempts; /**< the max number of attempts before giving up*/ uint_fast16_t max_verified_hashes; /**< max number of verified hashes to cache (actual number may temporarily exceed this value due to pending requests) */ uint_fast16_t alloc_verified_hashes; /**< number of currently allocated verified hashes */ uint_fast16_t pending; /**< number of pending requests created with this instance */ uint32_t cache_timeout; /**< number of seconds requests can be cached. */ uint32_t timeout; /**< specifies the number of milliseconds before the request times out. increasing may be helpful if the device uses a slow connection. */ uint32_t id_count; /**< counter for use as JSON RPC id - incremented for every request */ in3_plugin_supp_acts_t plugin_acts; /**< bitmask of supported actions of all plugins registered with this client */ in3_proof_t proof; /**< the type of proof used */ in3_chain_t chain; /**< chain spec and nodeList definitions*/ in3_plugin_t* plugins; /**< list of registered plugins */ } in3_t; /** creates a new Incubed configuration for a specified chain and returns the pointer. * when creating the client only the one chain will be configured. (saves memory). * but if you pass `CHAIN_ID_MULTICHAIN` as argument all known chains will be configured allowing you to switch between chains within the same client or configuring your own chain. * * you need to free this instance with `in3_free` after use! * * Before using the client you still need to set the transport and optional the storage handlers: * * * example of initialization: * ```c * // register verifiers * in3_register_eth_full(); * * // create new client * in3_t* client = in3_for_chain(CHAIN_ID_MAINNET); * * // configure transport * client->transport = send_curl; * * // configure storage * in3_set_storage_handler(c, storage_get_item, storage_set_item, storage_clear, NULL); * * // ready to use ... * ``` * * @returns the incubed instance. */ #define in3_for_chain(chain_id) in3_for_chain_default(chain_id) in3_t* in3_for_chain_default( chain_id_t chain_id /**< the chain_id (see CHAIN_ID_... constants). */ ); /** sends a request and stores the result in the provided buffer */ NONULL in3_ret_t in3_client_rpc( in3_t* c, /**< [in] the pointer to the incubed client config. */ const char* method, /**< [in] the name of the rpc-function to call. */ const char* params, /**< [in] docs for input parameter v. */ char** result, /**< [in] pointer to string which will be set if the request was successful. This will hold the result as json-rpc-string. (make sure you free this after use!) */ char** error /**< [in] pointer to a string containing the error-message. (make sure you free it after use!) */); /** sends a request and stores the result in the provided buffer, this method will always return the first, so bulk-requests are not supported. */ NONULL in3_ret_t in3_client_rpc_raw( in3_t* c, /**< [in] the pointer to the incubed client config. */ const char* request, /**< [in] the rpc request including method and params. */ char** result, /**< [in] pointer to string which will be set if the request was successful. This will hold the result as json-rpc-string. (make sure you free this after use!) */ char** error /**< [in] pointer to a string containing the error-message. (make sure you free it after use!) */); /** executes a request and returns result as string. in case of an error, the error-property of the result will be set. * This function also supports sending bulk-requests, but you can not mix internal and external calls, since bulk means all requests will be send to picked nodes. * The resulting string must be free by the the caller of this function! */ NONULL char* in3_client_exec_req( in3_t* c, /**< [in] the pointer to the incubed client config. */ char* req /**< [in] the request as rpc. */ ); /** registers a new chain or replaces a existing (but keeps the nodelist)*/ NONULL in3_ret_t in3_client_register_chain( in3_t* client, /**< [in] the pointer to the incubed client config. */ chain_id_t chain_id, /**< [in] the chain id. */ in3_chain_type_t type, /**< [in] the verification type of the chain. */ uint8_t version /**< [in] the chain version. */ ); /** frees the references of the client */ NONULL void in3_free(in3_t* a /**< [in] the pointer to the incubed client config to free. */); /** * configures the client based on a json-config. * * For details about the structure of the config see https://in3.readthedocs.io/en/develop/api-ts.html#type-in3config * Returns NULL on success, and error string on failure (to be freed by caller) - in which case the client state is undefined */ NONULL char* in3_configure( in3_t* c, /**< the incubed client */ const char* config /**< JSON-string with the configuration to set. */ ); /** * gets the current config as json. * * For details about the structure of the config see https://in3.readthedocs.io/en/develop/api-ts.html#type-in3config */ NONULL char* in3_get_config( in3_t* c /**< the incubed client */ ); /** a register-function for a plugin. */ typedef in3_ret_t (*plgn_register)(in3_t* c); #define assert_in3(c) \ assert(c); \ assert((c)->chain.chain_id); \ assert((c)->plugins); \ assert((c)->max_attempts > 0); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); #ifdef __cplusplus } #endif #endif