/******************************************************************************* * 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 * utility functions. * */ #ifndef UTILS_H #define UTILS_H #ifdef __cplusplus extern "C" { #endif #include "bytes.h" #include #include #ifdef __ZEPHYR__ #include #define _strtoull(str, endptr, base) strtoul(str, endptr, base) #else #define _strtoull(str, endptr, base) strtoull(str, endptr, base) #endif /** simple swap macro for integral types */ #define SWAP(a, b) \ { \ void* p = a; \ a = b; \ b = p; \ } #ifndef min /** simple min macro for interagl types */ #define min(a, b) ((a) < (b) ? (a) : (b)) /** simple max macro for interagl types */ #define max(a, b) ((a) > (b) ? (a) : (b)) #endif /** * Check if n1 & n2 are at max err apart * Expects n1 & n2 to be integral types */ #define IS_APPROX(n1, n2, err) ((n1 > n2) ? ((n1 - n2) <= err) : ((n2 - n1) <= err)) #define DIFF_ATMOST(n1, n2, diff) IS_APPROX(n1, n2, diff) #define DIFF_ATLEAST(n1, n2, err) ((n1 > n2) ? ((n1 - n2) >= err) : ((n2 - n1) >= err)) /** * simple macro to stringify other macro defs * eg. usage - to concatenate a const with a string at compile time -> * #define SOME_CONST_UINT 10U * printf("Using default value of " STR(SOME_CONST_UINT)); */ #define STR_IMPL_(x) #x #define STR(x) STR_IMPL_(x) /** converts the bytes to a unsigned long (at least the last max len bytes). */ uint64_t bytes_to_long(const uint8_t* data, int len); /** converts the bytes to a unsigned int (at least the last max len bytes) */ static inline uint32_t bytes_to_int(const uint8_t* data, int len) { if (data) { switch (len) { case 0: return 0; case 1: return data[0]; case 2: return (((uint32_t) data[0]) << 8) | data[1]; case 3: return (((uint32_t) data[0]) << 16) | (((uint32_t) data[1]) << 8) | data[2]; default: return (((uint32_t) data[0]) << 24) | (((uint32_t) data[1]) << 16) | (((uint32_t) data[2]) << 8) | data[3]; } } else return 0; } /** converts a character into a uint64_t*/ uint64_t char_to_long(const char* a, int l); /** converts a hexchar to byte (4bit). In case of a nonhex char 0xff will be returned. */ uint8_t hexchar_to_int(char c); #ifdef __ZEPHYR__ // this function is only used in zephyr, because there it does not support printf("%ull",u64); /** converts a uint64_t to string (char*); buffer-size min. 21 bytes */ const char* u64_to_str(uint64_t value, char* pBuf, int szBuf); #endif /** * convert a c hex string to a byte array storing it into an existing buffer. * * @param hexdata: the hex string * @param hexlen: the len of the string to read. -1 will use strlen to determine the length. * @param out: the byte buffer * @param outlen: the length of the buffer to write into * @retval the number of bytes written */ int hex_to_bytes(const char* hexdata, int hexlen, uint8_t* out, int outlen); /** convert a c string to a byte array creating a new buffer */ bytes_t* hex_to_new_bytes(const char* buf, int len); /** convefrts a bytes into hex */ int bytes_to_hex(const uint8_t* buffer, int len, char* out); /** writes 32 bytes to the pointer. */ int keccak(bytes_t data, void* dst); /** converts a a uin64_t to 8 bytes written to dst using big endian*/ void long_to_bytes(uint64_t val, uint8_t* dst); /** converts a unsigned int to 4 bytes written to dst using big endian*/ void int_to_bytes(uint32_t val, uint8_t* dst); /** duplicate the string. A len=-1 will determine the len with strlen. */ char* _strdupn(const char* src, int len); /** calculate the min number of byte to represents the len */ int min_bytes_len(uint64_t val); /** * sets a variable value to 32byte word. * @param src The src data * @param src_len the number of bytes * @param dst target pointer */ void uint256_set(const uint8_t* src, wlen_t src_len, bytes32_t dst); /** * replaces a string and returns a copy. * @retval */ char* str_replace(char* orig, const char* rep, const char* with); /** * replaces a string at the given position. */ char* str_replace_pos(char* orig, size_t pos, size_t len, const char* rep); /** * lightweight strstr() replacements */ char* str_find(char* haystack, const char* needle); /** * remove all html-tags in the text. This function will modify the orifinal data and return the same pointer as the input. */ char* str_remove_html(char* data); /** * current timestamp in ms. */ uint64_t current_ms(); /** changes to pointer (a) and it length (l) to remove leading 0 bytes. it will reduce it to max len=1*/ #define optimize_len(a, l) \ while (l > 1 && *a == 0) { \ l--; \ a++; \ } /** * executes the expression and expects the return value to be a int indicating the error. * if the return value is negative it will stop and return this value otherwise continue. */ #define TRY(exp) \ { \ int _r = (exp); \ if (_r < 0) return _r; \ } /** * executes the expression and expects the return value to be a int indicating the error. * if the return value is negative it will stop and return this value otherwise continue. */ #define TRY_FINAL(exp, final) \ { \ int _r = (exp); \ final; \ if (_r < 0) return _r; \ } /** * executes the expression and expects the return value to be a int indicating the error. * if the return value is negative it will stop and return this value otherwise continue. */ #define TRY_CATCH(exp, catch) \ { \ int _r = (exp); \ if (_r < 0) { \ catch; \ return _r; \ } \ } #define TRY_RPC(name, fn) \ if (strcmp(ctx->method, name) == 0) return fn; /** used in if-conditions and returns true if the vc->method mathes the name. It is also used as marker.*/ #define VERIFY_RPC(name) (strcmp(vc->method, name) == 0) #define CONFIG_KEY(name) key(name) /** * executes the expression and expects value to equal val. * if not it will return IN3_EINVAL */ #define EXPECT_EQ(exp, val) \ if ((exp) != val) return IN3_EINVAL; /** * executes the expression and expects the return value to be a int indicating the error. * the return value will be set to a existing variable (var). * if the return value is negative it will stop and return this value otherwise continue. */ #define TRY_SET(var, exp) \ { \ var = (exp); \ if (var < 0) return var; \ } /** * executes the expression and expects the return value to be a int indicating the error. * if the return value is negative it will stop and jump (goto) to a marked position "clean". * it also expects a previously declared variable "in3_ret_t res". */ #define TRY_GOTO(exp) \ { \ res = (exp); \ if (res < 0) goto clean; \ } /** * returns true if all pytes (specified by l) of pts have a value of zero. */ static inline bool memiszero(uint8_t* ptr, size_t l) { assert(l > 0); while (l) { if (*ptr) return false; l--; ptr++; } return true; } /** calculates the address of a word in a abi-encoded data (assuming data = bytes_t res exists) */ #define WORD_ADR(index, right) (res.data + 4 + (index) *32 + 32 - (right)) /** sets an address at the word index in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_ADDRESS(index, adr) memcpy(WORD_ADR(index, 20), adr, 20) /** sets an int at the word index in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_UINT32(index, val) int_to_bytes(val, WORD_ADR(index, 4)) /** sets an uint256 as bytes at the word index in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_UINT256(index, data, len) memcpy(WORD_ADR(index, len), data, len) /** writes the bytes at the word index in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_BYTES(index, bytes) \ { \ if (bytes.data) memcpy(WORD_ADR(index, 32), bytes.data, bytes.len); \ } /** writes the functionhash in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_FNC(hash) memcpy(res.data, (void*) hash, 4) /**allocates memory filled with zeros with the size words*32 +4 for e3ncoding abi-data */ #define ABI_BYTES_CALLOC(words) bytes(_calloc(4 + (words) *32, 1), 4 + (words) *32) /** calculates the number of words (32 bytes) needed to hold the specified bytes */ #define ABI_WORDS(byte_len) ((byte_len + 31) / 32) /** writes the offset (as word) at the word index in a abi-encoded data (assuming data = bytes_t res exists) */ #define ABI_OFFSET(index, word) ABI_UINT32(index, (word * 32)) /** * Pluggable functions: * Mechanism to replace library functions with custom alternatives. This is particularly useful for * embedded systems which have their own time or rand functions. * * eg. * // define function with specified signature * uint64_t my_time(void* t) { * // ... * } * * // then call in3_set_func_*() * int main() { * in3_set_func_time(my_time); * // Henceforth, all library calls will use my_time() instead of the platform default time function * } */ /** * time function * defaults to k_uptime_get() for zeohyr and time(NULL) for other platforms * expected to return a u64 value representative of time (from epoch/start) */ typedef uint64_t (*time_func)(void* t); void in3_set_func_time(time_func fn); uint64_t in3_time(void* t); /** * rand function * defaults to k_uptime_get() for zeohyr and rand() for other platforms * expected to return a random number */ typedef int (*rand_func)(void* s); void in3_set_func_rand(rand_func fn); int in3_rand(void* s); /** * srand function * defaults to NOOP for zephyr and srand() for other platforms * expected to set the seed for a new sequence of random numbers to be returned by in3_rand() */ typedef void (*srand_func)(unsigned int s); void in3_set_func_srand(srand_func fn); void in3_srand(unsigned int s); void in3_sleep(uint32_t ms); /** * parses a float-string and returns the value as int */ int64_t parse_float_val(const char* data, /**< the data string*/ int32_t expo /**< the exponent */ ); /** * simple add function, which adds the bytes (b) to a */ void b256_add(bytes32_t a, uint8_t* b, wlen_t len_b); /** * prints a bytes into a string */ char* bytes_to_hex_string(char* out, const char* prefix, const bytes_t b, const char* postfix); #ifdef THREADSAFE #define _NAME(x, y) x##y #if defined(_MSC_VER) || defined(__MINGW32__) #include #define INIT_LOCK(NAME) \ static HANDLE _NAME(_lock_handle_, NAME) = NULL; \ static void _NAME(_lock, NAME)() { \ if (!_NAME(_lock_handle_, NAME)) { \ HANDLE p = CreateMutex(NULL, FALSE, NULL); \ if (InterlockedCompareExchangePointer((PVOID*) &_NAME(_lock_handle_, NAME), (PVOID) p, NULL)) CloseHandle(p); \ } \ WaitForSingleObject(_NAME(_lock_handle_, NAME), INFINITE); \ } #define LOCK(NAME, code) \ { \ _NAME(_lock, NAME) \ (); \ code \ ReleaseMutex(_NAME(_lock_handle_, NAME)); \ } #else #include #define INIT_LOCK(NAME) static pthread_mutex_t _NAME(_lock_handle_, NAME) = PTHREAD_MUTEX_INITIALIZER; #define LOCK(NAME, code) \ { \ pthread_mutex_lock(&(_NAME(_lock_handle_, NAME))); \ code \ pthread_mutex_unlock(&(_NAME(_lock_handle_, NAME))); \ } #endif #else #define INIT_LOCK(NAME) \ {} #define LOCK(NAME, code) \ { code } #endif #ifdef __cplusplus } #endif #endif